xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.c (revision b02637af6dc592eb1f43cb4c74f06268648dbd2d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Sun4v Platform specific functions.
28  *
29  * 	called when :
30  *      machine_type ==  ontario
31  *
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <kstat.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <assert.h>
43 #include <libintl.h>
44 #include <note.h>
45 #include <sys/systeminfo.h>
46 #include <sys/openpromio.h>
47 #include <sys/sysmacros.h>
48 #include <picl.h>
49 #include "picldefs.h"
50 #include <pdevinfo.h>
51 #include <display.h>
52 #include <display_sun4v.h>
53 #include <libprtdiag.h>
54 #include "ontario.h"
55 #include "erie.h"
56 #include "pelton.h"
57 #include "stpaul.h"
58 #include "huron.h"
59 #include "glendale_common.h"
60 #include "turgo.h"
61 
62 #if !defined(TEXT_DOMAIN)
63 #define	TEXT_DOMAIN	"SYS_TEST"
64 #endif
65 
66 /*
67  * these functions will overlay the symbol table of libprtdiag
68  * at runtime
69  */
70 void sun4v_display_pci(picl_nodehdl_t plafh);
71 void sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh);
72 
73 
74 /* local functions */
75 static void sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh);
76 static int ontario_pci_callback(picl_nodehdl_t pcih, void *args);
77 static int ontario_get_first_compatible_value(picl_nodehdl_t nodeh,
78     char **outbuf);
79 static int64_t ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name,
80     int *ret);
81 
82 static void
83 get_bus_type(char *path, struct io_card *card)
84 {
85 	if (strncmp(path, PCIX_SLOT0, PCIX_COMP_NUM) == 0) {
86 		(void) strcpy(card->bus_type, "PCIX");
87 	} else {
88 		(void) strcpy(card->bus_type, "PCIE");
89 	}
90 }
91 
92 static void
93 get_slot_number(picl_nodehdl_t nodeh, char *path, struct io_card *card)
94 {
95 	if (strncmp(path, PCIE_SLOT0, PCIE_COMP_NUM) == 0) {
96 		(void) strcpy(card->slot_str, "0");
97 		card->slot = 0;
98 	} else if (strncmp(path, PCIE_SLOT1, PCIE_COMP_NUM) == 0) {
99 		(void) strcpy(card->slot_str, "1");
100 		card->slot = 1;
101 	} else if (strncmp(path, PCIE_SLOT2, PCIE_COMP_NUM) == 0) {
102 		(void) strcpy(card->slot_str, "2");
103 		card->slot = 2;
104 	} else if ((strncmp(path, PCIX_SLOT1, strlen(PCIX_SLOT1)) == 0) ||
105 	    (strncmp(path, PCIX_SLOT0, strlen(PCIX_SLOT0)) == 0)) {
106 		char	ua[MAXSTRLEN];
107 		int	err;
108 
109 		(void) strcpy(card->slot_str, "PCIX");
110 		card->slot = -1;
111 
112 		/*
113 		 * PCIX_SLOT0 and PCIX_SLOT1 are actually the same path so
114 		 * use the unit address to distinguish the slot number.
115 		 */
116 		err = picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS,
117 		    ua, sizeof (ua));
118 		if (err == PICL_SUCCESS) {
119 			if (ua[0] == '2') {
120 				card->slot = 0;
121 				(void) strcpy(card->slot_str, "0");
122 			} else if (ua[0] == '1') {
123 				card->slot = 1;
124 				(void) strcpy(card->slot_str, "1");
125 			}
126 		}
127 	} else {
128 		(void) strcpy(card->slot_str, IOBOARD);
129 		card->slot = -1;
130 	}
131 }
132 
133 static int
134 ontario_get_network_instance(char *path)
135 {
136 	if (strncmp(path, NETWORK_1_PATH, strlen(NETWORK_1_PATH)) == 0) {
137 		return (1);
138 	} else if (strncmp(path, NETWORK_3_PATH, strlen(NETWORK_3_PATH)) == 0) {
139 		return (3);
140 	} else if (strncmp(path, NETWORK_0_PATH, strlen(NETWORK_0_PATH)) == 0) {
141 		return (0);
142 	} else if (strncmp(path, NETWORK_2_PATH, strlen(NETWORK_2_PATH)) == 0) {
143 		return (2);
144 	} else {
145 		return (-1);
146 	}
147 }
148 /*
149  * add all io devices under pci in io list
150  */
151 /* ARGSUSED */
152 static int
153 ontario_pci_callback(picl_nodehdl_t pcih, void *args)
154 {
155 	int		err = PICL_SUCCESS;
156 	picl_nodehdl_t	nodeh;
157 	char		path[MAXSTRLEN];
158 	char		parent_path[MAXSTRLEN];
159 	char		piclclass[PICL_CLASSNAMELEN_MAX];
160 	char		name[MAXSTRLEN];
161 	char		model[MAXSTRLEN];
162 	char		*compatible;
163 	char		binding_name[MAXSTRLEN];
164 	struct io_card	pci_card;
165 	int32_t		instance;
166 
167 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
168 	    sizeof (parent_path));
169 	if (err != PICL_SUCCESS) {
170 		return (err);
171 	}
172 
173 	/* Walk through the children */
174 
175 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
176 	    sizeof (picl_nodehdl_t));
177 
178 	while (err == PICL_SUCCESS) {
179 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
180 		    piclclass, sizeof (piclclass));
181 		if (err !=  PICL_SUCCESS)
182 			return (err);
183 
184 		/*
185 		 * Skip PCI and PCIEX devices because they will be processed
186 		 * later in the picl tree walk.
187 		 */
188 		if ((strcmp(piclclass, "pci") == 0) ||
189 		    (strcmp(piclclass, "pciex") == 0)) {
190 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
191 			    &nodeh, sizeof (picl_nodehdl_t));
192 			continue;
193 		}
194 
195 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
196 		    path, sizeof (path));
197 		if (err != PICL_SUCCESS) {
198 			return (err);
199 		}
200 
201 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
202 
203 		get_bus_type(parent_path, &pci_card);
204 
205 		get_slot_number(nodeh, parent_path, &pci_card);
206 
207 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
208 		    sizeof (name));
209 		if (err == PICL_PROPNOTFOUND)
210 			(void) strcpy(name, "");
211 		else if (err != PICL_SUCCESS)
212 			return (err);
213 
214 		/* Figure NAC name */
215 		if ((strcmp(name, NETWORK) == 0) &&
216 		    (strcmp(pci_card.slot_str, IOBOARD) == 0)) {
217 			instance = ontario_get_network_instance(path);
218 
219 			(void) snprintf(pci_card.status,
220 			    sizeof (pci_card.status), "%s/%s%d", IOBOARD,
221 			    "NET", instance);
222 		} else {
223 			if (pci_card.slot != -1) {
224 				(void) snprintf(pci_card.status,
225 				    sizeof (pci_card.status), "%s/%s%d",
226 				    IOBOARD, pci_card.bus_type, pci_card.slot);
227 			} else {
228 				(void) snprintf(pci_card.status,
229 				    sizeof (pci_card.status), "%s/%s", IOBOARD,
230 				    pci_card.bus_type);
231 			}
232 		}
233 
234 		/*
235 		 * Get the name of this card. If binding_name is found,
236 		 * name will be <nodename>-<binding_name>
237 		 */
238 
239 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
240 		    &binding_name, sizeof (binding_name));
241 		if (err == PICL_PROPNOTFOUND) {
242 			/*
243 			 * if compatible prop is found, name will be
244 			 * <nodename>-<compatible>
245 			 */
246 			err = ontario_get_first_compatible_value(nodeh,
247 			    &compatible);
248 			if (err == PICL_SUCCESS) {
249 				(void) strlcat(name, "-", MAXSTRLEN);
250 				(void) strlcat(name, compatible, MAXSTRLEN);
251 				free(compatible);
252 			} else if (err != PICL_PROPNOTFOUND) {
253 				return (err);
254 			}
255 		} else if (err != PICL_SUCCESS) {
256 			return (err);
257 		} else if (strcmp(name, binding_name) != 0) {
258 			(void) strlcat(name, "-", MAXSTRLEN);
259 			(void) strlcat(name, binding_name, MAXSTRLEN);
260 		}
261 
262 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
263 
264 		/* Get the model of this card */
265 
266 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
267 		    &model, sizeof (model));
268 		if (err == PICL_PROPNOTFOUND)
269 			(void) strcpy(model, "");
270 		else if (err != PICL_SUCCESS)
271 			return (err);
272 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
273 
274 		/* Print NAC name */
275 		log_printf("%-11s", pci_card.status);
276 		/* Print IO Type */
277 		log_printf("%6s", pci_card.bus_type);
278 		/* Print Slot # */
279 		log_printf("%5s", pci_card.slot_str);
280 		/* Print Parent Path */
281 		log_printf("%46.45s", pci_card.notes);
282 		/* Printf Card Name */
283 		if (strlen(pci_card.name) > 25)
284 			log_printf("%25.24s+", pci_card.name);
285 		else
286 			log_printf("%26s", pci_card.name);
287 		/* Print Card Model */
288 		if (strlen(pci_card.model) > 10)
289 			log_printf("%10.9s+", pci_card.model);
290 		else
291 			log_printf("%11s", pci_card.model);
292 		log_printf("\n");
293 
294 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
295 		    sizeof (picl_nodehdl_t));
296 
297 	}
298 
299 	return (PICL_WALK_CONTINUE);
300 }
301 /*
302  * display_pci
303  * Display all the PCI IO cards on this board.
304  */
305 void
306 sun4v_display_pci(picl_nodehdl_t plafh)
307 {
308 	char    platbuf[MAXSTRLEN];
309 	char	*fmt = "%-11s %-5s %-4s %-45s %-25s %-10s";
310 	static int banner = FALSE; /* Have we printed the column headings? */
311 
312 	if (banner == FALSE) {
313 		log_printf("\n", 0);
314 		log_printf("=========================", 0);
315 		log_printf(dgettext(TEXT_DOMAIN, " IO Configuration "), 0);
316 		log_printf("=========================", 0);
317 		log_printf("\n", 0);
318 		log_printf("\n", 0);
319 		log_printf(fmt, "", "IO", "", "", "", "", 0);
320 		log_printf("\n", 0);
321 		log_printf(fmt, "Location", "Type", "Slot", "Path",
322 		    "Name", "Model", 0);
323 		log_printf("\n");
324 		log_printf(fmt, "-----------", "-----", "----",
325 		    "---------------------------------------------",
326 		    "-------------------------", "----------", 0);
327 		log_printf("\n");
328 		banner = TRUE;
329 	}
330 
331 	/* Get platform name, if that fails, use ontario name by default */
332 	if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) {
333 		(void) strcpy(platbuf, ONTARIO_PLATFORM);
334 	}
335 
336 	/*
337 	 * Call functions based on appropriate platform
338 	 */
339 	if ((strncmp(platbuf, ONTARIO_PLATFORM,
340 	    strlen(ONTARIO_PLATFORM)) == 0) ||
341 	    (strncmp(platbuf, ONTARIO_PLATFORM2,
342 	    strlen(ONTARIO_PLATFORM2)) == 0)) {
343 		(void) picl_walk_tree_by_class(plafh, "pciex",
344 		    "pciex", ontario_pci_callback);
345 		(void) picl_walk_tree_by_class(plafh, "pci",
346 		    "pci", ontario_pci_callback);
347 	} else if ((strncmp(platbuf, PELTON_PLATFORM,
348 	    strlen(PELTON_PLATFORM))) == 0) {
349 		(void) picl_walk_tree_by_class(plafh, "pciex",
350 		    "pciex", pelton_pci_callback);
351 		(void) picl_walk_tree_by_class(plafh, "pci",
352 		    "pci", pelton_pci_callback);
353 	} else if ((strncmp(platbuf, STPAUL_PLATFORM,
354 	    strlen(STPAUL_PLATFORM))) == 0) {
355 		(void) picl_walk_tree_by_class(plafh, "pciex",
356 		    "pciex", stpaul_pci_callback);
357 	} else if ((strncmp(platbuf, HURON_1U_PLATFORM,
358 	    strlen(HURON_1U_PLATFORM)) == 0) || (strncmp(platbuf,
359 	    HURON_2U_PLATFORM, strlen(HURON_2U_PLATFORM)) == 0)) {
360 			(void) picl_walk_tree_by_class(plafh, "sun4v",
361 			    "niu", huron_pci_callback);
362 			(void) picl_walk_tree_by_class(plafh, "pciex",
363 			    "pciex", huron_pci_callback);
364 	} else if ((strncmp(platbuf, GLENDALE_PLATFORM,
365 	    strlen(GLENDALE_PLATFORM))) == 0) {
366 		(void) picl_walk_tree_by_class(plafh, "sun4v",
367 		    "niu", glendale_pci_callback);
368 		(void) picl_walk_tree_by_class(plafh, "pciex",
369 		    "pciex", glendale_pci_callback);
370 	} else if (strncmp(platbuf, TURGO_PLATFORM,
371 	    strlen(TURGO_PLATFORM)) == 0) {
372 		(void) picl_walk_tree_by_class(plafh, "sun4v",
373 		    "niu", turgo_pci_callback);
374 		(void) picl_walk_tree_by_class(plafh, "pciex",
375 		    "pciex", turgo_pci_callback);
376 		(void) picl_walk_tree_by_class(plafh, "pci",
377 		    "pci", turgo_pci_callback);
378 	} else {
379 		(void) picl_walk_tree_by_class(plafh, "pciex", "pciex",
380 		    erie_pci_callback);
381 		(void) picl_walk_tree_by_class(plafh, "pci", "pci",
382 		    erie_pci_callback);
383 	}
384 }
385 
386 /*
387  * ----------------------------------------------------------------------------
388  */
389 
390 /* ARGSUSED */
391 void
392 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
393 {
394 	/* NOTE(ARGUNUSED(kstats)) */
395 	/*
396 	 * Now display the last powerfail time and the fatal hardware
397 	 * reset information. We do this under a couple of conditions.
398 	 * First if the user asks for it. The second is if the user
399 	 * told us to do logging, and we found a system failure.
400 	 */
401 	if (flag) {
402 		/*
403 		 * display time of latest powerfail. Not all systems
404 		 * have this capability. For those that do not, this
405 		 * is just a no-op.
406 		 */
407 		disp_powerfail(root);
408 
409 		/* platform_disp_prom_version(tree); */
410 		sun4v_display_hw_revisions(root, plafh);
411 	}
412 }
413 
414 /*
415  * local functions
416  */
417 /*
418  * add all io devices under pci in io list
419  */
420 /* ARGSUSED */
421 static int
422 ontario_hw_rev_callback(picl_nodehdl_t pcih, void *args)
423 {
424 	int		err = PICL_SUCCESS;
425 	char		path[MAXSTRLEN] = "";
426 	char		device_path[MAXSTRLEN];
427 	char		NAC[MAXSTRLEN];
428 	char		*compatible;
429 	int32_t		revision;
430 	int		device_found;
431 
432 	device_found = 0;
433 
434 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
435 	    sizeof (path));
436 	if (err != PICL_SUCCESS) {
437 		return (err);
438 	}
439 
440 	if ((strcmp(path, NETWORK_0_PATH) == 0) ||
441 	    (strcmp(path, NETWORK_1_PATH) == 0)) {
442 		device_found = 1;
443 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
444 		    0);
445 		revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
446 		    &err);
447 	}
448 
449 	if ((strcmp(path, NETWORK_2_PATH) == 0) ||
450 	    (strcmp(path, NETWORK_3_PATH) == 0)) {
451 		device_found = 1;
452 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
453 		    1);
454 		revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
455 		    &err);
456 	}
457 
458 	if ((strcmp(path, FIRE_PATH0) == 0) ||
459 	    (strcmp(path, FIRE_PATH1) == 0)) {
460 		device_found = 1;
461 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
462 		    "IO-BRIDGE");
463 		revision = ontario_get_int_propval(pcih, OBP_PROP_VERSION_NUM,
464 		    &err);
465 	}
466 
467 	if ((strcmp(path, PCIX_SLOT0) == 0) ||
468 	    (strcmp(path, PCIX_SLOT1) == 0)) {
469 		device_found = 1;
470 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
471 		    PCI_BRIDGE);
472 		revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
473 		    &err);
474 	}
475 
476 	if (strcmp(path, SWITCH_A_PATH) == 0) {
477 		device_found = 1;
478 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_A);
479 		revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
480 		    &err);
481 	}
482 
483 	if (strcmp(path, SWITCH_B_PATH) == 0) {
484 		device_found = 1;
485 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_B);
486 		revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
487 		    &err);
488 	}
489 
490 	if (strcmp(path, ONT_LSI_PATH) == 0) {
491 		device_found = 1;
492 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
493 		    SAS_SATA_HBA);
494 		revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
495 		    &err);
496 	}
497 	if (device_found == 1) {
498 		(void) strcpy(device_path, path);
499 		err = ontario_get_first_compatible_value(pcih, &compatible);
500 
501 		/* Print NAC name */
502 		log_printf("%-20s", NAC);
503 		/* Print Device Path */
504 		if (strlen(device_path) > 38)
505 			log_printf("%38.37s+", device_path);
506 		else
507 			log_printf("%39s", device_path);
508 		/* Print Compatible # */
509 		log_printf("%31s", compatible);
510 		free(compatible);
511 		/* Print Revision */
512 		log_printf("%6d", revision);
513 		log_printf("\n");
514 	}
515 
516 	return (PICL_WALK_CONTINUE);
517 }
518 
519 /*ARGSUSED*/
520 static void
521 sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh)
522 {
523 	Prom_node	*pnode;
524 	char		*value;
525 	char 		platbuf[MAXSTRLEN];
526 	char	*fmt = "%-20s %-45s %-30s %-9s";
527 
528 	log_printf(dgettext(TEXT_DOMAIN, "\n"
529 	    "========================= HW Revisions "
530 	    "=======================================\n\n"));
531 
532 	log_printf(dgettext(TEXT_DOMAIN,
533 	    "System PROM revisions:\n"
534 	    "----------------------\n"));
535 
536 	pnode = dev_find_node(root, "openprom");
537 	if (pnode != NULL) {
538 		value = (char *)get_prop_val(find_prop(pnode, "version"));
539 		log_printf(value);
540 	}
541 
542 	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
543 	    "IO ASIC revisions:\n"
544 	    "------------------\n"));
545 	log_printf(fmt, "Location", "Path", "Device", "Revision\n", 0);
546 	log_printf(fmt, "--------------------",
547 	    "---------------------------------------------",
548 	    "------------------------------",
549 	    "---------\n", 0);
550 
551 	/* Get platform name, if that fails, use ontario name by default */
552 	if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) {
553 		(void) strcpy(platbuf, ONTARIO_PLATFORM);
554 	}
555 
556 	/*
557 	 * Walk tree based on platform
558 	 */
559 	if ((strncmp(platbuf, ONTARIO_PLATFORM,
560 	    strlen(ONTARIO_PLATFORM))) == 0) {
561 		(void) picl_walk_tree_by_class(plafh, "pciex",
562 		    "pciex", ontario_hw_rev_callback);
563 		(void) picl_walk_tree_by_class(plafh, "pci",
564 		    "pci", ontario_hw_rev_callback);
565 		(void) picl_walk_tree_by_class(plafh, "network",
566 		    "network", ontario_hw_rev_callback);
567 		(void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
568 		    ontario_hw_rev_callback);
569 	} else if ((strncmp(platbuf, PELTON_PLATFORM,
570 	    strlen(PELTON_PLATFORM))) == 0) {
571 		(void) picl_walk_tree_by_class(plafh, "pciex",
572 		    "pciex", pelton_hw_rev_callback);
573 		(void) picl_walk_tree_by_class(plafh, "pci",
574 		    "pci", pelton_hw_rev_callback);
575 		(void) picl_walk_tree_by_class(plafh, "network",
576 		    "network", pelton_hw_rev_callback);
577 		(void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
578 		    pelton_hw_rev_callback);
579 	} else if ((strncmp(platbuf, STPAUL_PLATFORM,
580 	    strlen(STPAUL_PLATFORM))) == 0) {
581 		(void) picl_walk_tree_by_class(plafh, "pciex",
582 		    "pciex", stpaul_hw_rev_callback);
583 		(void) picl_walk_tree_by_class(plafh, "pci",
584 		    "pci", stpaul_hw_rev_callback);
585 		(void) picl_walk_tree_by_class(plafh, "network",
586 		    "network", stpaul_hw_rev_callback);
587 		(void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
588 		    stpaul_hw_rev_callback);
589 	} else if ((strncmp(platbuf, HURON_1U_PLATFORM,
590 	    strlen(HURON_1U_PLATFORM)) == 0) || (strncmp(platbuf,
591 	    HURON_2U_PLATFORM, strlen(HURON_2U_PLATFORM)) == 0)) {
592 		(void) picl_walk_tree_by_class(plafh, "pciex",
593 		    "pciex", huron_hw_rev_callback);
594 		(void) picl_walk_tree_by_class(plafh, "sun4v",
595 		    "niu", huron_hw_rev_callback);
596 		(void) picl_walk_tree_by_class(plafh, "network",
597 		    "network", huron_hw_rev_callback);
598 		(void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
599 		    huron_hw_rev_callback);
600 	} else if ((strncmp(platbuf, GLENDALE_PLATFORM,
601 	    strlen(GLENDALE_PLATFORM))) == 0) {
602 		(void) picl_walk_tree_by_class(plafh, "pciex",
603 		    "pciex", glendale_hw_rev_callback);
604 		(void) picl_walk_tree_by_class(plafh, "sun4v",
605 		    "niu", glendale_hw_rev_callback);
606 		(void) picl_walk_tree_by_class(plafh, "pci",
607 		    "pci", glendale_hw_rev_callback);
608 		(void) picl_walk_tree_by_class(plafh, "sun4v",
609 		    "pci", glendale_hw_rev_callback);
610 		(void) picl_walk_tree_by_class(plafh, "network",
611 		    "network", glendale_hw_rev_callback);
612 		(void) picl_walk_tree_by_class(plafh, "scsi-2",
613 		    "scsi-2", glendale_hw_rev_callback);
614 	} else if (strncmp(platbuf, TURGO_PLATFORM,
615 	    strlen(TURGO_PLATFORM)) == 0) {
616 		(void) picl_walk_tree_by_class(plafh, "pciex",
617 		    "pciex", turgo_hw_rev_callback);
618 		(void) picl_walk_tree_by_class(plafh, "sun4v",
619 		    "niu", turgo_hw_rev_callback);
620 		(void) picl_walk_tree_by_class(plafh, "network",
621 		    "network", turgo_hw_rev_callback);
622 		(void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
623 		    turgo_hw_rev_callback);
624 	} else {
625 		(void) picl_walk_tree_by_class(plafh, "pciex", "pciex",
626 		    erie_hw_rev_callback);
627 		(void) picl_walk_tree_by_class(plafh, "pci", "pci",
628 		    erie_hw_rev_callback);
629 		(void) picl_walk_tree_by_class(plafh, "network", "network",
630 		    erie_hw_rev_callback);
631 		(void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
632 		    erie_hw_rev_callback);
633 	}
634 }
635 
636 /*
637  * return the first compatible value
638  */
639 static int
640 ontario_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
641 {
642 	int		err;
643 	picl_prophdl_t	proph;
644 	picl_propinfo_t	pinfo;
645 	picl_prophdl_t	tblh;
646 	picl_prophdl_t	rowproph;
647 	char		*pval;
648 
649 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
650 	    &pinfo, &proph);
651 	if (err != PICL_SUCCESS)
652 		return (err);
653 
654 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
655 		pval = malloc(pinfo.size);
656 		if (pval == NULL)
657 			return (PICL_FAILURE);
658 		err = picl_get_propval(proph, pval, pinfo.size);
659 		if (err != PICL_SUCCESS) {
660 			free(pval);
661 			return (err);
662 		}
663 		*outbuf = pval;
664 		return (PICL_SUCCESS);
665 	}
666 
667 	if (pinfo.type != PICL_PTYPE_TABLE)
668 		return (PICL_FAILURE);
669 
670 	/* get first string from table */
671 	err = picl_get_propval(proph, &tblh, pinfo.size);
672 	if (err != PICL_SUCCESS)
673 		return (err);
674 
675 	err = picl_get_next_by_row(tblh, &rowproph);
676 	if (err != PICL_SUCCESS)
677 		return (err);
678 
679 	err = picl_get_propinfo(rowproph, &pinfo);
680 	if (err != PICL_SUCCESS)
681 		return (err);
682 
683 	pval = malloc(pinfo.size);
684 	if (pval == NULL)
685 		return (PICL_FAILURE);
686 
687 	err = picl_get_propval(rowproph, pval, pinfo.size);
688 	if (err != PICL_SUCCESS) {
689 		free(pval);
690 		return (err);
691 	}
692 
693 	*outbuf = pval;
694 	return (PICL_SUCCESS);
695 }
696 
697 static int64_t
698 ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
699 {
700 	int		err;
701 	picl_prophdl_t	proph;
702 	picl_propinfo_t	pinfo;
703 	int8_t		int8v;
704 	int16_t		int16v;
705 	int32_t		int32v;
706 	int64_t		int64v;
707 
708 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
709 	if (err != PICL_SUCCESS) {
710 		*ret = err;
711 		return (0);
712 	}
713 
714 	/*
715 	 * If it is not an int, uint or byte array prop, return failure
716 	 */
717 	if ((pinfo.type != PICL_PTYPE_INT) &&
718 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
719 	    (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
720 		*ret = PICL_FAILURE;
721 		return (0);
722 	}
723 
724 	switch (pinfo.size) {
725 	case sizeof (int8_t):
726 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
727 		*ret = err;
728 		return (int8v);
729 	case sizeof (int16_t):
730 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
731 		*ret = err;
732 		return (int16v);
733 	case sizeof (int32_t):
734 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
735 		*ret = err;
736 		return (int32v);
737 	case sizeof (int64_t):
738 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
739 		*ret = err;
740 		return (int64v);
741 	default:	/* not supported size */
742 		*ret = PICL_FAILURE;
743 		return (0);
744 	}
745 }
746