xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/monza/common/monza.c (revision ddb365bfc9e868ad24ccdcb0dc91af18b10df082)
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 ==  monza
31  *
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <kstat.h>
38 #include <fcntl.h>
39 #include <string.h>
40 #include <assert.h>
41 #include <libintl.h>
42 #include <note.h>
43 #include <sys/systeminfo.h>
44 #include <sys/openpromio.h>
45 #include <sys/sysmacros.h>
46 #include <picl.h>
47 #include "picldefs.h"
48 #include <pdevinfo.h>
49 #include <display.h>
50 #include <display_sun4v.h>
51 #include <libprtdiag.h>
52 #include "monza.h"
53 
54 #if !defined(TEXT_DOMAIN)
55 #define	TEXT_DOMAIN	"SYS_TEST"
56 #endif
57 
58 /*
59  * These functions will overlay the symbol table of libprtdiag
60  * at runtime
61  */
62 void sun4v_display_pci(picl_nodehdl_t plafh);
63 void sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh);
64 
65 
66 /*
67  * local functions
68  */
69 static void sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh);
70 static int monza_pci_callback(picl_nodehdl_t pcih, void *args);
71 static int monza_get_first_compatible_value(picl_nodehdl_t nodeh,
72     char **outbuf);
73 static int64_t monza_get_int_propval(picl_nodehdl_t modh, char *prop_name,
74     int *ret);
75 
76 static void
77 monza_get_bus_type(char *path, struct io_card *card)
78 {
79 	if (strcmp(path, MONZA_NIU) == 0) {
80 		(void) strcpy(card->bus_type, "NIU");
81 	} else {
82 		(void) strcpy(card->bus_type, "PCIE");
83 	}
84 }
85 
86 static void
87 monza_get_slot_number(char *path, struct io_card *card)
88 {
89 	if (strcmp(path, MONZA_N2_XAUI0) == 0) {
90 		(void) strcpy(card->slot_str, "0");
91 		card->slot = 0;
92 	} else if (strcmp(path, MONZA_N2_XAUI1) == 0) {
93 		(void) strcpy(card->slot_str, "1");
94 		card->slot = 1;
95 	} else {
96 		(void) strcpy(card->slot_str, MOTHERBOARD);
97 		card->slot = -1;
98 	}
99 }
100 
101 static int
102 monza_get_network_instance(char *path)
103 {
104 
105 	if (strncmp(path, MONZA_NETWORK_0, strlen(MONZA_NETWORK_0)) == 0) {
106 		return (0);
107 	} else if (strncmp(path, MONZA_NETWORK_1, strlen(MONZA_NETWORK_1))
108 	    == 0) {
109 		return (1);
110 	} else if (strncmp(path, MONZA_NETWORK_2, strlen(MONZA_NETWORK_2))
111 	    == 0) {
112 		return (2);
113 	} else if (strncmp(path, MONZA_ENET_2, strlen(MONZA_ENET_2))
114 	    == 0) {
115 		return (2);
116 	} else if (strncmp(path, MONZA_NETWORK_3, strlen(MONZA_NETWORK_3))
117 	    == 0) {
118 		return (3);
119 	} else if (strncmp(path, MONZA_ENET_3, strlen(MONZA_ENET_3))
120 	    == 0) {
121 		return (3);
122 	} else if (strncmp(path, MONZA_NETWORK_4, strlen(MONZA_NETWORK_4))
123 	    == 0) {
124 		return (4);
125 	} else if (strncmp(path, MONZA_NETWORK_5, strlen(MONZA_NETWORK_5))
126 	    == 0) {
127 		return (5);
128 	} else if (strncmp(path, MONZA_N2_XAUI0, strlen(MONZA_N2_XAUI0))
129 	    == 0) {
130 		return (0);
131 	} else if (strncmp(path, MONZA_N2_XAUI1, strlen(MONZA_N2_XAUI1))
132 	    == 0) {
133 		return (1);
134 	} else {
135 		return (-1);
136 	}
137 }
138 
139 /*
140  * add all io devices under pci in io list
141  */
142 /* ARGSUSED */
143 static int
144 monza_pci_callback(picl_nodehdl_t pcih, void *args)
145 {
146 	int		err = PICL_SUCCESS;
147 	picl_nodehdl_t	nodeh;
148 	char		path[MAXSTRLEN];
149 	char		parent_path[MAXSTRLEN];
150 	char		piclclass[PICL_CLASSNAMELEN_MAX];
151 	char		name[MAXSTRLEN];
152 	char		model[MAXSTRLEN];
153 	char		*compatible;
154 	char		binding_name[MAXSTRLEN];
155 	struct io_card	pci_card;
156 	int32_t		instance;
157 
158 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
159 	    sizeof (parent_path));
160 	if (err != PICL_SUCCESS) {
161 		return (err);
162 	}
163 
164 	/*
165 	 * Walk through the children
166 	 */
167 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
168 	    sizeof (picl_nodehdl_t));
169 
170 	while (err == PICL_SUCCESS) {
171 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
172 		    piclclass, sizeof (piclclass));
173 		if (err !=  PICL_SUCCESS)
174 			return (err);
175 
176 		/*
177 		 * Skip PCI and PCIEX devices because they will be processed
178 		 * later in the picl tree walk.
179 		 */
180 		if ((strcmp(piclclass, PCIEX) == 0) ||
181 		    (strcmp(piclclass, PCI) == 0)) {
182 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
183 			    &nodeh, sizeof (picl_nodehdl_t));
184 			continue;
185 		}
186 
187 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
188 		    path, sizeof (path));
189 		if (err != PICL_SUCCESS) {
190 			return (err);
191 		}
192 
193 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
194 
195 		monza_get_bus_type(parent_path, &pci_card);
196 
197 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
198 		    sizeof (name));
199 		if (err == PICL_PROPNOTFOUND)
200 			(void) strcpy(name, "");
201 		else if (err != PICL_SUCCESS)
202 			return (err);
203 
204 		if (strcmp(parent_path, MONZA_NIU) == 0)
205 			monza_get_slot_number(path, &pci_card);
206 		else
207 			monza_get_slot_number(parent_path, &pci_card);
208 
209 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
210 		    sizeof (name));
211 		if (err == PICL_PROPNOTFOUND)
212 			(void) strcpy(name, "");
213 		else if (err != PICL_SUCCESS)
214 			return (err);
215 
216 		/* Figure NAC name */
217 		if ((strcmp(name, NETWORK) == 0 ||
218 		    strcmp(name, ETHERNET) == 0) &&
219 		    (strcmp(pci_card.slot_str, MOTHERBOARD) == 0)) {
220 			instance = monza_get_network_instance(path);
221 
222 			(void) snprintf(pci_card.status,
223 			    sizeof (pci_card.status), "%s/%s%d", MOTHERBOARD,
224 			    "NET", instance);
225 		} else {
226 			if (pci_card.slot != -1) {
227 				(void) snprintf(pci_card.status,
228 				    sizeof (pci_card.status), "%s/%s%d",
229 				    IOBOARD, pci_card.bus_type, pci_card.slot);
230 			} else {
231 				(void) snprintf(pci_card.status,
232 				    sizeof (pci_card.status),
233 				"%s/%s", MOTHERBOARD, pci_card.bus_type);
234 			}
235 		}
236 
237 		/*
238 		 * Get the name of this card. If binding_name is found,
239 		 * name will be <nodename>-<binding_name>
240 		 */
241 
242 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
243 		    &binding_name, sizeof (binding_name));
244 		if (err == PICL_PROPNOTFOUND) {
245 			/*
246 			 * if compatible prop is found, name will be
247 			 * <nodename>-<compatible>
248 			 */
249 			err = monza_get_first_compatible_value(nodeh,
250 			    &compatible);
251 			if (err == PICL_SUCCESS) {
252 				(void) strlcat(name, "-", MAXSTRLEN);
253 				(void) strlcat(name, compatible, MAXSTRLEN);
254 				free(compatible);
255 			} else if (err != PICL_PROPNOTFOUND) {
256 				return (err);
257 			}
258 		} else if (err != PICL_SUCCESS) {
259 			return (err);
260 		} else if (strcmp(name, binding_name) != 0) {
261 			(void) strlcat(name, "-", MAXSTRLEN);
262 			(void) strlcat(name, binding_name, MAXSTRLEN);
263 		}
264 
265 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
266 
267 		/* Get the model of this card */
268 
269 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
270 		    &model, sizeof (model));
271 		if (err == PICL_PROPNOTFOUND)
272 			(void) strcpy(model, "");
273 		else if (err != PICL_SUCCESS)
274 			return (err);
275 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
276 
277 		/* Print NAC name */
278 		log_printf("%-11s", pci_card.status);
279 		/* Print IO Type */
280 		log_printf("%6s", pci_card.bus_type);
281 		/* Print Slot # */
282 		log_printf("%5s", pci_card.slot_str);
283 		/* Print Parent Path */
284 		log_printf("%46.45s", pci_card.notes);
285 		/* Printf Card Name */
286 		if (strlen(pci_card.name) > 24)
287 			log_printf("%25.24s+", pci_card.name);
288 		else
289 			log_printf("%26s", pci_card.name);
290 		/* Print Card Model */
291 		if (strlen(pci_card.model) > 10)
292 			log_printf("%10.9s+", pci_card.model);
293 		else
294 			log_printf("%10s", pci_card.model);
295 		log_printf("\n");
296 
297 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
298 		    sizeof (picl_nodehdl_t));
299 
300 	}
301 
302 	return (PICL_WALK_CONTINUE);
303 }
304 
305 /*
306  * display_pci
307  * Display all the PCI IO cards on this board.
308  */
309 void
310 sun4v_display_pci(picl_nodehdl_t plafh)
311 {
312 	char    platbuf[MAXSTRLEN];
313 	char	*fmt = "%-11s %-7s %-4s %-46s %-25s %-8s";
314 	static int banner = FALSE; /* Have we printed the column headings? */
315 
316 	if (banner == FALSE) {
317 		log_printf("\n", 0);
318 		log_printf("=========================", 0);
319 		log_printf(dgettext(TEXT_DOMAIN, " IO Configuration "), 0);
320 		log_printf("=========================", 0);
321 		log_printf("\n", 0);
322 		log_printf("\n", 0);
323 		log_printf(fmt, "", "IO", "", "", "", "", 0);
324 		log_printf("\n", 0);
325 		log_printf(fmt, "Location", "Type", "Slot", "Path",
326 		    "Name", "Model", 0);
327 		log_printf("\n");
328 		log_printf(fmt, "-----------", "-----", "----",
329 		    "---------------------------------------------",
330 		    "-------------------------", "---------", 0);
331 		log_printf("\n");
332 		banner = TRUE;
333 	}
334 
335 	/* Get platform name, if that fails, use monza name by default */
336 	if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) {
337 		(void) strcpy(platbuf, MONZA_PLATFORM);
338 	}
339 
340 	(void) picl_walk_tree_by_class(plafh, PCIEX, PCIEX, monza_pci_callback);
341 	(void) picl_walk_tree_by_class(plafh, PCI, PCI, monza_pci_callback);
342 }
343 
344 /* ARGSUSED */
345 void
346 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
347 {
348 	/* NOTE(ARGUNUSED(kstats)) */
349 	/*
350 	 * Now display the last powerfail time and the fatal hardware
351 	 * reset information. We do this under a couple of conditions.
352 	 * First if the user asks for it. The second is if the user
353 	 * told us to do logging, and we found a system failure.
354 	 */
355 	if (flag) {
356 		/*
357 		 * display time of latest powerfail. Not all systems
358 		 * have this capability. For those that do not, this
359 		 * is just a no-op.
360 		 */
361 		disp_powerfail(root);
362 
363 		/* platform_disp_prom_version(tree); */
364 		sun4v_display_hw_revisions(root, plafh);
365 	}
366 }
367 
368 /*
369  * local functions
370  */
371 /*
372  * add all io devices under pci in io list
373  */
374 /* ARGSUSED */
375 static int
376 monza_hw_rev_callback(picl_nodehdl_t pcih, void *args)
377 {
378 	int		err = PICL_SUCCESS;
379 	char		path[MAXSTRLEN] = "";
380 	char		device_path[MAXSTRLEN];
381 	char		NAC[MAXSTRLEN];
382 	char		*compatible;
383 	int32_t		revision;
384 	int		device_found;
385 
386 	device_found = 0;
387 
388 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
389 	    sizeof (path));
390 	if (err != PICL_SUCCESS) {
391 		return (err);
392 	}
393 
394 
395 	if ((strncmp(path, MONZA_NETWORK_0, strlen(MONZA_NETWORK_0)) == 0) ||
396 	    (strncmp(path, MONZA_NETWORK_1, strlen(MONZA_NETWORK_1)) == 0)) {
397 		device_found = 1;
398 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d",
399 		    MOTHERBOARD, OPHIR, 0);
400 		revision = monza_get_int_propval(pcih, OBP_PROP_REVISION_ID,
401 		    &err);
402 	}
403 
404 	if ((strncmp(path, MONZA_NETWORK_2, strlen(MONZA_NETWORK_2)) == 0) ||
405 	    (strncmp(path, MONZA_NETWORK_3, strlen(MONZA_NETWORK_3)) == 0)) {
406 		device_found = 1;
407 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d",
408 		    MOTHERBOARD, OPHIR, 1);
409 		revision = monza_get_int_propval(pcih, OBP_PROP_REVISION_ID,
410 		    &err);
411 	}
412 
413 	if ((strncmp(path, MONZA_ENET_2, strlen(MONZA_ENET_2)) == 0) ||
414 	    (strncmp(path, MONZA_ENET_3, strlen(MONZA_ENET_3)) == 0)) {
415 		device_found = 1;
416 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d",
417 		    MOTHERBOARD, OPHIR, 1);
418 		revision = monza_get_int_propval(pcih, OBP_PROP_REVISION_ID,
419 		    &err);
420 	}
421 
422 	if ((strncmp(path, MONZA_NETWORK_4, strlen(MONZA_NETWORK_4)) == 0) ||
423 	    (strncmp(path, MONZA_NETWORK_5, strlen(MONZA_NETWORK_5)) == 0)) {
424 		device_found = 1;
425 		(void) snprintf(NAC, sizeof (NAC), "%s/%s%d",
426 		    MOTHERBOARD, OPHIR, 2);
427 		revision = monza_get_int_propval(pcih, OBP_PROP_REVISION_ID,
428 		    &err);
429 	}
430 
431 	if (strcmp(path, MONZA_PCIE_SWITCH_PATH) == 0) {
432 		device_found = 1;
433 		(void) snprintf(NAC, sizeof (NAC), "%s/%s",
434 		    MOTHERBOARD, PCIE_SWITCH);
435 		revision = monza_get_int_propval(pcih,
436 		    OBP_PROP_REVISION_ID, &err);
437 	}
438 
439 	if (strcmp(path, MONZA_RTM_PATH) == 0) {
440 		device_found = 1;
441 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", RTM, AMC);
442 		revision = monza_get_int_propval(pcih, OBP_PROP_REVISION_ID,
443 		    &err);
444 	}
445 
446 	if (strcmp(path, MONZA_CF_PATH) == 0) {
447 		device_found = 1;
448 		(void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD,
449 		    MONZA_CF_DEVICE);
450 		revision = monza_get_int_propval(pcih, OBP_PROP_REVISION_ID,
451 		    &err);
452 	}
453 
454 	if (device_found == 1) {
455 		(void) strcpy(device_path, path);
456 		err = monza_get_first_compatible_value(pcih, &compatible);
457 
458 		/* Print NAC name */
459 		log_printf("%-20s", NAC);
460 		/* Print Device Path */
461 		if (strlen(device_path) > 38)
462 			log_printf("%38.37s+", device_path);
463 		else
464 			log_printf("%39s", device_path);
465 
466 		/* Print Compatible # */
467 		if (err == PICL_SUCCESS) {
468 			log_printf("%31s", compatible);
469 			free(compatible);
470 		} else
471 			log_printf("%31s", " ");
472 
473 		/* Print Revision */
474 		log_printf("%6d", revision);
475 		log_printf("\n");
476 	}
477 
478 	return (PICL_WALK_CONTINUE);
479 }
480 
481 /*ARGSUSED*/
482 static void
483 sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh)
484 {
485 	Prom_node	*pnode;
486 	char		*value;
487 	char 		platbuf[MAXSTRLEN];
488 	char	*fmt = "%-20s %-40s %-30s %-9s";
489 
490 	log_printf(dgettext(TEXT_DOMAIN, "\n"
491 	    "========================= HW Revisions "
492 	    "=======================================\n\n"));
493 
494 	log_printf(dgettext(TEXT_DOMAIN,
495 	    "System PROM revisions:\n"
496 	    "----------------------\n"));
497 
498 	pnode = dev_find_node(root, "openprom");
499 	if (pnode != NULL) {
500 		value = (char *)get_prop_val(find_prop(pnode, "version"));
501 		log_printf(value);
502 	}
503 
504 	log_printf(dgettext(TEXT_DOMAIN, "\n\n"
505 	    "IO ASIC revisions:\n"
506 	    "------------------\n"));
507 	log_printf(fmt, "Location", "Path", "Device", "Revision\n", 0);
508 	log_printf(fmt, "--------------------",
509 	    "----------------------------------------",
510 	    "------------------------------",
511 	    "---------\n", 0);
512 
513 	/* Get platform name, if that fails, use monza name by default */
514 	if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) {
515 		(void) strcpy(platbuf, MONZA_PLATFORM);
516 	}
517 
518 	(void) picl_walk_tree_by_class(plafh, PCIEX,
519 	    PCIEX, monza_hw_rev_callback);
520 	(void) picl_walk_tree_by_class(plafh, PCI,
521 	    PCI, monza_hw_rev_callback);
522 	(void) picl_walk_tree_by_class(plafh, NETWORK,
523 	    NETWORK, monza_hw_rev_callback);
524 }
525 
526 /*
527  * return the first compatible value
528  */
529 static int
530 monza_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
531 {
532 	int		err;
533 	picl_prophdl_t	proph;
534 	picl_propinfo_t	pinfo;
535 	picl_prophdl_t	tblh;
536 	picl_prophdl_t	rowproph;
537 	char		*pval;
538 
539 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
540 	    &pinfo, &proph);
541 	if (err != PICL_SUCCESS)
542 		return (err);
543 
544 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
545 		pval = malloc(pinfo.size);
546 		if (pval == NULL)
547 			return (PICL_FAILURE);
548 		err = picl_get_propval(proph, pval, pinfo.size);
549 		if (err != PICL_SUCCESS) {
550 			free(pval);
551 			return (err);
552 		}
553 		*outbuf = pval;
554 		return (PICL_SUCCESS);
555 	}
556 
557 	if (pinfo.type != PICL_PTYPE_TABLE)
558 		return (PICL_FAILURE);
559 
560 	/* get first string from table */
561 	err = picl_get_propval(proph, &tblh, pinfo.size);
562 	if (err != PICL_SUCCESS)
563 		return (err);
564 
565 	err = picl_get_next_by_row(tblh, &rowproph);
566 	if (err != PICL_SUCCESS)
567 		return (err);
568 
569 	err = picl_get_propinfo(rowproph, &pinfo);
570 	if (err != PICL_SUCCESS)
571 		return (err);
572 
573 	pval = malloc(pinfo.size);
574 	if (pval == NULL)
575 		return (PICL_FAILURE);
576 
577 	err = picl_get_propval(rowproph, pval, pinfo.size);
578 	if (err != PICL_SUCCESS) {
579 		free(pval);
580 		return (err);
581 	}
582 
583 	*outbuf = pval;
584 	return (PICL_SUCCESS);
585 }
586 
587 static int64_t
588 monza_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
589 {
590 	int		err;
591 	picl_prophdl_t	proph;
592 	picl_propinfo_t	pinfo;
593 	int8_t		int8v;
594 	int16_t		int16v;
595 	int32_t		int32v;
596 	int64_t		int64v;
597 
598 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
599 	if (err != PICL_SUCCESS) {
600 		*ret = err;
601 		return (0);
602 	}
603 
604 	/*
605 	 * If it is not an int, uint or byte array prop, return failure
606 	 */
607 	if ((pinfo.type != PICL_PTYPE_INT) &&
608 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
609 	    (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
610 		*ret = PICL_FAILURE;
611 		return (0);
612 	}
613 
614 	switch (pinfo.size) {
615 	case sizeof (int8_t):
616 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
617 		*ret = err;
618 		return (int8v);
619 	case sizeof (int16_t):
620 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
621 		*ret = err;
622 		return (int16v);
623 	case sizeof (int32_t):
624 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
625 		*ret = err;
626 		return (int32v);
627 	case sizeof (int64_t):
628 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
629 		*ret = err;
630 		return (int64v);
631 	default:	/* not supported size */
632 		*ret = PICL_FAILURE;
633 		return (0);
634 	}
635 }
636