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