1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2018, Joyent, Inc.
28 */
29
30 /*
31 * PICL plug-in that creates device tree nodes for all platforms
32 */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <assert.h>
40 #include <alloca.h>
41 #include <unistd.h>
42 #include <stropts.h>
43 #include <syslog.h>
44 #include <libdevinfo.h>
45 #include <sys/dkio.h>
46 #include <sys/vtoc.h>
47 #include <sys/time.h>
48 #include <fcntl.h>
49 #include <picl.h>
50 #include <picltree.h>
51 #include <sys/types.h>
52 #include <sys/processor.h>
53 #include <kstat.h>
54 #include <sys/sysinfo.h>
55 #include <dirent.h>
56 #include <libintl.h>
57 #include <pthread.h>
58 #include <libnvpair.h>
59 #include <sys/utsname.h>
60 #include <sys/systeminfo.h>
61 #include <sys/obpdefs.h>
62 #include <sys/openpromio.h>
63 #include "picldevtree.h"
64
65 /*
66 * Plugin registration entry points
67 */
68 static void picldevtree_register(void);
69 static void picldevtree_init(void);
70 static void picldevtree_fini(void);
71
72 static void picldevtree_evhandler(const char *ename, const void *earg,
73 size_t size, void *cookie);
74
75 #pragma init(picldevtree_register)
76
77 /*
78 * Log message texts
79 */
80 #define DEVINFO_PLUGIN_INIT_FAILED gettext("SUNW_picldevtree failed!\n")
81 #define PICL_EVENT_DROPPED \
82 gettext("SUNW_picldevtree '%s' event dropped.\n")
83
84 /*
85 * Macro to get PCI device id (from IEEE 1275 spec)
86 */
87 #define PCI_DEVICE_ID(x) (((x) >> 11) & 0x1f)
88 /*
89 * Local variables
90 */
91 static picld_plugin_reg_t my_reg_info = {
92 PICLD_PLUGIN_VERSION_1,
93 PICLD_PLUGIN_CRITICAL,
94 "SUNW_picldevtree",
95 picldevtree_init,
96 picldevtree_fini
97 };
98
99 /*
100 * Debug enabling environment variable
101 */
102 #define SUNW_PICLDEVTREE_PLUGIN_DEBUG "SUNW_PICLDEVTREE_PLUGIN_DEBUG"
103 static int picldevtree_debug = 0;
104
105 static conf_entries_t *conf_name_class_map = NULL;
106 static builtin_map_t sun4u_map[] = {
107 /* MAX_NAMEVAL_SIZE */
108 { "SUNW,bpp", PICL_CLASS_PARALLEL},
109 { "parallel", PICL_CLASS_PARALLEL},
110 { "floppy", PICL_CLASS_FLOPPY},
111 { "memory", PICL_CLASS_MEMORY},
112 { "ebus", PICL_CLASS_EBUS},
113 { "i2c", PICL_CLASS_I2C},
114 { "usb", PICL_CLASS_USB},
115 { "isa", PICL_CLASS_ISA},
116 { "dma", PICL_CLASS_DMA},
117 { "keyboard", PICL_CLASS_KEYBOARD},
118 { "mouse", PICL_CLASS_MOUSE},
119 { "fan-control", PICL_CLASS_FAN_CONTROL},
120 { "sc", PICL_CLASS_SYSTEM_CONTROLLER},
121 { "dimm", PICL_CLASS_SEEPROM},
122 { "dimm-fru", PICL_CLASS_SEEPROM},
123 { "cpu", PICL_CLASS_SEEPROM},
124 { "cpu-fru", PICL_CLASS_SEEPROM},
125 { "flashprom", PICL_CLASS_FLASHPROM},
126 { "temperature", PICL_CLASS_TEMPERATURE_DEVICE},
127 { "motherboard", PICL_CLASS_SEEPROM},
128 { "motherboard-fru", PICL_CLASS_SEEPROM},
129 { "motherboard-fru-prom", PICL_CLASS_SEEPROM},
130 { "pmu", PICL_CLASS_PMU},
131 { "sound", PICL_CLASS_SOUND},
132 { "firewire", PICL_CLASS_FIREWIRE},
133 { "i2c-at34c02", PICL_CLASS_SEEPROM},
134 { "hardware-monitor", PICL_CLASS_HARDWARE_MONITOR},
135 { "", ""}
136 };
137 static builtin_map_t i86pc_map[] = {
138 /* MAX_NAMEVAL_SIZE */
139 { "cpus", PICL_CLASS_I86CPUS},
140 { "cpu", PICL_CLASS_CPU},
141 { "memory", PICL_CLASS_MEMORY},
142 { "asy", PICL_CLASS_SERIAL},
143 { "", ""}
144 };
145 static pname_type_map_t pname_type_map[] = {
146 { "reg", PICL_PTYPE_BYTEARRAY},
147 { "device_type", PICL_PTYPE_CHARSTRING},
148 { "ranges", PICL_PTYPE_BYTEARRAY},
149 { "status", PICL_PTYPE_CHARSTRING},
150 { "compatible", PICL_PTYPE_CHARSTRING},
151 { "interrupts", PICL_PTYPE_BYTEARRAY},
152 { "model", PICL_PTYPE_CHARSTRING},
153 { "address", PICL_PTYPE_BYTEARRAY},
154 { "vendor-id", PICL_PTYPE_UNSIGNED_INT},
155 { "device-id", PICL_PTYPE_UNSIGNED_INT},
156 { "revision-id", PICL_PTYPE_UNSIGNED_INT},
157 { "class-code", PICL_PTYPE_UNSIGNED_INT},
158 { "min-grant", PICL_PTYPE_UNSIGNED_INT},
159 { "max-latency", PICL_PTYPE_UNSIGNED_INT},
160 { "devsel-speed", PICL_PTYPE_UNSIGNED_INT},
161 { "subsystem-id", PICL_PTYPE_UNSIGNED_INT},
162 { "subsystem-vendor-id", PICL_PTYPE_UNSIGNED_INT},
163 { "assigned-addresses", PICL_PTYPE_BYTEARRAY},
164 { "configuration#", PICL_PTYPE_UNSIGNED_INT},
165 { "assigned-address", PICL_PTYPE_UNSIGNED_INT},
166 { "#address-cells", PICL_PTYPE_UNSIGNED_INT},
167 { "#size-cells", PICL_PTYPE_UNSIGNED_INT},
168 { "clock-frequency", PICL_PTYPE_UNSIGNED_INT},
169 { "scsi-initiator-id", PICL_PTYPE_UNSIGNED_INT},
170 { "differential", PICL_PTYPE_UNSIGNED_INT},
171 { "idprom", PICL_PTYPE_BYTEARRAY},
172 { "bus-range", PICL_PTYPE_BYTEARRAY},
173 { "alternate-reg", PICL_PTYPE_BYTEARRAY},
174 { "power-consumption", PICL_PTYPE_BYTEARRAY},
175 { "slot-names", PICL_PTYPE_BYTEARRAY},
176 { "burst-sizes", PICL_PTYPE_UNSIGNED_INT},
177 { "up-burst-sizes", PICL_PTYPE_UNSIGNED_INT},
178 { "slot-address-bits", PICL_PTYPE_UNSIGNED_INT},
179 { "eisa-slots", PICL_PTYPE_BYTEARRAY},
180 { "dma", PICL_PTYPE_BYTEARRAY},
181 { "slot-names-index", PICL_PTYPE_UNSIGNED_INT},
182 { "pnp-csn", PICL_PTYPE_UNSIGNED_INT},
183 { "pnp-data", PICL_PTYPE_BYTEARRAY},
184 { "description", PICL_PTYPE_CHARSTRING},
185 { "pnp-id", PICL_PTYPE_CHARSTRING},
186 { "max-frame-size", PICL_PTYPE_UNSIGNED_INT},
187 { "address-bits", PICL_PTYPE_UNSIGNED_INT},
188 { "local-mac-address", PICL_PTYPE_BYTEARRAY},
189 { "mac-address", PICL_PTYPE_BYTEARRAY},
190 { "character-set", PICL_PTYPE_CHARSTRING},
191 { "available", PICL_PTYPE_BYTEARRAY},
192 { "port-wwn", PICL_PTYPE_BYTEARRAY},
193 { "node-wwn", PICL_PTYPE_BYTEARRAY},
194 { "width", PICL_PTYPE_UNSIGNED_INT},
195 { "linebytes", PICL_PTYPE_UNSIGNED_INT},
196 { "height", PICL_PTYPE_UNSIGNED_INT},
197 { "banner-name", PICL_PTYPE_CHARSTRING},
198 { "reset-reason", PICL_PTYPE_CHARSTRING},
199 { "implementation#", PICL_PTYPE_UNSIGNED_INT},
200 { "version#", PICL_PTYPE_UNSIGNED_INT},
201 { "icache-size", PICL_PTYPE_UNSIGNED_INT},
202 { "icache-line-size", PICL_PTYPE_UNSIGNED_INT},
203 { "icache-associativity", PICL_PTYPE_UNSIGNED_INT},
204 { "l1-icache-size", PICL_PTYPE_UNSIGNED_INT},
205 { "l1-icache-line-size", PICL_PTYPE_UNSIGNED_INT},
206 { "l1-icache-associativity", PICL_PTYPE_UNSIGNED_INT},
207 { "#itlb-entries", PICL_PTYPE_UNSIGNED_INT},
208 { "dcache-size", PICL_PTYPE_UNSIGNED_INT},
209 { "dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
210 { "dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
211 { "l1-dcache-size", PICL_PTYPE_UNSIGNED_INT},
212 { "l1-dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
213 { "l1-dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
214 { "#dtlb-entries", PICL_PTYPE_UNSIGNED_INT},
215 { "ecache-size", PICL_PTYPE_UNSIGNED_INT},
216 { "ecache-line-size", PICL_PTYPE_UNSIGNED_INT},
217 { "ecache-associativity", PICL_PTYPE_UNSIGNED_INT},
218 { "l2-cache-size", PICL_PTYPE_UNSIGNED_INT},
219 { "l2-cache-line-size", PICL_PTYPE_UNSIGNED_INT},
220 { "l2-cache-associativity", PICL_PTYPE_UNSIGNED_INT},
221 { "l2-cache-sharing", PICL_PTYPE_BYTEARRAY},
222 { "mask#", PICL_PTYPE_UNSIGNED_INT},
223 { "manufacturer#", PICL_PTYPE_UNSIGNED_INT},
224 { "sparc-version", PICL_PTYPE_UNSIGNED_INT},
225 { "version", PICL_PTYPE_CHARSTRING},
226 { "cpu-model", PICL_PTYPE_UNSIGNED_INT},
227 { "memory-layout", PICL_PTYPE_BYTEARRAY},
228 { "#interrupt-cells", PICL_PTYPE_UNSIGNED_INT},
229 { "interrupt-map", PICL_PTYPE_BYTEARRAY},
230 { "interrupt-map-mask", PICL_PTYPE_BYTEARRAY}
231 };
232
233 #define PNAME_MAP_SIZE sizeof (pname_type_map) / sizeof (pname_type_map_t)
234
235 static builtin_map_t *builtin_map_ptr = NULL;
236 static int builtin_map_size = 0;
237 static char mach_name[SYS_NMLN];
238 static di_prom_handle_t ph = DI_PROM_HANDLE_NIL;
239 static int snapshot_stale;
240
241 /*
242 * UnitAddress mapping table
243 */
244 static unitaddr_func_t encode_default_unitaddr;
245 static unitaddr_func_t encode_optional_unitaddr;
246 static unitaddr_func_t encode_scsi_unitaddr;
247 static unitaddr_func_t encode_upa_unitaddr;
248 static unitaddr_func_t encode_gptwo_jbus_unitaddr;
249 static unitaddr_func_t encode_pci_unitaddr;
250
251 static unitaddr_map_t unitaddr_map_table[] = {
252 {PICL_CLASS_JBUS, encode_gptwo_jbus_unitaddr, 0},
253 {PICL_CLASS_GPTWO, encode_gptwo_jbus_unitaddr, 0},
254 {PICL_CLASS_PCI, encode_pci_unitaddr, 0},
255 {PICL_CLASS_PCIEX, encode_pci_unitaddr, 0},
256 {PICL_CLASS_UPA, encode_upa_unitaddr, 0},
257 {PICL_CLASS_SCSI, encode_scsi_unitaddr, 0},
258 {PICL_CLASS_SCSI2, encode_scsi_unitaddr, 0},
259 {PICL_CLASS_EBUS, encode_default_unitaddr, 2},
260 {PICL_CLASS_SBUS, encode_default_unitaddr, 2},
261 {PICL_CLASS_I2C, encode_default_unitaddr, 2},
262 {PICL_CLASS_USB, encode_default_unitaddr, 1},
263 {PICL_CLASS_PMU, encode_optional_unitaddr, 2},
264 {NULL, encode_default_unitaddr, 0}
265 };
266
267 static int add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh);
268 static int get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh,
269 char *unitaddr, size_t ualen);
270 static void set_pci_pciex_deviceid(picl_nodehdl_t plafh);
271
272 /*
273 * The mc event completion handler.
274 * The arguments are event name buffer and a packed nvlist buffer
275 * with the size specifying the size of unpacked nvlist. These
276 * buffers are deallcoated here.
277 *
278 * Also, if a memory controller node is being removed then destroy the
279 * PICL subtree associated with that memory controller.
280 */
281 static void
282 mc_completion_handler(char *ename, void *earg, size_t size)
283 {
284 picl_nodehdl_t mch;
285 nvlist_t *unpack_nvl;
286
287 if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0 &&
288 nvlist_unpack(earg, size, &unpack_nvl, NULL) == 0) {
289 mch = NULL;
290 (void) nvlist_lookup_uint64(unpack_nvl,
291 PICLEVENTARG_NODEHANDLE, &mch);
292 if (mch != NULL) {
293 if (picldevtree_debug)
294 syslog(LOG_INFO,
295 "picldevtree: destroying_node:%llx\n",
296 mch);
297 (void) ptree_destroy_node(mch);
298 }
299 nvlist_free(unpack_nvl);
300 }
301
302 free(ename);
303 free(earg);
304 }
305
306 /*
307 * Functions to post memory controller change event
308 */
309 static int
310 post_mc_event(char *ename, picl_nodehdl_t mch)
311 {
312 nvlist_t *nvl;
313 size_t nvl_size;
314 char *pack_buf;
315 char *ev_name;
316
317 ev_name = strdup(ename);
318 if (ev_name == NULL)
319 return (-1);
320
321 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) {
322 free(ev_name);
323 return (-1);
324 }
325
326 pack_buf = NULL;
327 if (nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE, mch) ||
328 nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, NULL)) {
329 free(ev_name);
330 nvlist_free(nvl);
331 return (-1);
332 }
333
334 if (picldevtree_debug)
335 syslog(LOG_INFO,
336 "picldevtree: posting MC event ename:%s nodeh:%llx\n",
337 ev_name, mch);
338 if (ptree_post_event(ev_name, pack_buf, nvl_size,
339 mc_completion_handler) != PICL_SUCCESS) {
340 free(ev_name);
341 nvlist_free(nvl);
342 return (-1);
343 }
344 nvlist_free(nvl);
345 return (0);
346 }
347
348 /*
349 * Lookup a name in the name to class map tables
350 */
351 static int
352 lookup_name_class_map(char *classbuf, const char *nm)
353 {
354 conf_entries_t *ptr;
355 int i;
356
357 /*
358 * check name to class mapping in conf file
359 */
360 ptr = conf_name_class_map;
361
362 while (ptr != NULL) {
363 if (strcmp(ptr->name, nm) == 0) {
364 (void) strlcpy(classbuf, ptr->piclclass,
365 PICL_CLASSNAMELEN_MAX);
366 return (0);
367 }
368 ptr = ptr->next;
369 }
370
371 /*
372 * check name to class mapping in builtin table
373 */
374 if (builtin_map_ptr == NULL)
375 return (-1);
376
377 for (i = 0; i < builtin_map_size; ++i)
378 if (strcmp(builtin_map_ptr[i].name, nm) == 0) {
379 (void) strlcpy(classbuf, builtin_map_ptr[i].piclclass,
380 PICL_CLASSNAMELEN_MAX);
381 return (0);
382 }
383 return (-1);
384 }
385
386 /*
387 * Lookup a prop name in the pname to class map table
388 */
389 static int
390 lookup_pname_type_map(const char *pname, picl_prop_type_t *type)
391 {
392 int i;
393
394 for (i = 0; i < PNAME_MAP_SIZE; ++i)
395 if (strcmp(pname_type_map[i].pname, pname) == 0) {
396 *type = pname_type_map[i].type;
397 return (0);
398 }
399
400 return (-1);
401 }
402
403 /*
404 * Return the number of strings in the buffer
405 */
406 static int
407 get_string_count(char *strdat, int length)
408 {
409 int count;
410 char *lastnull;
411 char *nullptr;
412
413 count = 1;
414 for (lastnull = &strdat[length - 1], nullptr = strchr(strdat, '\0');
415 nullptr != lastnull; nullptr = strchr(nullptr+1, '\0'))
416 count++;
417
418 return (count);
419 }
420
421 /*
422 * Return 1 if the node has a "reg" property
423 */
424 static int
425 has_reg_prop(di_node_t dn)
426 {
427 int *pdata;
428 int dret;
429
430 dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, &pdata);
431 if (dret > 0)
432 return (1);
433
434 if (!ph)
435 return (0);
436 dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata);
437 return (dret < 0 ? 0 : 1);
438 }
439
440 /*
441 * This function copies a PROM node's device_type property value into the
442 * buffer given by outbuf. The buffer size is PICL_CLASSNAMELEN_MAX.
443 *
444 * We reclassify device_type 'fru-prom' to PICL class 'seeprom'
445 * for FRUID support.
446 */
447 static int
448 get_device_type(char *outbuf, di_node_t dn)
449 {
450 char *pdata;
451 char *pdatap;
452 int dret;
453 int i;
454
455 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_DEVICETYPE,
456 &pdata);
457 if (dret <= 0) {
458 if (!ph)
459 return (-1);
460
461 dret = di_prom_prop_lookup_strings(ph, dn, OBP_DEVICETYPE,
462 &pdata);
463 if (dret <= 0) {
464 return (-1);
465 }
466 }
467
468 if (dret != 1) {
469 /*
470 * multiple strings
471 */
472 pdatap = pdata;
473 for (i = 0; i < (dret - 1); ++i) {
474 pdatap += strlen(pdatap);
475 *pdatap = '-'; /* replace '\0' with '-' */
476 pdatap++;
477 }
478 }
479 if (strcasecmp(pdata, "fru-prom") == 0) {
480 /*
481 * Use PICL 'seeprom' class for fru-prom device types
482 */
483 (void) strlcpy(outbuf, PICL_CLASS_SEEPROM,
484 PICL_CLASSNAMELEN_MAX);
485 } else {
486 (void) strlcpy(outbuf, pdata, PICL_CLASSNAMELEN_MAX);
487 }
488 return (0);
489 }
490
491 /*
492 * Get the minor node name in the class buffer passed
493 */
494 static int
495 get_minor_class(char *classbuf, di_node_t dn)
496 {
497 di_minor_t mi_node;
498 char *mi_nodetype;
499 char *mi_name;
500
501 /* get minor node type */
502 mi_node = di_minor_next(dn, DI_MINOR_NIL);
503 if (mi_node == DI_MINOR_NIL)
504 return (-1);
505
506 mi_nodetype = di_minor_nodetype(mi_node);
507 if (mi_nodetype == NULL) { /* no type info, return name */
508 mi_name = di_minor_name(mi_node);
509 if (mi_name == NULL)
510 return (-1);
511 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX);
512 return (0);
513 }
514
515 #define DDI_NODETYPE(x, y) (strncmp(x, y, (sizeof (y) - 1)) == 0)
516
517 /*
518 * convert the string to the picl class for non-peudo nodes
519 */
520 if (DDI_NODETYPE(mi_nodetype, DDI_PSEUDO))
521 return (-1);
522 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_WWN))
523 (void) strcpy(classbuf, PICL_CLASS_BLOCK);
524 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_CHAN))
525 (void) strcpy(classbuf, PICL_CLASS_BLOCK);
526 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD))
527 (void) strcpy(classbuf, PICL_CLASS_CDROM);
528 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD_CHAN))
529 (void) strcpy(classbuf, PICL_CLASS_CDROM);
530 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_FD))
531 (void) strcpy(classbuf, PICL_CLASS_FLOPPY);
532 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_FABRIC))
533 (void) strcpy(classbuf, PICL_CLASS_FABRIC);
534 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_SAS))
535 (void) strcpy(classbuf, PICL_CLASS_SAS);
536 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK))
537 (void) strcpy(classbuf, PICL_CLASS_BLOCK);
538 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_MOUSE))
539 (void) strcpy(classbuf, PICL_CLASS_MOUSE);
540 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_KEYBOARD))
541 (void) strcpy(classbuf, PICL_CLASS_KEYBOARD);
542 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ATTACHMENT_POINT))
543 (void) strcpy(classbuf, PICL_CLASS_ATTACHMENT_POINT);
544 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_TAPE))
545 (void) strcpy(classbuf, PICL_CLASS_TAPE);
546 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_SCSI_ENCLOSURE))
547 (void) strcpy(classbuf, PICL_CLASS_SCSI);
548 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ENCLOSURE)) {
549 char *colon;
550
551 if ((colon = strchr(mi_nodetype, ':')) == NULL)
552 return (-1);
553 ++colon;
554 (void) strcpy(classbuf, colon);
555 } else { /* unrecognized type, return name */
556 mi_name = di_minor_name(mi_node);
557 if (mi_name == NULL)
558 return (-1);
559 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX);
560 }
561 return (0);
562 }
563
564 /*
565 * Derive PICL class using the compatible property of the node
566 * We use the map table to map compatible property value to
567 * class.
568 */
569 static int
570 get_compatible_class(char *outbuf, di_node_t dn)
571 {
572 char *pdata;
573 char *pdatap;
574 int dret;
575 int i;
576
577 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_COMPATIBLE,
578 &pdata);
579 if (dret <= 0) {
580 if (!ph)
581 return (-1);
582
583 dret = di_prom_prop_lookup_strings(ph, dn, OBP_COMPATIBLE,
584 &pdata);
585 if (dret <= 0) {
586 return (-1);
587 }
588 }
589
590 pdatap = pdata;
591 for (i = 0; i < dret; ++i) {
592 if (lookup_name_class_map(outbuf, pdatap) == 0)
593 return (0);
594 pdatap += strlen(pdatap);
595 pdatap++;
596 }
597 return (-1);
598 }
599
600 /*
601 * For a given device node find the PICL class to use. Returns NULL
602 * for non device node
603 */
604 static int
605 get_node_class(char *classbuf, di_node_t dn, const char *nodename)
606 {
607 if (get_device_type(classbuf, dn) == 0) {
608 if (di_nodeid(dn) == DI_PROM_NODEID) {
609 /*
610 * discard place holder nodes
611 */
612 if ((strcmp(classbuf, DEVICE_TYPE_BLOCK) == 0) ||
613 (strcmp(classbuf, DEVICE_TYPE_BYTE) == 0) ||
614 (strcmp(classbuf, DEVICE_TYPE_SES) == 0) ||
615 (strcmp(classbuf, DEVICE_TYPE_FP) == 0) ||
616 (strcmp(classbuf, DEVICE_TYPE_DISK) == 0))
617 return (-1);
618
619 return (0);
620 }
621 return (0); /* return device_type value */
622 }
623
624 if (get_compatible_class(classbuf, dn) == 0) {
625 return (0); /* derive class using compatible prop */
626 }
627
628 if (lookup_name_class_map(classbuf, nodename) == 0)
629 return (0); /* derive class using name prop */
630
631 if (has_reg_prop(dn)) { /* use default obp-device */
632 (void) strcpy(classbuf, PICL_CLASS_OBP_DEVICE);
633 return (0);
634 }
635
636 return (get_minor_class(classbuf, dn));
637 }
638
639 /*
640 * Add a table property containing nrows with one column
641 */
642 static int
643 add_string_list_prop(picl_nodehdl_t nodeh, char *name, char *strlist,
644 unsigned int nrows)
645 {
646 ptree_propinfo_t propinfo;
647 picl_prophdl_t proph;
648 picl_prophdl_t tblh;
649 int err;
650 unsigned int i;
651 unsigned int j;
652 picl_prophdl_t *proprow;
653 int len;
654
655 #define NCOLS_IN_STRING_TABLE 1
656
657 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
658 PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t), name,
659 NULL, NULL);
660 if (err != PICL_SUCCESS)
661 return (err);
662
663 err = ptree_create_table(&tblh);
664 if (err != PICL_SUCCESS)
665 return (err);
666
667 err = ptree_create_and_add_prop(nodeh, &propinfo, &tblh, &proph);
668 if (err != PICL_SUCCESS)
669 return (err);
670
671 proprow = alloca(sizeof (picl_prophdl_t) * nrows);
672 if (proprow == NULL) {
673 (void) ptree_destroy_prop(proph);
674 return (PICL_FAILURE);
675 }
676
677 for (j = 0; j < nrows; ++j) {
678 len = strlen(strlist) + 1;
679 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
680 PICL_PTYPE_CHARSTRING, PICL_READ, len, name,
681 NULL, NULL);
682 if (err != PICL_SUCCESS)
683 break;
684 err = ptree_create_prop(&propinfo, strlist, &proprow[j]);
685 if (err != PICL_SUCCESS)
686 break;
687 strlist += len;
688 err = ptree_add_row_to_table(tblh, NCOLS_IN_STRING_TABLE,
689 &proprow[j]);
690 if (err != PICL_SUCCESS)
691 break;
692 }
693
694 if (err != PICL_SUCCESS) {
695 for (i = 0; i < j; ++i)
696 (void) ptree_destroy_prop(proprow[i]);
697 (void) ptree_delete_prop(proph);
698 (void) ptree_destroy_prop(proph);
699 return (err);
700 }
701
702 return (PICL_SUCCESS);
703 }
704
705 /*
706 * return 1 if this node has this property with the given value
707 */
708 static int
709 compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
710 const char *pval)
711 {
712 char *pvalbuf;
713 int err;
714 int len;
715 ptree_propinfo_t pinfo;
716 picl_prophdl_t proph;
717
718 err = ptree_get_prop_by_name(nodeh, pname, &proph);
719 if (err != PICL_SUCCESS) /* prop doesn't exist */
720 return (0);
721
722 err = ptree_get_propinfo(proph, &pinfo);
723 if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
724 return (0); /* not string prop */
725
726 len = strlen(pval) + 1;
727
728 pvalbuf = alloca(len);
729 if (pvalbuf == NULL)
730 return (0);
731
732 err = ptree_get_propval(proph, pvalbuf, len);
733 if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
734 return (1); /* prop match */
735
736 return (0);
737 }
738
739 /*
740 * This function recursively searches the tree for a node that has
741 * the specified string property name and value
742 */
743 static int
744 find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
745 const char *pval, picl_nodehdl_t *nodeh)
746 {
747 picl_nodehdl_t childh;
748 int err;
749
750 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
751 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
752 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, &childh,
753 sizeof (picl_nodehdl_t))) {
754 if (err != PICL_SUCCESS)
755 return (err);
756
757 if (compare_string_propval(childh, pname, pval)) {
758 *nodeh = childh;
759 return (PICL_SUCCESS);
760 }
761
762 if (find_node_by_string_prop(childh, pname, pval, nodeh) ==
763 PICL_SUCCESS)
764 return (PICL_SUCCESS);
765 }
766
767 return (PICL_FAILURE);
768 }
769
770 /*
771 * check if this is a string prop
772 * If the length is less than or equal to 4, assume it's not a string list.
773 * If there is any non-ascii or non-print char, it's not a string prop
774 * If \0 is in the first char or any two consecutive \0's exist,
775 * it's a bytearray prop.
776 * Return value: 0 means it's not a string prop, 1 means it's a string prop
777 */
778 static int
779 is_string_propval(unsigned char *pdata, int len)
780 {
781 int i;
782 int lastindex;
783 int prevnull = -1;
784
785 switch (len) {
786 case 1:
787 if (!isascii(pdata[0]) || !isprint(pdata[0]))
788 return (0);
789 return (1);
790 case 2:
791 case 3:
792 case 4:
793 lastindex = len;
794 if (pdata[len-1] == '\0')
795 lastindex = len - 1;
796
797 for (i = 0; i < lastindex; i++)
798 if (!isascii(pdata[i]) || !isprint(pdata[i]))
799 return (0);
800
801 return (1);
802
803 default:
804 if (len <= 0)
805 return (0);
806 for (i = 0; i < len; i++) {
807 if (!isascii(pdata[i]) || !isprint(pdata[i])) {
808 if (pdata[i] != '\0')
809 return (0);
810 /*
811 * if the null char is in the first char
812 * or two consecutive nulls' exist,
813 * it's a bytearray prop
814 */
815 if ((i == 0) || ((i - prevnull) == 1))
816 return (0);
817
818 prevnull = i;
819 }
820 }
821 break;
822 }
823
824 return (1);
825 }
826
827 /*
828 * This function counts the number of strings in the value buffer pdata
829 * and creates a property.
830 * If there is only one string in the buffer, pdata, a charstring property
831 * type is created and added.
832 * If there are more than one string in the buffer, pdata, then a table
833 * of charstrings is added.
834 */
835 static int
836 process_charstring_data(picl_nodehdl_t nodeh, char *pname, unsigned char *pdata,
837 int retval)
838 {
839 int err;
840 int strcount;
841 char *strdat;
842 ptree_propinfo_t propinfo;
843
844 /*
845 * append the null char at the end of string when there is
846 * no null terminator
847 */
848 if (pdata[retval - 1] != '\0') {
849 strdat = alloca(retval + 1);
850 (void) memcpy(strdat, pdata, retval);
851 strdat[retval] = '\0';
852 retval++;
853 } else {
854 strdat = alloca(retval);
855 (void) memcpy(strdat, pdata, retval);
856 }
857
858 /*
859 * If it's a string list, create a table prop
860 */
861 strcount = get_string_count(strdat, retval);
862 if (strcount > 1) {
863 err = add_string_list_prop(nodeh, pname,
864 strdat, strcount);
865 if (err != PICL_SUCCESS)
866 return (err);
867 } else {
868 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
869 PICL_PTYPE_CHARSTRING, PICL_READ,
870 strlen(strdat) + 1, pname, NULL,
871 NULL);
872 if (err != PICL_SUCCESS)
873 return (err);
874 (void) ptree_create_and_add_prop(nodeh, &propinfo,
875 strdat, NULL);
876 }
877 return (PICL_SUCCESS);
878 }
879
880 /*
881 * Add the OBP properties as properties of the PICL node
882 */
883 static int
884 add_openprom_props(picl_nodehdl_t nodeh, di_node_t di_node)
885 {
886 di_prom_prop_t promp;
887 char *pname;
888 unsigned char *pdata;
889 int retval;
890 ptree_propinfo_t propinfo;
891 int err;
892 picl_prop_type_t type;
893
894 if (!ph)
895 return (PICL_FAILURE);
896
897 for (promp = di_prom_prop_next(ph, di_node, DI_PROM_PROP_NIL);
898 promp != DI_PROM_PROP_NIL;
899 promp = di_prom_prop_next(ph, di_node, promp)) {
900
901 pname = di_prom_prop_name(promp);
902
903 retval = di_prom_prop_data(promp, &pdata);
904 if (retval < 0) {
905 return (PICL_SUCCESS);
906 }
907 if (retval == 0) {
908 err = ptree_init_propinfo(&propinfo,
909 PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID,
910 PICL_READ, (size_t)0, pname, NULL, NULL);
911 if (err != PICL_SUCCESS) {
912 return (err);
913 }
914 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL,
915 NULL);
916 continue;
917 }
918
919 /*
920 * Get the prop type from pname map table
921 */
922 if (lookup_pname_type_map(pname, &type) == 0) {
923 if (type == PICL_PTYPE_CHARSTRING) {
924 err = process_charstring_data(nodeh, pname,
925 pdata, retval);
926 if (err != PICL_SUCCESS) {
927 return (err);
928 }
929 continue;
930 }
931
932 err = ptree_init_propinfo(&propinfo,
933 PTREE_PROPINFO_VERSION, type, PICL_READ,
934 retval, pname, NULL, NULL);
935 if (err != PICL_SUCCESS) {
936 return (err);
937 }
938 (void) ptree_create_and_add_prop(nodeh, &propinfo,
939 pdata, NULL);
940 } else if (!is_string_propval(pdata, retval)) {
941 switch (retval) {
942 case sizeof (uint8_t):
943 /*FALLTHROUGH*/
944 case sizeof (uint16_t):
945 /*FALLTHROUGH*/
946 case sizeof (uint32_t):
947 type = PICL_PTYPE_UNSIGNED_INT;
948 break;
949 default:
950 type = PICL_PTYPE_BYTEARRAY;
951 break;
952 }
953 err = ptree_init_propinfo(&propinfo,
954 PTREE_PROPINFO_VERSION, type, PICL_READ,
955 retval, pname, NULL, NULL);
956 if (err != PICL_SUCCESS) {
957 return (err);
958 }
959 (void) ptree_create_and_add_prop(nodeh, &propinfo,
960 pdata, NULL);
961 } else {
962 err = process_charstring_data(nodeh, pname, pdata,
963 retval);
964 if (err != PICL_SUCCESS) {
965 return (err);
966 }
967 }
968 }
969
970 return (PICL_SUCCESS);
971 }
972
973 static void
974 add_boolean_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val)
975 {
976 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
977 PICL_PTYPE_VOID, PICL_READ, (size_t)0, di_val, NULL, NULL);
978 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
979 }
980
981 static void
982 add_uints_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
983 int *idata, int len)
984 {
985 if (len == 1)
986 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
987 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (int), di_val,
988 NULL, NULL);
989 else
990 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
991 PICL_PTYPE_BYTEARRAY, PICL_READ, len * sizeof (int), di_val,
992 NULL, NULL);
993
994 (void) ptree_create_and_add_prop(nodeh, &propinfo, idata, NULL);
995 }
996
997 static void
998 add_strings_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
999 char *sdata, int len)
1000 {
1001 if (len == 1) {
1002 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1003 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(sdata) + 1, di_val,
1004 NULL, NULL);
1005 (void) ptree_create_and_add_prop(nodeh, &propinfo, sdata, NULL);
1006 } else {
1007 (void) add_string_list_prop(nodeh, di_val, sdata, len);
1008 }
1009 }
1010
1011 static void
1012 add_bytes_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
1013 unsigned char *bdata, int len)
1014 {
1015 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1016 PICL_PTYPE_BYTEARRAY, PICL_READ, len, di_val, NULL, NULL);
1017 (void) ptree_create_and_add_prop(nodeh, &propinfo, bdata, NULL);
1018 }
1019
1020 static const char *
1021 path_state_name(di_path_state_t st)
1022 {
1023 switch (st) {
1024 case DI_PATH_STATE_ONLINE:
1025 return ("online");
1026 case DI_PATH_STATE_STANDBY:
1027 return ("standby");
1028 case DI_PATH_STATE_OFFLINE:
1029 return ("offline");
1030 case DI_PATH_STATE_FAULT:
1031 return ("faulted");
1032 }
1033 return ("unknown");
1034 }
1035
1036 /*
1037 * This function is the volatile property handler for the multipath node
1038 * "State" property. It must locate the associated devinfo node in order to
1039 * determine the current state. Since the devinfo node can have multiple
1040 * paths the devfs_path is used to locate the correct path.
1041 */
1042 static int
1043 get_path_state_name(ptree_rarg_t *rarg, void *vbuf)
1044 {
1045 int err;
1046 picl_nodehdl_t parh;
1047 char devfs_path[PATH_MAX];
1048 di_node_t di_node;
1049 di_node_t di_root;
1050 di_path_t pi = DI_PATH_NIL;
1051 picl_nodehdl_t mpnode;
1052
1053 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
1054
1055 mpnode = rarg->nodeh;
1056
1057 /*
1058 * The parent node represents the vHCI.
1059 */
1060 err = ptree_get_propval_by_name(mpnode, PICL_PROP_PARENT, &parh,
1061 sizeof (picl_nodehdl_t));
1062 if (err != PICL_SUCCESS) {
1063 return (PICL_SUCCESS);
1064 }
1065
1066 /*
1067 * The PICL_PROP_DEVFS_PATH property will be used to locate the
1068 * devinfo node for the vHCI driver.
1069 */
1070 err = ptree_get_propval_by_name(parh, PICL_PROP_DEVFS_PATH, devfs_path,
1071 sizeof (devfs_path));
1072 if (err != PICL_SUCCESS) {
1073 return (PICL_SUCCESS);
1074 }
1075 /*
1076 * Find the di_node for the vHCI driver. It will be used to scan
1077 * the path information nodes.
1078 */
1079 di_root = di_init("/", DINFOCACHE);
1080 if (di_root == DI_NODE_NIL) {
1081 return (PICL_SUCCESS);
1082 }
1083 di_node = di_lookup_node(di_root, devfs_path);
1084 if (di_node == DI_NODE_NIL) {
1085 di_fini(di_root);
1086 return (PICL_SUCCESS);
1087 }
1088
1089 /*
1090 * The devfs_path will be used below to match the
1091 * proper path information node.
1092 */
1093 err = ptree_get_propval_by_name(mpnode, PICL_PROP_DEVFS_PATH,
1094 devfs_path, sizeof (devfs_path));
1095 if (err != PICL_SUCCESS) {
1096 di_fini(di_root);
1097 return (PICL_SUCCESS);
1098 }
1099
1100 /*
1101 * Scan the path information nodes looking for the matching devfs
1102 * path. When found obtain the state information.
1103 */
1104 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
1105 char *di_path;
1106 di_node_t phci_node = di_path_phci_node(pi);
1107
1108 if (phci_node == DI_PATH_NIL)
1109 continue;
1110
1111 di_path = di_devfs_path(phci_node);
1112 if (di_path) {
1113 if (strcmp(di_path, devfs_path) != 0) {
1114 di_devfs_path_free(di_path);
1115 continue;
1116 }
1117 (void) strlcpy(vbuf, path_state_name(di_path_state(pi)),
1118 MAX_STATE_SIZE);
1119 di_devfs_path_free(di_path);
1120 break;
1121 }
1122 }
1123
1124 di_fini(di_root);
1125 return (PICL_SUCCESS);
1126 }
1127
1128 static void
1129 add_di_path_prop(picl_nodehdl_t nodeh, di_path_prop_t di_path_prop)
1130 {
1131 int di_ptype;
1132 char *di_val;
1133 ptree_propinfo_t propinfo;
1134 int *idata;
1135 char *sdata;
1136 unsigned char *bdata;
1137 int len;
1138
1139 di_ptype = di_path_prop_type(di_path_prop);
1140 di_val = di_path_prop_name(di_path_prop);
1141
1142 switch (di_ptype) {
1143 case DI_PROP_TYPE_BOOLEAN:
1144 add_boolean_prop(nodeh, propinfo, di_val);
1145 break;
1146 case DI_PROP_TYPE_INT:
1147 case DI_PROP_TYPE_INT64:
1148 len = di_path_prop_ints(di_path_prop, &idata);
1149 if (len < 0)
1150 /* Received error, so ignore prop */
1151 break;
1152 add_uints_prop(nodeh, propinfo, di_val, idata, len);
1153 break;
1154 case DI_PROP_TYPE_STRING:
1155 len = di_path_prop_strings(di_path_prop, &sdata);
1156 if (len <= 0)
1157 break;
1158 add_strings_prop(nodeh, propinfo, di_val, sdata, len);
1159 break;
1160 case DI_PROP_TYPE_BYTE:
1161 len = di_path_prop_bytes(di_path_prop, &bdata);
1162 if (len < 0)
1163 break;
1164 add_bytes_prop(nodeh, propinfo, di_val, bdata, len);
1165 break;
1166 case DI_PROP_TYPE_UNKNOWN:
1167 /*
1168 * Unknown type, we'll try and guess what it should be.
1169 */
1170 len = di_path_prop_strings(di_path_prop, &sdata);
1171 if ((len > 0) && (sdata[0] != 0)) {
1172 add_strings_prop(nodeh, propinfo, di_val, sdata,
1173 len);
1174 break;
1175 }
1176 len = di_path_prop_ints(di_path_prop, &idata);
1177 if (len > 0) {
1178 add_uints_prop(nodeh, propinfo, di_val,
1179 idata, len);
1180 break;
1181 }
1182 len = di_path_prop_bytes(di_path_prop, &bdata);
1183 if (len > 0)
1184 add_bytes_prop(nodeh, propinfo,
1185 di_val, bdata, len);
1186 else if (len == 0)
1187 add_boolean_prop(nodeh, propinfo,
1188 di_val);
1189 break;
1190 case DI_PROP_TYPE_UNDEF_IT:
1191 break;
1192 default:
1193 break;
1194 }
1195 }
1196
1197 /*
1198 * Add nodes for path information (PSARC/1999/647, PSARC/2008/437)
1199 */
1200 static void
1201 construct_mpath_node(picl_nodehdl_t parh, di_node_t di_node)
1202 {
1203 di_path_t pi = DI_PATH_NIL;
1204
1205 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
1206 di_node_t phci_node = di_path_phci_node(pi);
1207 di_path_prop_t di_path_prop;
1208 picl_nodehdl_t nodeh;
1209 ptree_propinfo_t propinfo;
1210 int err;
1211 int instance;
1212 char *di_val;
1213
1214 if (phci_node == DI_PATH_NIL)
1215 continue;
1216
1217 err = ptree_create_and_add_node(parh, PICL_CLASS_MULTIPATH,
1218 PICL_CLASS_MULTIPATH, &nodeh);
1219 if (err != PICL_SUCCESS)
1220 continue;
1221
1222 instance = di_instance(phci_node);
1223 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1224 PICL_PTYPE_INT, PICL_READ, sizeof (instance),
1225 PICL_PROP_INSTANCE, NULL, NULL);
1226 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance,
1227 NULL);
1228
1229 di_val = di_devfs_path(phci_node);
1230 if (di_val) {
1231 (void) ptree_init_propinfo(&propinfo,
1232 PTREE_PROPINFO_VERSION,
1233 PICL_PTYPE_CHARSTRING, PICL_READ,
1234 strlen(di_val) + 1, PICL_PROP_DEVFS_PATH,
1235 NULL, NULL);
1236 (void) ptree_create_and_add_prop(nodeh,
1237 &propinfo, di_val, NULL);
1238 di_devfs_path_free(di_val);
1239 }
1240
1241 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1242 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE),
1243 MAX_STATE_SIZE, PICL_PROP_STATE, get_path_state_name, NULL);
1244 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
1245
1246 for (di_path_prop = di_path_prop_next(pi, DI_PROP_NIL);
1247 di_path_prop != DI_PROP_NIL;
1248 di_path_prop = di_path_prop_next(pi, di_path_prop)) {
1249 add_di_path_prop(nodeh, di_path_prop);
1250 }
1251 }
1252 }
1253
1254 /*
1255 * Add properties provided by libdevinfo
1256 */
1257 static void
1258 add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node)
1259 {
1260 int instance;
1261 char *di_val;
1262 di_prop_t di_prop;
1263 int di_ptype;
1264 ptree_propinfo_t propinfo;
1265 char *sdata;
1266 unsigned char *bdata;
1267 int *idata;
1268 int len;
1269
1270 instance = di_instance(di_node);
1271 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1272 PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE,
1273 NULL, NULL);
1274 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL);
1275
1276 di_val = di_bus_addr(di_node);
1277 if (di_val) {
1278 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1279 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1280 PICL_PROP_BUS_ADDR, NULL, NULL);
1281 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1282 NULL);
1283 }
1284
1285 di_val = di_binding_name(di_node);
1286 if (di_val) {
1287 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1288 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1289 PICL_PROP_BINDING_NAME, NULL, NULL);
1290 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1291 NULL);
1292 }
1293
1294 di_val = di_driver_name(di_node);
1295 if (di_val) {
1296 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1297 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1298 PICL_PROP_DRIVER_NAME, NULL, NULL);
1299 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1300 NULL);
1301 }
1302
1303 di_val = di_devfs_path(di_node);
1304 if (di_val) {
1305 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1306 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1307 PICL_PROP_DEVFS_PATH, NULL, NULL);
1308 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1309 NULL);
1310 di_devfs_path_free(di_val);
1311 }
1312
1313 for (di_prop = di_prop_next(di_node, DI_PROP_NIL);
1314 di_prop != DI_PROP_NIL;
1315 di_prop = di_prop_next(di_node, di_prop)) {
1316
1317 di_val = di_prop_name(di_prop);
1318 di_ptype = di_prop_type(di_prop);
1319
1320 switch (di_ptype) {
1321 case DI_PROP_TYPE_BOOLEAN:
1322 add_boolean_prop(nodeh, propinfo, di_val);
1323 break;
1324 case DI_PROP_TYPE_INT:
1325 len = di_prop_ints(di_prop, &idata);
1326 if (len < 0)
1327 /* Received error, so ignore prop */
1328 break;
1329 add_uints_prop(nodeh, propinfo, di_val, idata, len);
1330 break;
1331 case DI_PROP_TYPE_STRING:
1332 len = di_prop_strings(di_prop, &sdata);
1333 if (len < 0)
1334 break;
1335 add_strings_prop(nodeh, propinfo, di_val, sdata, len);
1336 break;
1337 case DI_PROP_TYPE_BYTE:
1338 len = di_prop_bytes(di_prop, &bdata);
1339 if (len < 0)
1340 break;
1341 add_bytes_prop(nodeh, propinfo, di_val, bdata, len);
1342 break;
1343 case DI_PROP_TYPE_UNKNOWN:
1344 /*
1345 * Unknown type, we'll try and guess what it should be.
1346 */
1347 len = di_prop_strings(di_prop, &sdata);
1348 if ((len > 0) && (sdata[0] != 0)) {
1349 add_strings_prop(nodeh, propinfo, di_val, sdata,
1350 len);
1351 break;
1352 }
1353 len = di_prop_ints(di_prop, &idata);
1354 if (len > 0) {
1355 add_uints_prop(nodeh, propinfo, di_val,
1356 idata, len);
1357 break;
1358 }
1359 len = di_prop_rawdata(di_prop, &bdata);
1360 if (len > 0)
1361 add_bytes_prop(nodeh, propinfo,
1362 di_val, bdata, len);
1363 else if (len == 0)
1364 add_boolean_prop(nodeh, propinfo,
1365 di_val);
1366 break;
1367 case DI_PROP_TYPE_UNDEF_IT:
1368 break;
1369 default:
1370 break;
1371 }
1372 }
1373 }
1374
1375 /*
1376 * This function creates the /obp node in the PICL tree for OBP nodes
1377 * without a device type class.
1378 */
1379 static int
1380 construct_picl_openprom(picl_nodehdl_t rooth, picl_nodehdl_t *obph)
1381 {
1382 picl_nodehdl_t tmph;
1383 int err;
1384
1385 err = ptree_create_and_add_node(rooth, PICL_NODE_OBP,
1386 PICL_CLASS_PICL, &tmph);
1387
1388 if (err != PICL_SUCCESS)
1389 return (err);
1390 *obph = tmph;
1391 return (PICL_SUCCESS);
1392 }
1393
1394 /*
1395 * This function creates the /platform node in the PICL tree and
1396 * its properties. It sets the "platform-name" property to the
1397 * platform name
1398 */
1399 static int
1400 construct_picl_platform(picl_nodehdl_t rooth, di_node_t di_root,
1401 picl_nodehdl_t *piclh)
1402 {
1403 int err;
1404 picl_nodehdl_t plafh;
1405 char *nodename;
1406 char nodeclass[PICL_CLASSNAMELEN_MAX];
1407 ptree_propinfo_t propinfo;
1408 picl_prophdl_t proph;
1409
1410 nodename = di_node_name(di_root);
1411 if (nodename == NULL)
1412 return (PICL_FAILURE);
1413
1414 err = 0;
1415 if (di_nodeid(di_root) == DI_PROM_NODEID ||
1416 di_nodeid(di_root) == DI_SID_NODEID)
1417 err = get_device_type(nodeclass, di_root);
1418
1419 if (err < 0)
1420 (void) strcpy(nodeclass, PICL_CLASS_UPA); /* default */
1421
1422 err = ptree_create_and_add_node(rooth, PICL_NODE_PLATFORM,
1423 nodeclass, &plafh);
1424 if (err != PICL_SUCCESS)
1425 return (err);
1426
1427 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1428 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(nodename) + 1,
1429 PICL_PROP_PLATFORM_NAME, NULL, NULL);
1430 err = ptree_create_and_add_prop(plafh, &propinfo, nodename, &proph);
1431 if (err != PICL_SUCCESS)
1432 return (err);
1433
1434 (void) add_devinfo_props(plafh, di_root);
1435
1436 (void) add_openprom_props(plafh, di_root);
1437
1438 *piclh = plafh;
1439
1440 return (PICL_SUCCESS);
1441 }
1442
1443 /*
1444 * This function creates a node in /obp tree for the libdevinfo handle.
1445 */
1446 static int
1447 construct_obp_node(picl_nodehdl_t parh, di_node_t dn, picl_nodehdl_t *chdh)
1448 {
1449 int err;
1450 char *nodename;
1451 char nodeclass[PICL_CLASSNAMELEN_MAX];
1452 picl_nodehdl_t anodeh;
1453
1454 nodename = di_node_name(dn); /* PICL_PROP_NAME */
1455 if (nodename == NULL)
1456 return (PICL_FAILURE);
1457
1458 if (strcmp(nodename, "pseudo") == 0)
1459 return (PICL_FAILURE);
1460
1461 if ((di_nodeid(dn) == DI_PROM_NODEID) &&
1462 (get_device_type(nodeclass, dn) == 0))
1463 return (PICL_FAILURE);
1464
1465 err = ptree_create_and_add_node(parh, nodename, nodename, &anodeh);
1466 if (err != PICL_SUCCESS)
1467 return (err);
1468
1469 add_devinfo_props(anodeh, dn);
1470
1471 (void) add_openprom_props(anodeh, dn);
1472
1473 *chdh = anodeh;
1474
1475 return (PICL_SUCCESS);
1476 }
1477
1478 /*
1479 * This function creates a PICL node in /platform tree for a device
1480 */
1481 static int
1482 construct_devtype_node(picl_nodehdl_t parh, char *nodename,
1483 char *nodeclass, di_node_t dn, picl_nodehdl_t *chdh)
1484 {
1485 int err;
1486 picl_nodehdl_t anodeh;
1487
1488 err = ptree_create_and_add_node(parh, nodename, nodeclass, &anodeh);
1489 if (err != PICL_SUCCESS)
1490 return (err);
1491
1492 (void) add_devinfo_props(anodeh, dn);
1493 (void) add_openprom_props(anodeh, dn);
1494 construct_mpath_node(anodeh, dn);
1495
1496 *chdh = anodeh;
1497 return (err);
1498 }
1499
1500 /*
1501 * Create a subtree of "picl" class nodes in /obp for these nodes
1502 */
1503 static int
1504 construct_openprom_tree(picl_nodehdl_t nodeh, di_node_t dinode)
1505 {
1506 di_node_t cnode;
1507 picl_nodehdl_t chdh;
1508 int err;
1509
1510 err = construct_obp_node(nodeh, dinode, &chdh);
1511 if (err != PICL_SUCCESS)
1512 return (err);
1513
1514 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL;
1515 cnode = di_sibling_node(cnode))
1516 (void) construct_openprom_tree(chdh, cnode);
1517
1518 return (PICL_SUCCESS);
1519
1520 }
1521
1522 /*
1523 * Process the libdevinfo device tree and create nodes in /platform or /obp
1524 * PICL tree.
1525 *
1526 * This routine traverses the immediate children of "dinode" device and
1527 * determines the node class for that child. If it finds a valid class
1528 * name, then it builds a PICL node under /platform subtree and calls itself
1529 * recursively to construct the subtree for that child node. Otherwise, if
1530 * the parent_class is NULL, then it constructs a node and subtree under /obp
1531 * subtree.
1532 *
1533 * Note that we skip the children nodes that don't have a valid class name
1534 * and the parent_class is non NULL to prevent creation of any placeholder
1535 * nodes (such as sd,...).
1536 */
1537 static int
1538 construct_devinfo_tree(picl_nodehdl_t plafh, picl_nodehdl_t obph,
1539 di_node_t dinode, char *parent_class)
1540 {
1541 di_node_t cnode;
1542 picl_nodehdl_t chdh;
1543 char nodeclass[PICL_CLASSNAMELEN_MAX];
1544 char *nodename;
1545 int err;
1546
1547 err = PICL_SUCCESS;
1548 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL;
1549 cnode = di_sibling_node(cnode)) {
1550 nodename = di_node_name(cnode); /* PICL_PROP_NAME */
1551 if (nodename == NULL)
1552 continue;
1553
1554 err = get_node_class(nodeclass, cnode, nodename);
1555
1556 if (err == 0) {
1557 err = construct_devtype_node(plafh, nodename,
1558 nodeclass, cnode, &chdh);
1559 if (err != PICL_SUCCESS)
1560 return (err);
1561 err = construct_devinfo_tree(chdh, obph, cnode,
1562 nodeclass);
1563 } else if (parent_class == NULL)
1564 err = construct_openprom_tree(obph, cnode);
1565 else
1566 continue;
1567 /*
1568 * if parent_class is non NULL, skip the children nodes
1569 * that don't have a valid device class - eliminates
1570 * placeholder nodes (sd,...) from being created.
1571 */
1572 }
1573
1574 return (err);
1575
1576 }
1577
1578 /*
1579 * This function is called from the event handler called from the daemon
1580 * on PICL events.
1581 *
1582 * This routine traverses the children of the "dinode" device and
1583 * creates a PICL node for each child not found in the PICL tree and
1584 * invokes itself recursively to create a subtree for the newly created
1585 * child node. It also checks if the node being created is a meory
1586 * controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL
1587 * framework.
1588 */
1589 static int
1590 update_subtree(picl_nodehdl_t nodeh, di_node_t dinode)
1591 {
1592 di_node_t cnode;
1593 picl_nodehdl_t chdh;
1594 picl_nodehdl_t nh;
1595 char *nodename;
1596 char nodeclass[PICL_CLASSNAMELEN_MAX];
1597 char *path_buf;
1598 char buf[MAX_UNIT_ADDRESS_LEN];
1599 char unitaddr[MAX_UNIT_ADDRESS_LEN];
1600 char path_w_ua[MAXPATHLEN];
1601 char path_wo_ua[MAXPATHLEN];
1602 char *strp;
1603 int gotit;
1604 int err;
1605
1606 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL;
1607 cnode = di_sibling_node(cnode)) {
1608 path_buf = di_devfs_path(cnode);
1609 if (path_buf == NULL)
1610 continue;
1611
1612 nodename = di_node_name(cnode);
1613 if (nodename == NULL) {
1614 di_devfs_path_free(path_buf);
1615 continue;
1616 }
1617
1618 err = get_node_class(nodeclass, cnode, nodename);
1619
1620 if (err < 0) {
1621 di_devfs_path_free(path_buf);
1622 continue;
1623 }
1624
1625 /*
1626 * this is quite complicated - both path_buf and any nodes
1627 * already in the picl tree may, or may not, have the
1628 * @<unit_addr> at the end of their names. So we must
1629 * take path_buf and work out what the device path would
1630 * be both with and without the unit_address, then search
1631 * the picl tree for both forms.
1632 */
1633 if (((strp = strrchr(path_buf, '/')) != NULL) &&
1634 strchr(strp, '@') == NULL) {
1635 /*
1636 * This is an unattached node - so the path is not
1637 * unique. Need to find out which node it is.
1638 * Find the unit_address from the OBP or devinfo
1639 * properties.
1640 */
1641 err = ptree_create_node(nodename, nodeclass, &chdh);
1642 if (err != PICL_SUCCESS)
1643 return (err);
1644
1645 (void) add_devinfo_props(chdh, cnode);
1646 (void) add_openprom_props(chdh, cnode);
1647
1648 err = get_unitaddr(nodeh, chdh, unitaddr,
1649 sizeof (unitaddr));
1650 if (err != PICL_SUCCESS)
1651 return (err);
1652 (void) ptree_destroy_node(chdh);
1653 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s@%s",
1654 path_buf, unitaddr);
1655 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s",
1656 path_buf);
1657 } else {
1658 /*
1659 * this is an attached node - so the path is unique
1660 */
1661 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s",
1662 path_buf);
1663 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s",
1664 path_buf);
1665 strp = strrchr(path_wo_ua, '@');
1666 *strp++ = '\0';
1667 (void) snprintf(unitaddr, sizeof (unitaddr), "%s",
1668 strp);
1669 }
1670 /*
1671 * first look for node with unit address in devfs_path
1672 */
1673 if (ptree_find_node(nodeh, PICL_PROP_DEVFS_PATH,
1674 PICL_PTYPE_CHARSTRING, path_w_ua, strlen(path_w_ua) + 1,
1675 &nh) == PICL_SUCCESS) {
1676 /*
1677 * node already there - there's nothing we need to do
1678 */
1679 if (picldevtree_debug > 1)
1680 syslog(LOG_INFO,
1681 "update_subtree: path:%s node exists\n",
1682 path_buf);
1683 di_devfs_path_free(path_buf);
1684 continue;
1685 }
1686 /*
1687 * now look for node without unit address in devfs_path.
1688 * This might be just one out of several
1689 * nodes - need to check all siblings
1690 */
1691 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
1692 &chdh, sizeof (chdh));
1693 if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
1694 return (err);
1695 gotit = 0;
1696 while (err == PICL_SUCCESS) {
1697 err = ptree_get_propval_by_name(chdh,
1698 PICL_PROP_DEVFS_PATH, buf, sizeof (buf));
1699 if (err != PICL_SUCCESS)
1700 return (err);
1701 if (strcmp(buf, path_wo_ua) == 0) {
1702 err = ptree_get_propval_by_name(chdh,
1703 PICL_PROP_UNIT_ADDRESS, buf, sizeof (buf));
1704 if (err != PICL_SUCCESS)
1705 return (err);
1706 if (strcmp(buf, unitaddr) == 0) {
1707 gotit = 1;
1708 break;
1709 }
1710 }
1711 err = ptree_get_propval_by_name(chdh,
1712 PICL_PROP_PEER, &chdh, sizeof (chdh));
1713 if (err != PICL_SUCCESS)
1714 break;
1715 }
1716 if (gotit) {
1717 /*
1718 * node already there - there's nothing we need to do
1719 */
1720 if (picldevtree_debug > 1)
1721 syslog(LOG_INFO,
1722 "update_subtree: path:%s node exists\n",
1723 path_buf);
1724 di_devfs_path_free(path_buf);
1725 continue;
1726 }
1727
1728 #define IS_MC(x) (strcmp(x, PICL_CLASS_MEMORY_CONTROLLER) == 0 ? 1 : 0)
1729
1730 if (construct_devtype_node(nodeh, nodename, nodeclass, cnode,
1731 &chdh) == PICL_SUCCESS) {
1732 if (picldevtree_debug)
1733 syslog(LOG_INFO,
1734 "picldevtree: added node:%s path:%s\n",
1735 nodename, path_buf);
1736 if (IS_MC(nodeclass)) {
1737 if (post_mc_event(PICLEVENT_MC_ADDED, chdh) !=
1738 PICL_SUCCESS)
1739 syslog(LOG_WARNING, PICL_EVENT_DROPPED,
1740 PICLEVENT_MC_ADDED);
1741 }
1742
1743 di_devfs_path_free(path_buf);
1744 (void) update_subtree(chdh, cnode);
1745 }
1746 }
1747
1748 return (PICL_SUCCESS);
1749
1750 }
1751
1752 /*
1753 * Check for a stale OBP node. EINVAL is returned from the openprom(7D) driver
1754 * if the nodeid stored in the snapshot is not valid.
1755 */
1756 static int
1757 check_stale_node(di_node_t node, void *arg)
1758 {
1759 di_prom_prop_t promp;
1760
1761 errno = 0;
1762 promp = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL);
1763 if (promp == DI_PROM_PROP_NIL && errno == EINVAL) {
1764 snapshot_stale = 1;
1765 return (DI_WALK_TERMINATE);
1766 }
1767 return (DI_WALK_CONTINUE);
1768 }
1769
1770 /*
1771 * Walk the snapshot and check the OBP properties of each node.
1772 */
1773 static int
1774 is_snapshot_stale(di_node_t root)
1775 {
1776 snapshot_stale = 0;
1777 (void) di_walk_node(root, DI_WALK_CLDFIRST, NULL, check_stale_node);
1778 return (snapshot_stale);
1779 }
1780
1781 /*
1782 * This function processes the data from libdevinfo and creates nodes
1783 * in the PICL tree.
1784 */
1785 static int
1786 libdevinfo_init(picl_nodehdl_t rooth)
1787 {
1788 di_node_t di_root;
1789 picl_nodehdl_t plafh;
1790 picl_nodehdl_t obph;
1791 int err;
1792
1793 /*
1794 * Use DINFOCACHE so that we obtain all attributes for all
1795 * device instances (without necessarily doing a load/attach
1796 * of all drivers). Once the (on-disk) cache file is built, it
1797 * exists over a reboot and can be read into memory at a very
1798 * low cost.
1799 */
1800 if ((di_root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
1801 return (PICL_FAILURE);
1802
1803 if ((ph = di_prom_init()) == NULL)
1804 return (PICL_FAILURE);
1805
1806 /*
1807 * Check if the snapshot cache contains stale OBP nodeid references.
1808 * If it does release the snapshot and obtain a live snapshot from the
1809 * kernel.
1810 */
1811 if (is_snapshot_stale(di_root)) {
1812 syslog(LOG_INFO, "picld detected stale snapshot cache");
1813 di_fini(di_root);
1814 if ((di_root = di_init("/", DINFOCPYALL | DINFOFORCE)) ==
1815 DI_NODE_NIL) {
1816 return (PICL_FAILURE);
1817 }
1818 }
1819
1820 /*
1821 * create platform PICL node using di_root node
1822 */
1823 err = construct_picl_platform(rooth, di_root, &plafh);
1824 if (err != PICL_SUCCESS) {
1825 di_fini(di_root);
1826 return (PICL_FAILURE);
1827 }
1828
1829 err = construct_picl_openprom(rooth, &obph);
1830 if (err != PICL_SUCCESS) {
1831 di_fini(di_root);
1832 return (PICL_FAILURE);
1833 }
1834
1835 (void) construct_devinfo_tree(plafh, obph, di_root, NULL);
1836 if (ph) {
1837 di_prom_fini(ph);
1838 ph = NULL;
1839 }
1840 di_fini(di_root);
1841 return (err);
1842 }
1843
1844 /*
1845 * This function returns the integer property value
1846 */
1847 static int
1848 get_int_propval_by_name(picl_nodehdl_t nodeh, char *pname, int *ival)
1849 {
1850 int err;
1851
1852 err = ptree_get_propval_by_name(nodeh, pname, ival,
1853 sizeof (int));
1854
1855 return (err);
1856 }
1857
1858 /*
1859 * This function returns the port ID (or CPU ID in the case of CMP cores)
1860 * of the specific CPU node handle. If upa_portid exists, return its value.
1861 * Otherwise, return portid/cpuid.
1862 */
1863 static int
1864 get_cpu_portid(picl_nodehdl_t modh, int *id)
1865 {
1866 int err;
1867
1868 if (strcmp(mach_name, "sun4u") == 0 ||
1869 strcmp(mach_name, "sun4v") == 0) {
1870 err = get_int_propval_by_name(modh, OBP_PROP_UPA_PORTID, id);
1871 if (err == PICL_SUCCESS)
1872 return (err);
1873 err = get_int_propval_by_name(modh, OBP_PROP_PORTID, id);
1874 if (err == PICL_SUCCESS)
1875 return (err);
1876 return (get_int_propval_by_name(modh, OBP_PROP_CPUID, id));
1877 }
1878 if (strcmp(mach_name, "i86pc") == 0)
1879 return (get_int_propval_by_name(modh, OBP_REG, id));
1880
1881 return (PICL_FAILURE);
1882 }
1883
1884 /*
1885 * This function is the volatile read access function of CPU state
1886 * property
1887 */
1888 static int
1889 get_pi_state(ptree_rarg_t *rarg, void *vbuf)
1890 {
1891 int id;
1892 int err;
1893
1894 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1895 if (err != PICL_SUCCESS)
1896 return (err);
1897
1898 switch (p_online(id, P_STATUS)) {
1899 case P_ONLINE:
1900 (void) strlcpy(vbuf, PS_ONLINE, MAX_STATE_SIZE);
1901 break;
1902 case P_OFFLINE:
1903 (void) strlcpy(vbuf, PS_OFFLINE, MAX_STATE_SIZE);
1904 break;
1905 case P_NOINTR:
1906 (void) strlcpy(vbuf, PS_NOINTR, MAX_STATE_SIZE);
1907 break;
1908 case P_SPARE:
1909 (void) strlcpy(vbuf, PS_SPARE, MAX_STATE_SIZE);
1910 break;
1911 case P_FAULTED:
1912 (void) strlcpy(vbuf, PS_FAULTED, MAX_STATE_SIZE);
1913 break;
1914 case P_POWEROFF:
1915 (void) strlcpy(vbuf, PS_POWEROFF, MAX_STATE_SIZE);
1916 break;
1917 default:
1918 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
1919 break;
1920 }
1921 return (PICL_SUCCESS);
1922 }
1923
1924 /*
1925 * This function is the volatile read access function of CPU processor_type
1926 * property
1927 */
1928 static int
1929 get_processor_type(ptree_rarg_t *rarg, void *vbuf)
1930 {
1931 processor_info_t cpu_info;
1932 int id;
1933 int err;
1934
1935 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1936 if (err != PICL_SUCCESS)
1937 return (err);
1938
1939 if (processor_info(id, &cpu_info) >= 0) {
1940 (void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN);
1941 }
1942 return (PICL_SUCCESS);
1943 }
1944
1945 /*
1946 * This function is the volatile read access function of CPU fputypes
1947 * property
1948 */
1949 static int
1950 get_fputypes(ptree_rarg_t *rarg, void *vbuf)
1951 {
1952 processor_info_t cpu_info;
1953 int id;
1954 int err;
1955
1956 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1957 if (err != PICL_SUCCESS)
1958 return (err);
1959
1960 if (processor_info(id, &cpu_info) >= 0) {
1961 (void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE);
1962 }
1963 return (PICL_SUCCESS);
1964 }
1965
1966 /*
1967 * This function is the volatile read access function of CPU StateBegin
1968 * property. To minimize overhead, use kstat_chain_update() to refresh
1969 * the kstat header info as opposed to invoking kstat_open() every time.
1970 */
1971 static int
1972 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf)
1973 {
1974 int err;
1975 int cpu_id;
1976 static kstat_ctl_t *kc = NULL;
1977 static pthread_mutex_t kc_mutex = PTHREAD_MUTEX_INITIALIZER;
1978 kstat_t *kp;
1979 kstat_named_t *kn;
1980
1981 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id);
1982 if (err != PICL_SUCCESS)
1983 return (err);
1984
1985 (void) pthread_mutex_lock(&kc_mutex);
1986 if (kc == NULL)
1987 kc = kstat_open();
1988 else if (kstat_chain_update(kc) == -1) {
1989 (void) kstat_close(kc);
1990 kc = kstat_open();
1991 }
1992
1993 if (kc == NULL) {
1994 (void) pthread_mutex_unlock(&kc_mutex);
1995 return (PICL_FAILURE);
1996 }
1997
1998 /* Get the state_begin from kstat */
1999 if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL ||
2000 kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) {
2001 (void) pthread_mutex_unlock(&kc_mutex);
2002 return (PICL_FAILURE);
2003 }
2004
2005 kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN);
2006 if (kn) {
2007 *(uint64_t *)vbuf = (uint64_t)kn->value.l;
2008 err = PICL_SUCCESS;
2009 } else
2010 err = PICL_FAILURE;
2011
2012 (void) pthread_mutex_unlock(&kc_mutex);
2013 return (err);
2014 }
2015
2016 /*
2017 * This function adds CPU information to the CPU nodes
2018 */
2019 /* ARGSUSED */
2020 static int
2021 add_processor_info(picl_nodehdl_t cpuh, void *args)
2022 {
2023 int err;
2024 int cpu_id;
2025 ptree_propinfo_t propinfo;
2026 ptree_propinfo_t pinfo;
2027
2028 err = get_cpu_portid(cpuh, &cpu_id);
2029 if (err != PICL_SUCCESS)
2030 return (PICL_WALK_CONTINUE);
2031
2032 /*
2033 * Check to make sure that the CPU is still present, i.e. that it
2034 * has not been DR'ed out of the system.
2035 */
2036 if (p_online(cpu_id, P_STATUS) == -1) {
2037 if (picldevtree_debug)
2038 syslog(LOG_INFO,
2039 "picldevtree: cpu %d (%llx) does not exist - "
2040 "deleting node\n", cpu_id, cpuh);
2041
2042 if (ptree_delete_node(cpuh) == PICL_SUCCESS)
2043 (void) ptree_destroy_node(cpuh);
2044
2045 return (PICL_WALK_CONTINUE);
2046 }
2047
2048 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2049 PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL);
2050 err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL);
2051 if (err != PICL_SUCCESS)
2052 return (PICL_WALK_CONTINUE);
2053
2054 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2055 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE,
2056 PICL_PROP_STATE, get_pi_state, NULL);
2057 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2058
2059 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2060 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN,
2061 PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL);
2062 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2063
2064 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2065 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE,
2066 PICL_PROP_FPUTYPE, get_fputypes, NULL);
2067 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2068
2069 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2070 PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t),
2071 PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL);
2072 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2073
2074 return (PICL_WALK_CONTINUE);
2075 }
2076
2077 /*
2078 * This function sets up the "ID" property in every CPU nodes
2079 * and adds processor info
2080 */
2081 static int
2082 setup_cpus(picl_nodehdl_t plafh)
2083 {
2084 int err;
2085
2086 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL,
2087 add_processor_info);
2088
2089 return (err);
2090 }
2091
2092 /*
2093 * This function format's the manufacture's information for FFB display
2094 * devices
2095 */
2096 static void
2097 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf)
2098 {
2099 /*
2100 * Format the manufacturer's info. Note a small inconsistency we
2101 * have to work around - Brooktree has it's part number in decimal,
2102 * while Mitsubishi has it's part number in hex.
2103 */
2104 switch (manufid.fld.manf) {
2105 case MANF_BROOKTREE:
2106 (void) snprintf(outbuf, bufsz, "%s %d, version %d",
2107 "Brooktree", manufid.fld.partno, manufid.fld.version);
2108 break;
2109
2110 case MANF_MITSUBISHI:
2111 (void) snprintf(outbuf, bufsz, "%s %x, version %d",
2112 "Mitsubishi", manufid.fld.partno, manufid.fld.version);
2113 break;
2114
2115 default:
2116 (void) snprintf(outbuf, bufsz,
2117 "JED code %d, Part num 0x%x, version %d",
2118 manufid.fld.manf, manufid.fld.partno, manufid.fld.version);
2119 }
2120 }
2121
2122 /*
2123 * If it's an ffb device, open ffb devices and return PICL_SUCCESS
2124 */
2125 static int
2126 open_ffb_device(picl_nodehdl_t ffbh, int *fd)
2127 {
2128 DIR *dirp;
2129 char devfs_path[PATH_MAX];
2130 char dev_path[PATH_MAX];
2131 char *devp;
2132 struct dirent *direntp;
2133 int err;
2134 int tmpfd;
2135
2136 /* Get the devfs_path of the ffb devices */
2137 err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path,
2138 sizeof (devfs_path));
2139 if (err != PICL_SUCCESS)
2140 return (err);
2141
2142 /* Get the device node name */
2143 devp = strrchr(devfs_path, '/');
2144 if (devp == NULL)
2145 return (PICL_FAILURE);
2146 *devp = '\0';
2147 ++devp;
2148
2149 /*
2150 * Check if device node name has the ffb string
2151 * If not, assume it's not a ffb device.
2152 */
2153 if (strstr(devp, FFB_NAME) == NULL)
2154 return (PICL_FAILURE);
2155
2156 /*
2157 * Get the parent path of the ffb device node.
2158 */
2159 (void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices",
2160 devfs_path);
2161
2162 /*
2163 * Since we don't know ffb's minor nodename,
2164 * we need to search all the devices under its
2165 * parent dir by comparing the node name
2166 */
2167 if ((dirp = opendir(dev_path)) == NULL)
2168 return (PICL_FAILURE);
2169
2170 while ((direntp = readdir(dirp)) != NULL) {
2171 if (strstr(direntp->d_name, devp) != NULL) {
2172 (void) strcat(dev_path, "/");
2173 (void) strcat(dev_path, direntp->d_name);
2174 tmpfd = open(dev_path, O_RDWR);
2175 if (tmpfd < 0)
2176 continue;
2177 *fd = tmpfd;
2178 (void) closedir(dirp);
2179 return (PICL_SUCCESS);
2180 }
2181 }
2182
2183 (void) closedir(dirp);
2184 return (PICL_FAILURE);
2185 }
2186
2187 /*
2188 * This function recursively searches the tree for ffb display devices
2189 * and add ffb config information
2190 */
2191 static int
2192 add_ffb_config_info(picl_nodehdl_t rooth)
2193 {
2194 picl_nodehdl_t nodeh;
2195 int err;
2196 char piclclass[PICL_CLASSNAMELEN_MAX];
2197 char manfidbuf[FFB_MANUF_BUFSIZE];
2198 int fd;
2199 int board_rev;
2200 ffb_sys_info_t fsi;
2201 ptree_propinfo_t pinfo;
2202
2203 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
2204 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2205 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
2206 &nodeh, sizeof (picl_nodehdl_t))) {
2207
2208 if (err != PICL_SUCCESS)
2209 return (err);
2210
2211 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2212 piclclass, PICL_CLASSNAMELEN_MAX);
2213
2214 if ((err == PICL_SUCCESS) &&
2215 (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) {
2216
2217 err = open_ffb_device(nodeh, &fd);
2218 if ((err == PICL_SUCCESS) &&
2219 (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) {
2220 (void) ptree_init_propinfo(&pinfo,
2221 PTREE_PROPINFO_VERSION,
2222 PICL_PTYPE_UNSIGNED_INT, PICL_READ,
2223 sizeof (int), PICL_PROP_FFB_BOARD_REV,
2224 NULL, NULL);
2225 board_rev = fsi.ffb_strap_bits.fld.board_rev;
2226 (void) ptree_create_and_add_prop(nodeh, &pinfo,
2227 &board_rev, NULL);
2228
2229 fmt_manf_id(fsi.dac_version,
2230 sizeof (manfidbuf), manfidbuf);
2231 (void) ptree_init_propinfo(&pinfo,
2232 PTREE_PROPINFO_VERSION,
2233 PICL_PTYPE_CHARSTRING, PICL_READ,
2234 strlen(manfidbuf) + 1,
2235 PICL_PROP_FFB_DAC_VER, NULL, NULL);
2236 (void) ptree_create_and_add_prop(nodeh, &pinfo,
2237 manfidbuf, NULL);
2238
2239 fmt_manf_id(fsi.fbram_version,
2240 sizeof (manfidbuf), manfidbuf);
2241 (void) ptree_init_propinfo(&pinfo,
2242 PTREE_PROPINFO_VERSION,
2243 PICL_PTYPE_CHARSTRING, PICL_READ,
2244 strlen(manfidbuf) + 1,
2245 PICL_PROP_FFB_FBRAM_VER, NULL,
2246 NULL);
2247 (void) ptree_create_and_add_prop(nodeh, &pinfo,
2248 manfidbuf, NULL);
2249 (void) close(fd);
2250 }
2251 } else if (add_ffb_config_info(nodeh) != PICL_SUCCESS)
2252 return (PICL_FAILURE);
2253 }
2254 return (PICL_SUCCESS);
2255 }
2256
2257 static conf_entries_t *
2258 free_conf_entries(conf_entries_t *list)
2259 {
2260 conf_entries_t *el;
2261 conf_entries_t *del;
2262
2263 if (list == NULL)
2264 return (NULL);
2265 el = list;
2266 while (el != NULL) {
2267 del = el;
2268 el = el->next;
2269 free(del->name);
2270 free(del->piclclass);
2271 free(del);
2272 }
2273 return (el);
2274 }
2275
2276 /*
2277 * Reading config order: platform, common
2278 */
2279 static conf_entries_t *
2280 read_conf_file(char *fname, conf_entries_t *list)
2281 {
2282 FILE *fp;
2283 char lbuf[CONFFILE_LINELEN_MAX];
2284 char *nametok;
2285 char *classtok;
2286 conf_entries_t *el;
2287 conf_entries_t *ptr;
2288
2289 if (fname == NULL)
2290 return (list);
2291
2292 fp = fopen(fname, "r");
2293
2294 if (fp == NULL)
2295 return (list);
2296
2297 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) {
2298 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n'))
2299 continue;
2300
2301 nametok = strtok(lbuf, " \t\n");
2302 if (nametok == NULL)
2303 continue;
2304
2305 classtok = strtok(NULL, " \t\n");
2306 if (classtok == NULL)
2307 continue;
2308
2309 el = malloc(sizeof (conf_entries_t));
2310 if (el == NULL)
2311 break;
2312 el->name = strdup(nametok);
2313 el->piclclass = strdup(classtok);
2314 if ((el->name == NULL) || (el->piclclass == NULL)) {
2315 free(el);
2316 return (list);
2317 }
2318 el->next = NULL;
2319
2320 /*
2321 * Add it to the end of list
2322 */
2323 if (list == NULL)
2324 list = el;
2325 else {
2326 ptr = list;
2327 while (ptr->next != NULL)
2328 ptr = ptr->next;
2329 ptr->next = el;
2330 }
2331
2332 }
2333 (void) fclose(fp);
2334 return (list);
2335 }
2336
2337 /*
2338 * Process the devtree conf file and set up the conf_name_class_map list
2339 */
2340 static void
2341 process_devtree_conf_file(void)
2342 {
2343 char nmbuf[SYS_NMLN];
2344 char pname[PATH_MAX];
2345
2346 conf_name_class_map = NULL;
2347
2348 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2349 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2350 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX);
2351 conf_name_class_map = read_conf_file(pname,
2352 conf_name_class_map);
2353 }
2354
2355 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2356 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2357 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX);
2358 conf_name_class_map = read_conf_file(pname,
2359 conf_name_class_map);
2360 }
2361
2362 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
2363 DEVTREE_CONFFILE_NAME);
2364 conf_name_class_map = read_conf_file(pname, conf_name_class_map);
2365 }
2366
2367 static asr_conf_entries_t *conf_name_asr_map = NULL;
2368
2369 static void
2370 free_asr_conf_entries(asr_conf_entries_t *list) {
2371 asr_conf_entries_t *el;
2372 asr_conf_entries_t *del;
2373
2374 el = list;
2375 while (el != NULL) {
2376 del = el;
2377 el = el->next;
2378 if (del->name)
2379 free(del->name);
2380 if (del->address)
2381 free(del->address);
2382 if (del->status)
2383 free(del->status);
2384 if (del->piclclass)
2385 free(del->piclclass);
2386 if (del->props)
2387 free(del->props);
2388 free(del);
2389 }
2390 }
2391
2392 /*
2393 * Reading config order: platform, common
2394 */
2395 static asr_conf_entries_t *
2396 read_asr_conf_file(char *fname, asr_conf_entries_t *list)
2397 {
2398 FILE *fp;
2399 char lbuf[CONFFILE_LINELEN_MAX];
2400 char *nametok;
2401 char *classtok;
2402 char *statustok;
2403 char *addresstok;
2404 char *propstok;
2405 asr_conf_entries_t *el;
2406 asr_conf_entries_t *ptr;
2407
2408 if (fname == NULL)
2409 return (list);
2410
2411 fp = fopen(fname, "r");
2412 if (fp == NULL)
2413 return (list);
2414
2415 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) {
2416 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n'))
2417 continue;
2418
2419 nametok = strtok(lbuf, " \t\n");
2420 if (nametok == NULL)
2421 continue;
2422
2423 classtok = strtok(NULL, " \t\n");
2424 if (classtok == NULL)
2425 continue;
2426
2427 statustok = strtok(NULL, " \t\n");
2428 if (statustok == NULL)
2429 continue;
2430
2431 addresstok = strtok(NULL, " \t\n");
2432 if (addresstok == NULL)
2433 continue;
2434
2435 /*
2436 * props are optional
2437 */
2438 propstok = strtok(NULL, " \t\n");
2439
2440 el = malloc(sizeof (asr_conf_entries_t));
2441 if (el == NULL)
2442 break;
2443 el->name = strdup(nametok);
2444 el->piclclass = strdup(classtok);
2445 el->status = strdup(statustok);
2446 el->address = strdup(addresstok);
2447 if (propstok != NULL)
2448 el->props = strdup(propstok);
2449 else
2450 el->props = NULL;
2451 if ((el->name == NULL) || (el->piclclass == NULL) ||
2452 (el->address == NULL) || (el->status == NULL)) {
2453 if (el->name)
2454 free(el->name);
2455 if (el->address)
2456 free(el->address);
2457 if (el->status)
2458 free(el->status);
2459 if (el->piclclass)
2460 free(el->piclclass);
2461 if (el->props)
2462 free(el->props);
2463 free(el);
2464 break;
2465 }
2466 el->next = NULL;
2467
2468 /*
2469 * Add it to the end of list
2470 */
2471 if (list == NULL)
2472 list = el;
2473 else {
2474 ptr = list;
2475 while (ptr->next != NULL)
2476 ptr = ptr->next;
2477 ptr->next = el;
2478 }
2479
2480 }
2481 (void) fclose(fp);
2482 return (list);
2483 }
2484
2485 /*
2486 * Process the asr conf file
2487 */
2488 static void
2489 process_asrtree_conf_file(void)
2490 {
2491 char nmbuf[SYS_NMLN];
2492 char pname[PATH_MAX];
2493
2494 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2495 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2496 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX);
2497 conf_name_asr_map = read_asr_conf_file(pname,
2498 conf_name_asr_map);
2499 }
2500
2501 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2502 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2503 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX);
2504 conf_name_asr_map = read_asr_conf_file(pname,
2505 conf_name_asr_map);
2506 }
2507
2508 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
2509 ASRTREE_CONFFILE_NAME);
2510 conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map);
2511 }
2512
2513 /*
2514 * This function reads the export file list from ASR
2515 */
2516 static int
2517 get_asr_export_list(char **exportlist, int *exportlistlen)
2518 {
2519 struct openpromio oppbuf;
2520 struct openpromio *opp = &oppbuf;
2521 int d;
2522 int listsize;
2523
2524 d = open("/dev/openprom", O_RDWR);
2525 if (d < 0)
2526 return (0);
2527
2528 if (ioctl(d, OPROMEXPORTLEN, opp) == -1) {
2529 (void) close(d);
2530 return (0);
2531 }
2532 listsize = opp->oprom_size;
2533 opp = (struct openpromio *)malloc(sizeof (struct openpromio) +
2534 listsize);
2535 if (opp == NULL) {
2536 (void) close(d);
2537 return (0);
2538 }
2539 (void) memset(opp, '\0', sizeof (struct openpromio) + listsize);
2540 opp->oprom_size = listsize;
2541 if (ioctl(d, OPROMEXPORT, opp) == -1) {
2542 free(opp);
2543 (void) close(d);
2544 return (0);
2545 }
2546 *exportlist = malloc(listsize);
2547 if (*exportlist == NULL) {
2548 free(opp);
2549 (void) close(d);
2550 return (0);
2551 }
2552 (void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size);
2553 *exportlistlen = opp->oprom_size;
2554 free(opp);
2555 (void) close(d);
2556 return (1);
2557 }
2558
2559 /*
2560 * Parses properties string, fills in triplet structure with first
2561 * type, name, val triplet and returns pointer to next property.
2562 * Returns NULL if no valid triplet found
2563 * CAUTION: drops \0 characters over separator characters: if you
2564 * want to parse the string twice, you'll have to take a copy.
2565 */
2566 static char *
2567 parse_props_string(char *props, asr_prop_triplet_t *triplet)
2568 {
2569 char *prop_name;
2570 char *prop_val;
2571 char *prop_next;
2572
2573 prop_name = strchr(props, '?');
2574 if (prop_name == NULL)
2575 return (NULL);
2576 *prop_name++ = '\0';
2577 prop_val = strchr(prop_name, '=');
2578 if (prop_val == NULL)
2579 return (NULL);
2580 *prop_val++ = '\0';
2581 triplet->proptype = props;
2582 triplet->propname = prop_name;
2583 triplet->propval = prop_val;
2584 prop_next = strchr(prop_val, ':');
2585 if (prop_next == NULL)
2586 return (prop_val - 1);
2587 *prop_next++ = '\0';
2588 return (prop_next);
2589 }
2590
2591 static int
2592 add_status_prop(picl_nodehdl_t chdh, char *status)
2593 {
2594 ptree_propinfo_t propinfo;
2595 picl_prophdl_t proph;
2596 int err;
2597
2598 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2599 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1,
2600 PICL_PROP_STATUS, NULL, NULL);
2601 if (err != PICL_SUCCESS)
2602 return (err);
2603 err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph);
2604 return (err);
2605 }
2606
2607 static void
2608 create_asr_node(char *parent, char *child, char *unitaddr, char *class,
2609 char *status, char *props)
2610 {
2611 char ptreepath[PATH_MAX];
2612 char nodename[PICL_PROPNAMELEN_MAX];
2613 char ua[MAX_UNIT_ADDRESS_LEN];
2614 char *props_copy = NULL;
2615 char *next;
2616 char *prop_string;
2617 boolean_t found = B_FALSE;
2618 picl_nodehdl_t nodeh;
2619 picl_nodehdl_t chdh;
2620 asr_prop_triplet_t triple;
2621 ptree_propinfo_t propinfo;
2622 picl_prophdl_t proph;
2623 int val;
2624 int err;
2625
2626 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
2627 (void) strlcat(ptreepath, parent, PATH_MAX);
2628
2629 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
2630 return;
2631 /*
2632 * see if the required child node already exists
2633 */
2634 for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
2635 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2636 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2637 sizeof (picl_nodehdl_t))) {
2638 if (err != PICL_SUCCESS)
2639 break;
2640 err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME,
2641 (void *)nodename, PICL_PROPNAMELEN_MAX);
2642 if (err != PICL_SUCCESS)
2643 break;
2644 if (strcmp(nodename, child) != 0)
2645 continue;
2646 /*
2647 * found a candidate child node
2648 */
2649 if (unitaddr) {
2650 /*
2651 * does it match the required unit address?
2652 */
2653 err = ptree_get_propval_by_name(chdh,
2654 PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua));
2655 if (err == PICL_PROPNOTFOUND)
2656 continue;
2657 if (err != PICL_SUCCESS)
2658 break;
2659 if (strcmp(unitaddr, ua) != 0)
2660 continue;
2661 }
2662 if (props == NULL) {
2663 next = "";
2664 } else if (props_copy == NULL) {
2665 props_copy = strdup(props);
2666 if (props_copy == NULL)
2667 return;
2668 next = props_copy;
2669 }
2670 while ((next = parse_props_string(next, &triple)) != NULL) {
2671 err = ptree_get_prop_by_name(chdh, triple.propname,
2672 &proph);
2673 if (err != PICL_SUCCESS)
2674 break;
2675 err = ptree_get_propinfo(proph, &propinfo);
2676 if (err != PICL_SUCCESS)
2677 break;
2678 err = PICL_FAILURE;
2679 switch (propinfo.piclinfo.type) {
2680 case PICL_PTYPE_INT:
2681 case PICL_PTYPE_UNSIGNED_INT:
2682 if (strcmp(triple.proptype, "I") != 0)
2683 break;
2684 err = ptree_get_propval(proph, (void *)&val,
2685 sizeof (val));
2686 if (err != PICL_SUCCESS)
2687 break;
2688 if (val != atoi(triple.propval))
2689 err = PICL_FAILURE;
2690 break;
2691 case PICL_PTYPE_CHARSTRING:
2692 if (strcmp(triple.proptype, "S") != 0)
2693 break;
2694 prop_string = malloc(propinfo.piclinfo.size);
2695 if (prop_string == NULL)
2696 break;
2697 err = ptree_get_propval(proph,
2698 (void *)prop_string,
2699 propinfo.piclinfo.size);
2700 if (err != PICL_SUCCESS) {
2701 free(prop_string);
2702 break;
2703 }
2704 if (strcmp(prop_string, triple.propval) != 0)
2705 err = PICL_FAILURE;
2706 free(prop_string);
2707 break;
2708 default:
2709 break;
2710 }
2711 if (err != PICL_SUCCESS) {
2712 break;
2713 }
2714 }
2715 if (next == NULL) {
2716 found = B_TRUE;
2717 break;
2718 }
2719 }
2720 if (props_copy)
2721 free(props_copy);
2722 if (found) {
2723 /*
2724 * does the pre-existing node have a status property?
2725 */
2726 err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS,
2727 ua, sizeof (ua));
2728 if (err == PICL_PROPNOTFOUND)
2729 (void) add_status_prop(chdh, status);
2730 if (err != PICL_SUCCESS)
2731 return;
2732 if ((strcmp(ua, ASR_DISABLED) == 0) ||
2733 (strcmp(ua, ASR_FAILED) == 0) ||
2734 ((strcmp(status, ASR_DISABLED) != 0) &&
2735 (strcmp(status, ASR_FAILED) != 0))) {
2736 return;
2737 }
2738 /*
2739 * more urgent status now, so replace existing value
2740 */
2741 err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph);
2742 if (err != PICL_SUCCESS)
2743 return;
2744 (void) ptree_delete_prop(proph);
2745 (void) ptree_destroy_prop(proph);
2746 err = add_status_prop(chdh, status);
2747 if (err != PICL_SUCCESS)
2748 return;
2749 return;
2750 }
2751
2752 /*
2753 * typical case, node needs adding together with a set of properties
2754 */
2755 if (ptree_create_and_add_node(nodeh, child, class, &chdh) ==
2756 PICL_SUCCESS) {
2757 (void) add_status_prop(chdh, status);
2758 if (unitaddr) {
2759 (void) ptree_init_propinfo(&propinfo,
2760 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
2761 PICL_READ, strlen(unitaddr) + 1,
2762 PICL_PROP_UNIT_ADDRESS, NULL, NULL);
2763 (void) ptree_create_and_add_prop(chdh, &propinfo,
2764 unitaddr, &proph);
2765 (void) strlcpy(ptreepath, parent, PATH_MAX);
2766 (void) strlcat(ptreepath, "/", PATH_MAX);
2767 (void) strlcat(ptreepath, child, PATH_MAX);
2768 (void) strlcat(ptreepath, "@", PATH_MAX);
2769 (void) strlcat(ptreepath, unitaddr, PATH_MAX);
2770 (void) ptree_init_propinfo(&propinfo,
2771 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
2772 PICL_READ, strlen(ptreepath) + 1,
2773 PICL_PROP_DEVFS_PATH, NULL, NULL);
2774 (void) ptree_create_and_add_prop(chdh, &propinfo,
2775 ptreepath, &proph);
2776 }
2777 next = props;
2778 while ((next = parse_props_string(next, &triple)) != NULL) {
2779 /*
2780 * only handle int and string properties for
2781 * simplicity
2782 */
2783 if (strcmp(triple.proptype, "I") == 0) {
2784 (void) ptree_init_propinfo(&propinfo,
2785 PTREE_PROPINFO_VERSION,
2786 PICL_PTYPE_INT, PICL_READ,
2787 sizeof (int), triple.propname, NULL, NULL);
2788 val = atoi(triple.propval);
2789 (void) ptree_create_and_add_prop(chdh,
2790 &propinfo, &val, &proph);
2791 } else {
2792 (void) ptree_init_propinfo(&propinfo,
2793 PTREE_PROPINFO_VERSION,
2794 PICL_PTYPE_CHARSTRING, PICL_READ,
2795 strlen(triple.propval) + 1,
2796 triple.propname, NULL, NULL);
2797 (void) ptree_create_and_add_prop(chdh,
2798 &propinfo, triple.propval, &proph);
2799 }
2800 }
2801 }
2802 }
2803
2804 static void
2805 add_asr_nodes()
2806 {
2807 char *asrexport;
2808 int asrexportlen;
2809 asr_conf_entries_t *c = NULL;
2810 int i;
2811 char *key;
2812 char *child;
2813 char *unitaddr;
2814 uint16_t count;
2815 int disabled;
2816
2817 if (get_asr_export_list(&asrexport, &asrexportlen) == 0)
2818 return;
2819 process_asrtree_conf_file();
2820 if (conf_name_asr_map == NULL)
2821 return;
2822 i = 0;
2823 while (i < asrexportlen) {
2824 key = &asrexport[i];
2825 i += strlen(key) + 1;
2826 if (i >= asrexportlen)
2827 break;
2828
2829 /*
2830 * next byte tells us whether failed by diags or manually
2831 * disabled
2832 */
2833 disabled = asrexport[i];
2834 i++;
2835 if (i >= asrexportlen)
2836 break;
2837
2838 /*
2839 * only type 1 supported
2840 */
2841 if (asrexport[i] != 1)
2842 break;
2843 i++;
2844 if (i >= asrexportlen)
2845 break;
2846
2847 /*
2848 * next two bytes give size of reason string
2849 */
2850 count = (asrexport[i] << 8) | asrexport[i + 1];
2851 i += count + 2;
2852 if (i > asrexportlen)
2853 break;
2854
2855 /*
2856 * now look for key in conf file info
2857 */
2858 c = conf_name_asr_map;
2859 while (c != NULL) {
2860 if (strcmp(key, c->name) == 0) {
2861 child = strrchr(c->address, '/');
2862 *child++ = '\0';
2863 unitaddr = strchr(child, '@');
2864 if (unitaddr)
2865 *unitaddr++ = '\0';
2866 if (strcmp(c->status, ASR_DISABLED) == 0) {
2867 create_asr_node(c->address, child,
2868 unitaddr, c->piclclass, disabled ?
2869 ASR_DISABLED : ASR_FAILED,
2870 c->props);
2871 } else {
2872 create_asr_node(c->address, child,
2873 unitaddr, c->piclclass, c->status,
2874 c->props);
2875 }
2876 }
2877 c = c->next;
2878 }
2879 }
2880
2881 free_asr_conf_entries(conf_name_asr_map);
2882 free(asrexport);
2883 }
2884
2885 /*
2886 * This function adds information to the /platform node
2887 */
2888 static int
2889 add_platform_info(picl_nodehdl_t plafh)
2890 {
2891 struct utsname uts_info;
2892 int err;
2893 ptree_propinfo_t propinfo;
2894 picl_prophdl_t proph;
2895
2896 if (uname(&uts_info) < 0)
2897 return (PICL_FAILURE);
2898
2899 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2900 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1,
2901 PICL_PROP_SYSNAME, NULL, NULL);
2902 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname,
2903 &proph);
2904 if (err != PICL_SUCCESS)
2905 return (err);
2906
2907 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2908 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1,
2909 PICL_PROP_NODENAME, NULL, NULL);
2910 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename,
2911 &proph);
2912 if (err != PICL_SUCCESS)
2913 return (err);
2914
2915 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2916 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1,
2917 PICL_PROP_RELEASE, NULL, NULL);
2918 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release,
2919 &proph);
2920 if (err != PICL_SUCCESS)
2921 return (err);
2922
2923 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2924 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1,
2925 PICL_PROP_VERSION, NULL, NULL);
2926 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version,
2927 &proph);
2928 if (err != PICL_SUCCESS)
2929 return (err);
2930
2931 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2932 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1,
2933 PICL_PROP_MACHINE, NULL, NULL);
2934 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine,
2935 &proph);
2936 return (err);
2937 }
2938
2939 /*
2940 * Get first 32-bit value from the reg property
2941 */
2942 static int
2943 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval)
2944 {
2945 int err;
2946 uint32_t *regbuf;
2947 picl_prophdl_t regh;
2948 ptree_propinfo_t pinfo;
2949
2950 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h);
2951 if (err != PICL_SUCCESS) /* no reg property */
2952 return (err);
2953 err = ptree_get_propinfo(regh, &pinfo);
2954 if (err != PICL_SUCCESS)
2955 return (err);
2956 if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */
2957 return (PICL_FAILURE);
2958 regbuf = alloca(pinfo.piclinfo.size);
2959 if (regbuf == NULL)
2960 return (PICL_FAILURE);
2961 err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size);
2962 if (err != PICL_SUCCESS)
2963 return (err);
2964 *regval = *regbuf; /* get first 32-bit value */
2965 return (PICL_SUCCESS);
2966 }
2967
2968 /*
2969 * Get device ID from the reg property
2970 */
2971 static int
2972 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id)
2973 {
2974 int err;
2975 uint32_t regval;
2976
2977 err = get_first_reg_word(nodeh, ®val);
2978 if (err != PICL_SUCCESS)
2979 return (err);
2980
2981 *dev_id = PCI_DEVICE_ID(regval);
2982 return (PICL_SUCCESS);
2983 }
2984
2985 /*
2986 * add Slot property for children of SBUS node
2987 */
2988 /* ARGSUSED */
2989 static int
2990 add_sbus_slots(picl_nodehdl_t pcih, void *args)
2991 {
2992 picl_nodehdl_t nodeh;
2993 uint32_t slot;
2994 int err;
2995 ptree_propinfo_t pinfo;
2996
2997 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
2998 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2999 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
3000 sizeof (picl_nodehdl_t))) {
3001 if (err != PICL_SUCCESS)
3002 return (err);
3003
3004 if (get_first_reg_word(nodeh, &slot) != 0)
3005 continue;
3006 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3007 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t),
3008 PICL_PROP_SLOT, NULL, NULL);
3009 (void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL);
3010 }
3011
3012 return (PICL_WALK_CONTINUE);
3013 }
3014
3015 /*
3016 * This function creates a Slot property for SBUS child nodes
3017 * which can be correlated with the slot they are plugged into
3018 * on the motherboard.
3019 */
3020 static int
3021 set_sbus_slot(picl_nodehdl_t plafh)
3022 {
3023 int err;
3024
3025 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL,
3026 add_sbus_slots);
3027
3028 return (err);
3029 }
3030
3031 /*
3032 * add DeviceID property for children of PCI/PCIEX node
3033 */
3034 /* ARGSUSED */
3035 static int
3036 add_pci_deviceids(picl_nodehdl_t pcih, void *args)
3037 {
3038 picl_nodehdl_t nodeh;
3039 uint32_t dev_id;
3040 int err;
3041 ptree_propinfo_t pinfo;
3042
3043 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
3044 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
3045 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
3046 sizeof (picl_nodehdl_t))) {
3047 if (err != PICL_SUCCESS)
3048 return (err);
3049
3050 if (get_device_id(nodeh, &dev_id) != 0)
3051 continue;
3052 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3053 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t),
3054 PICL_PROP_DEVICE_ID, NULL, NULL);
3055 (void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL);
3056 }
3057
3058 return (PICL_WALK_CONTINUE);
3059 }
3060
3061 /*
3062 * This function creates a DeviceID property for PCI/PCIEX child nodes
3063 * which can be correlated with the slot they are plugged into
3064 * on the motherboard.
3065 */
3066 static void
3067 set_pci_pciex_deviceid(picl_nodehdl_t plafh)
3068 {
3069 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL,
3070 add_pci_deviceids);
3071
3072 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, NULL,
3073 add_pci_deviceids);
3074 }
3075
3076 /*
3077 * Default UnitAddress encode function
3078 */
3079 static int
3080 encode_default_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3081 {
3082 int i, len;
3083
3084 /*
3085 * Encode UnitAddress as %a,%b,%c,...,%n
3086 */
3087 if (addrcells < 1)
3088 return (-1);
3089
3090 len = snprintf(buf, sz, "%x", *regprop);
3091 for (i = 1; i < addrcells && len < sz; i++)
3092 len += snprintf(&buf[len], sz-len, ",%x", regprop[i]);
3093
3094 return ((len >= sz) ? -1 : 0);
3095 }
3096
3097 /*
3098 * UnitAddress encode function where the last component is not printed
3099 * unless non-zero.
3100 */
3101 static int
3102 encode_optional_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3103 {
3104 int retval;
3105
3106 /*
3107 * Encode UnitAddress as %a,%b,%c,...,%n where the last component
3108 * is printed only if non-zero.
3109 */
3110 if (addrcells > 1 && regprop[addrcells-1] == 0)
3111 retval = encode_default_unitaddr(buf, sz, regprop, addrcells-1);
3112 else
3113 retval = encode_default_unitaddr(buf, sz, regprop, addrcells);
3114
3115 return (retval);
3116 }
3117
3118
3119 /*
3120 * UnitAddress encode function for SCSI class of devices
3121 */
3122 static int
3123 encode_scsi_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3124 {
3125 int len, retval;
3126
3127 /*
3128 * #address-cells Format
3129 * 2 second component printed only if non-zero
3130 *
3131 * 4 regprop: phys_hi phys_lo lun_hi lun_lo
3132 * UnitAddr: w<phys_hi><phys_lo>,<lun_lo>
3133 */
3134
3135 if (addrcells == 2) {
3136 retval = encode_optional_unitaddr(buf, sz, regprop, addrcells);
3137 } else if (addrcells == 4) {
3138 len = snprintf(buf, sz, "w%08x%08x,%x", regprop[0], regprop[1],
3139 regprop[3]);
3140 retval = (len >= sz) ? -1 : 0;
3141 } else
3142 retval = -1;
3143
3144 return (retval);
3145 }
3146
3147 /*
3148 * UnitAddress encode function for UPA devices
3149 */
3150 static int
3151 encode_upa_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3152 {
3153 int len;
3154
3155 if (addrcells != 2)
3156 return (-1);
3157
3158 len = snprintf(buf, sz, "%x,%x", (regprop[0]/2)&0x1f, regprop[1]);
3159 return ((len >= sz) ? -1 : 0);
3160 }
3161
3162 /*
3163 * UnitAddress encode function for GPTWO, JBUS devices
3164 */
3165 static int
3166 encode_gptwo_jbus_unitaddr(char *buf, int sz, uint32_t *regprop,
3167 uint_t addrcells)
3168 {
3169 uint32_t hi, lo;
3170 int len, id, off;
3171
3172 if (addrcells != 2)
3173 return (-1);
3174
3175 hi = regprop[0];
3176 lo = regprop[1];
3177
3178 if (hi & 0x400) {
3179 id = ((hi & 0x1) << 9) | (lo >> 23); /* agent id */
3180 off = lo & 0x7fffff; /* config offset */
3181 len = snprintf(buf, sz, "%x,%x", id, off);
3182 } else {
3183 len = snprintf(buf, sz, "m%x,%x", hi, lo);
3184 }
3185 return ((len >= sz) ? -1 : 0);
3186 }
3187
3188 /*
3189 * UnitAddress encode function for PCI devices
3190 */
3191 static int
3192 encode_pci_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3193 {
3194 typedef struct {
3195 uint32_t n:1, /* relocatable */
3196 p:1, /* prefetchable */
3197 t:1, /* address region aliases */
3198 zero:3, /* must be zero */
3199 ss:2, /* address space type */
3200 bus:8, /* bus number */
3201 dev:5, /* device number */
3202 fn:3, /* function number */
3203 reg:8; /* register number */
3204 uint32_t phys_hi; /* high physical address */
3205 uint32_t phys_lo; /* low physical address */
3206 } pci_addrcell_t;
3207
3208 pci_addrcell_t *p;
3209 int len;
3210
3211 if (addrcells != 3)
3212 return (-1);
3213
3214 p = (pci_addrcell_t *)regprop;
3215 switch (p->ss) {
3216 case 0: /* Config */
3217 if (p->fn)
3218 len = snprintf(buf, sz, "%x,%x", p->dev, p->fn);
3219 else
3220 len = snprintf(buf, sz, "%x", p->dev);
3221 break;
3222 case 1: /* IO */
3223 len = snprintf(buf, sz, "i%x,%x,%x,%x", p->dev, p->fn, p->reg,
3224 p->phys_lo);
3225 break;
3226 case 2: /* Mem32 */
3227 len = snprintf(buf, sz, "m%x,%x,%x,%x", p->dev, p->fn, p->reg,
3228 p->phys_lo);
3229 break;
3230 case 3: /* Mem64 */
3231 len = snprintf(buf, sz, "x%x,%x,%x,%x%08x", p->dev, p->fn,
3232 p->reg, p->phys_hi, p->phys_lo);
3233 break;
3234 }
3235 return ((len >= sz) ? -1 : 0);
3236 }
3237
3238 /*
3239 * Get #address-cells property value
3240 */
3241 static uint_t
3242 get_addrcells_prop(picl_nodehdl_t nodeh)
3243 {
3244 int len, err;
3245 uint32_t addrcells;
3246 ptree_propinfo_t pinfo;
3247 picl_prophdl_t proph;
3248
3249 /*
3250 * Get #address-cells property. If not present, use default value.
3251 */
3252 err = ptree_get_prop_by_name(nodeh, OBP_PROP_ADDRESS_CELLS, &proph);
3253 if (err == PICL_SUCCESS)
3254 err = ptree_get_propinfo(proph, &pinfo);
3255
3256 len = pinfo.piclinfo.size;
3257 if (err == PICL_SUCCESS && len >= sizeof (uint8_t) &&
3258 len <= sizeof (addrcells)) {
3259 err = ptree_get_propval(proph, &addrcells, len);
3260 if (err == PICL_SUCCESS) {
3261 if (len == sizeof (uint8_t))
3262 addrcells = *(uint8_t *)&addrcells;
3263 else if (len == sizeof (uint16_t))
3264 addrcells = *(uint16_t *)&addrcells;
3265 } else
3266 addrcells = DEFAULT_ADDRESS_CELLS;
3267 } else
3268 addrcells = DEFAULT_ADDRESS_CELLS;
3269
3270 return (addrcells);
3271 }
3272
3273 /*
3274 * Get UnitAddress mapping entry for a node
3275 */
3276 static unitaddr_map_t *
3277 get_unitaddr_mapping(picl_nodehdl_t nodeh)
3278 {
3279 int err;
3280 unitaddr_map_t *uamap;
3281 char clname[PICL_CLASSNAMELEN_MAX];
3282
3283 /*
3284 * Get my classname and locate a function to translate "reg" prop
3285 * into "UnitAddress" prop for my children.
3286 */
3287 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, clname,
3288 sizeof (clname));
3289 if (err != PICL_SUCCESS)
3290 (void) strcpy(clname, ""); /* NULL class name */
3291
3292 for (uamap = &unitaddr_map_table[0]; uamap->class != NULL; uamap++)
3293 if (strcmp(clname, uamap->class) == 0)
3294 break;
3295
3296 return (uamap);
3297 }
3298
3299 /*
3300 * Add UnitAddress property to the specified node
3301 */
3302 static int
3303 add_unitaddr_prop(picl_nodehdl_t nodeh, unitaddr_map_t *uamap, uint_t addrcells)
3304 {
3305 int regproplen, err;
3306 uint32_t *regbuf;
3307 picl_prophdl_t regh;
3308 ptree_propinfo_t pinfo;
3309 char unitaddr[MAX_UNIT_ADDRESS_LEN];
3310
3311 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h);
3312 if (err != PICL_SUCCESS)
3313 return (err);
3314
3315 err = ptree_get_propinfo(regh, &pinfo);
3316 if (err != PICL_SUCCESS)
3317 return (PICL_FAILURE);
3318
3319 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t)))
3320 return (PICL_FAILURE);
3321
3322 regproplen = pinfo.piclinfo.size;
3323 regbuf = alloca(regproplen);
3324 if (regbuf == NULL)
3325 return (PICL_FAILURE);
3326
3327 err = ptree_get_propval(regh, regbuf, regproplen);
3328 if (err != PICL_SUCCESS || uamap->func == NULL ||
3329 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) ||
3330 (uamap->func)(unitaddr, sizeof (unitaddr), regbuf,
3331 addrcells) != 0) {
3332 return (PICL_FAILURE);
3333 }
3334
3335 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3336 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(unitaddr)+1,
3337 PICL_PROP_UNIT_ADDRESS, NULL, NULL);
3338 if (err == PICL_SUCCESS)
3339 err = ptree_create_and_add_prop(nodeh, &pinfo, unitaddr, NULL);
3340
3341 return (err);
3342 }
3343
3344 /*
3345 * work out UnitAddress property of the specified node
3346 */
3347 static int
3348 get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, char *unitaddr,
3349 size_t ualen)
3350 {
3351 int regproplen, err;
3352 uint32_t *regbuf;
3353 picl_prophdl_t regh;
3354 ptree_propinfo_t pinfo;
3355 unitaddr_map_t *uamap;
3356 uint32_t addrcells;
3357
3358 addrcells = get_addrcells_prop(parh);
3359 uamap = get_unitaddr_mapping(parh);
3360
3361 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h);
3362 if (err != PICL_SUCCESS)
3363 return (err);
3364
3365 err = ptree_get_propinfo(regh, &pinfo);
3366 if (err != PICL_SUCCESS)
3367 return (err);
3368
3369 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t)))
3370 return (PICL_FAILURE);
3371
3372 regproplen = pinfo.piclinfo.size;
3373 regbuf = alloca(regproplen);
3374 if (regbuf == NULL)
3375 return (PICL_FAILURE);
3376
3377 err = ptree_get_propval(regh, regbuf, regproplen);
3378 if (err != PICL_SUCCESS || uamap->func == NULL ||
3379 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) ||
3380 (uamap->func)(unitaddr, ualen, regbuf, addrcells) != 0) {
3381 return (PICL_FAILURE);
3382 }
3383 return (PICL_SUCCESS);
3384 }
3385
3386 /*
3387 * Add UnitAddress property to all children of the specified node
3388 */
3389 static int
3390 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh)
3391 {
3392 int err;
3393 picl_nodehdl_t chdh;
3394 unitaddr_map_t *uamap;
3395 uint32_t addrcells;
3396
3397 /*
3398 * Get #address-cells and unit address mapping entry for my
3399 * node's class
3400 */
3401 addrcells = get_addrcells_prop(nodeh);
3402 uamap = get_unitaddr_mapping(nodeh);
3403
3404 /*
3405 * Add UnitAddress property to my children and their subtree
3406 */
3407 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
3408 sizeof (picl_nodehdl_t));
3409
3410 while (err == PICL_SUCCESS) {
3411 (void) add_unitaddr_prop(chdh, uamap, addrcells);
3412 (void) add_unitaddr_prop_to_subtree(chdh);
3413
3414 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3415 sizeof (picl_nodehdl_t));
3416 }
3417
3418 return (PICL_SUCCESS);
3419 }
3420
3421 static int
3422 update_memory_size_prop(picl_nodehdl_t plafh)
3423 {
3424 picl_nodehdl_t memh;
3425 picl_prophdl_t proph;
3426 ptree_propinfo_t pinfo;
3427 int err, nspecs, snum, pval;
3428 char *regbuf;
3429 memspecs_t *mspecs;
3430 uint64_t memsize;
3431
3432 /*
3433 * check if the #size-cells of the platform node is 2
3434 */
3435 err = ptree_get_propval_by_name(plafh, OBP_PROP_SIZE_CELLS, &pval,
3436 sizeof (pval));
3437
3438 if (err == PICL_PROPNOTFOUND)
3439 pval = SUPPORTED_NUM_CELL_SIZE;
3440 else if (err != PICL_SUCCESS)
3441 return (err);
3442
3443 /*
3444 * don't know how to handle other vals
3445 */
3446 if (pval != SUPPORTED_NUM_CELL_SIZE)
3447 return (PICL_FAILURE);
3448
3449 err = ptree_get_node_by_path(MEMORY_PATH, &memh);
3450 if (err != PICL_SUCCESS)
3451 return (err);
3452
3453 /*
3454 * Get the REG property to calculate the size of memory
3455 */
3456 err = ptree_get_prop_by_name(memh, OBP_REG, &proph);
3457 if (err != PICL_SUCCESS)
3458 return (err);
3459
3460 err = ptree_get_propinfo(proph, &pinfo);
3461 if (err != PICL_SUCCESS)
3462 return (err);
3463
3464 regbuf = alloca(pinfo.piclinfo.size);
3465 if (regbuf == NULL)
3466 return (PICL_FAILURE);
3467
3468 err = ptree_get_propval(proph, regbuf, pinfo.piclinfo.size);
3469 if (err != PICL_SUCCESS)
3470 return (err);
3471
3472 mspecs = (memspecs_t *)regbuf;
3473 nspecs = pinfo.piclinfo.size / sizeof (memspecs_t);
3474
3475 memsize = 0;
3476 for (snum = 0; snum < nspecs; ++snum)
3477 memsize += mspecs[snum].size;
3478
3479 err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph);
3480 if (err == PICL_SUCCESS) {
3481 err = ptree_update_propval(proph, &memsize, sizeof (memsize));
3482 return (err);
3483 }
3484
3485 /*
3486 * Add the size property
3487 */
3488 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3489 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize),
3490 PICL_PROP_SIZE, NULL, NULL);
3491 err = ptree_create_and_add_prop(memh, &pinfo, &memsize, NULL);
3492 return (err);
3493 }
3494
3495 /*
3496 * This function is executed as part of .init when the plugin is
3497 * dlopen()ed
3498 */
3499 static void
3500 picldevtree_register(void)
3501 {
3502 if (getenv(SUNW_PICLDEVTREE_PLUGIN_DEBUG))
3503 picldevtree_debug = 1;
3504 (void) picld_plugin_register(&my_reg_info);
3505 }
3506
3507 /*
3508 * This function is the init entry point of the plugin.
3509 * It initializes the /platform tree based on libdevinfo
3510 */
3511 static void
3512 picldevtree_init(void)
3513 {
3514 picl_nodehdl_t rhdl;
3515 int err;
3516 struct utsname utsname;
3517 picl_nodehdl_t plafh;
3518
3519 if (uname(&utsname) < 0)
3520 return;
3521
3522 (void) strcpy(mach_name, utsname.machine);
3523
3524 if (strcmp(mach_name, "sun4u") == 0) {
3525 builtin_map_ptr = sun4u_map;
3526 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
3527 } else if (strcmp(mach_name, "sun4v") == 0) {
3528 builtin_map_ptr = sun4u_map;
3529 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
3530 } else if (strcmp(mach_name, "i86pc") == 0) {
3531 builtin_map_ptr = i86pc_map;
3532 builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t);
3533 } else {
3534 builtin_map_ptr = NULL;
3535 builtin_map_size = 0;
3536 }
3537
3538 err = ptree_get_root(&rhdl);
3539 if (err != PICL_SUCCESS) {
3540 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED);
3541 return;
3542 }
3543
3544 process_devtree_conf_file();
3545
3546 if (libdevinfo_init(rhdl) != PICL_SUCCESS) {
3547 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED);
3548 return;
3549 }
3550
3551 err = ptree_get_node_by_path(PLATFORM_PATH, &plafh);
3552 if (err != PICL_SUCCESS)
3553 return;
3554
3555 (void) add_unitaddr_prop_to_subtree(plafh);
3556
3557 add_asr_nodes();
3558
3559 (void) update_memory_size_prop(plafh);
3560
3561 (void) setup_cpus(plafh);
3562
3563 (void) add_ffb_config_info(plafh);
3564
3565 (void) add_platform_info(plafh);
3566
3567 set_pci_pciex_deviceid(plafh);
3568
3569 (void) set_sbus_slot(plafh);
3570
3571 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
3572 picldevtree_evhandler, NULL);
3573 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
3574 picldevtree_evhandler, NULL);
3575 (void) ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE,
3576 picldevtree_evhandler, NULL);
3577 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3578 picldevtree_evhandler, NULL);
3579 }
3580
3581 /*
3582 * This function is the fini entry point of the plugin
3583 */
3584 static void
3585 picldevtree_fini(void)
3586 {
3587 /* First unregister the event handlers */
3588 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
3589 picldevtree_evhandler, NULL);
3590 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
3591 picldevtree_evhandler, NULL);
3592 (void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE,
3593 picldevtree_evhandler, NULL);
3594 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3595 picldevtree_evhandler, NULL);
3596
3597 conf_name_class_map = free_conf_entries(conf_name_class_map);
3598 }
3599
3600 /*
3601 * This function is the event handler of this plug-in.
3602 *
3603 * It processes the following events:
3604 *
3605 * PICLEVENT_SYSEVENT_DEVICE_ADDED
3606 * PICLEVENT_SYSEVENT_DEVICE_REMOVED
3607 * PICLEVENT_CPU_STATE_CHANGE
3608 * PICLEVENT_DR_AP_STATE_CHANGE
3609 */
3610 /* ARGSUSED */
3611 static void
3612 picldevtree_evhandler(const char *ename, const void *earg, size_t size,
3613 void *cookie)
3614 {
3615 char *devfs_path;
3616 char ptreepath[PATH_MAX];
3617 char dipath[PATH_MAX];
3618 picl_nodehdl_t plafh;
3619 picl_nodehdl_t nodeh;
3620 nvlist_t *nvlp;
3621
3622 if ((earg == NULL) ||
3623 (ptree_get_node_by_path(PLATFORM_PATH, &plafh) != PICL_SUCCESS))
3624 return;
3625
3626 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0) {
3627 (void) setup_cpus(plafh);
3628 if (picldevtree_debug > 1)
3629 syslog(LOG_INFO, "picldevtree: event handler done\n");
3630 return;
3631 }
3632
3633 nvlp = NULL;
3634 if (nvlist_unpack((char *)earg, size, &nvlp, NULL) ||
3635 nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &devfs_path) ||
3636 strlen(devfs_path) > (PATH_MAX - sizeof (PLATFORM_PATH))) {
3637 syslog(LOG_INFO, PICL_EVENT_DROPPED, ename);
3638 nvlist_free(nvlp);
3639 return;
3640 }
3641
3642 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
3643 (void) strlcat(ptreepath, devfs_path, PATH_MAX);
3644 (void) strlcpy(dipath, devfs_path, PATH_MAX);
3645 nvlist_free(nvlp);
3646
3647 if (picldevtree_debug)
3648 syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s "
3649 "ptreepath:%s\n", ename, ptreepath);
3650
3651 if (strcmp(ename, PICLEVENT_CPU_STATE_CHANGE) == 0) {
3652 goto done;
3653 }
3654 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) {
3655 di_node_t devnode;
3656 char *strp;
3657 picl_nodehdl_t parh;
3658 char nodeclass[PICL_CLASSNAMELEN_MAX];
3659 char *nodename;
3660 int err;
3661
3662 /* If the node already exist, then nothing else to do here */
3663 if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS)
3664 return;
3665
3666 /* Skip if unable to find parent PICL node handle */
3667 parh = plafh;
3668 if (((strp = strrchr(ptreepath, '/')) != NULL) &&
3669 (strp != strchr(ptreepath, '/'))) {
3670 *strp = '\0';
3671 if (ptree_get_node_by_path(ptreepath, &parh) !=
3672 PICL_SUCCESS)
3673 return;
3674 }
3675
3676 /*
3677 * If parent is the root node
3678 */
3679 if (parh == plafh) {
3680 ph = di_prom_init();
3681 devnode = di_init(dipath, DINFOCPYALL);
3682 if (devnode == DI_NODE_NIL) {
3683 if (ph != NULL) {
3684 di_prom_fini(ph);
3685 ph = NULL;
3686 }
3687 return;
3688 }
3689 nodename = di_node_name(devnode);
3690 if (nodename == NULL) {
3691 di_fini(devnode);
3692 if (ph != NULL) {
3693 di_prom_fini(ph);
3694 ph = NULL;
3695 }
3696 return;
3697 }
3698
3699 err = get_node_class(nodeclass, devnode, nodename);
3700 if (err < 0) {
3701 di_fini(devnode);
3702 if (ph != NULL) {
3703 di_prom_fini(ph);
3704 ph = NULL;
3705 }
3706 return;
3707 }
3708 err = construct_devtype_node(plafh, nodename,
3709 nodeclass, devnode, &nodeh);
3710 if (err != PICL_SUCCESS) {
3711 di_fini(devnode);
3712 if (ph != NULL) {
3713 di_prom_fini(ph);
3714 ph = NULL;
3715 }
3716 return;
3717 }
3718 (void) update_subtree(nodeh, devnode);
3719 (void) add_unitaddr_prop_to_subtree(nodeh);
3720 if (ph != NULL) {
3721 di_prom_fini(ph);
3722 ph = NULL;
3723 }
3724 di_fini(devnode);
3725 goto done;
3726 }
3727
3728 /* kludge ... try without bus-addr first */
3729 if ((strp = strrchr(dipath, '@')) != NULL) {
3730 char *p;
3731
3732 p = strrchr(dipath, '/');
3733 if (p != NULL && strp > p) {
3734 *strp = '\0';
3735 devnode = di_init(dipath, DINFOCPYALL);
3736 if (devnode != DI_NODE_NIL)
3737 di_fini(devnode);
3738 *strp = '@';
3739 }
3740 }
3741 /* Get parent devnode */
3742 if ((strp = strrchr(dipath, '/')) != NULL)
3743 *++strp = '\0';
3744 devnode = di_init(dipath, DINFOCPYALL);
3745 if (devnode == DI_NODE_NIL)
3746 return;
3747 ph = di_prom_init();
3748 (void) update_subtree(parh, devnode);
3749 (void) add_unitaddr_prop_to_subtree(parh);
3750 if (ph) {
3751 di_prom_fini(ph);
3752 ph = NULL;
3753 }
3754 di_fini(devnode);
3755 } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) {
3756 char delclass[PICL_CLASSNAMELEN_MAX];
3757 char *strp;
3758
3759 /*
3760 * if final element of path doesn't have a unit address
3761 * then it is not uniquely identifiable - cannot remove
3762 */
3763 if (((strp = strrchr(ptreepath, '/')) != NULL) &&
3764 strchr(strp, '@') == NULL)
3765 return;
3766
3767 /* skip if can't find the node */
3768 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
3769 return;
3770
3771 if (ptree_delete_node(nodeh) != PICL_SUCCESS)
3772 return;
3773
3774 if (picldevtree_debug)
3775 syslog(LOG_INFO,
3776 "picldevtree: deleted node nodeh:%llx\n", nodeh);
3777 if ((ptree_get_propval_by_name(nodeh,
3778 PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) ==
3779 PICL_SUCCESS) && IS_MC(delclass)) {
3780 if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) !=
3781 PICL_SUCCESS)
3782 syslog(LOG_WARNING, PICL_EVENT_DROPPED,
3783 PICLEVENT_MC_REMOVED);
3784 } else
3785 (void) ptree_destroy_node(nodeh);
3786 }
3787 done:
3788 (void) setup_cpus(plafh);
3789 (void) add_ffb_config_info(plafh);
3790 set_pci_pciex_deviceid(plafh);
3791 (void) set_sbus_slot(plafh);
3792 if (picldevtree_debug > 1)
3793 syslog(LOG_INFO, "picldevtree: event handler done\n");
3794 }