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