Home | History | Annotate | Download | only in common
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
     24  * All rights reserved.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <unistd.h>
     32 #include <ctype.h>
     33 #include <string.h>
     34 #include <kvm.h>
     35 #include <varargs.h>
     36 #include <errno.h>
     37 #include <time.h>
     38 #include <dirent.h>
     39 #include <fcntl.h>
     40 #include <sys/param.h>
     41 #include <sys/stat.h>
     42 #include <sys/types.h>
     43 #include <sys/utsname.h>
     44 #include <sys/openpromio.h>
     45 #include <sys/systeminfo.h>
     46 #include <kstat.h>
     47 #include <libintl.h>
     48 #include <syslog.h>
     49 #include <sys/dkio.h>
     50 #include "pdevinfo.h"
     51 #include "display.h"
     52 #include "pdevinfo_sun4u.h"
     53 #include "display_sun4u.h"
     54 #include "libprtdiag.h"
     55 
     56 #if !defined(TEXT_DOMAIN)
     57 #define	TEXT_DOMAIN	"SYS_TEST"
     58 #endif
     59 
     60 Prom_node *
     61 find_pci_bus(Prom_node *node, int id, int bus)
     62 {
     63 	Prom_node *pnode;
     64 
     65 	/* find the first pci node */
     66 	pnode = dev_find_node(node, "pci");
     67 
     68 	while (pnode != NULL) {
     69 		int tmp_id;
     70 		int tmp_bus;
     71 
     72 		tmp_id = get_id(pnode);
     73 		tmp_bus = get_pci_bus(pnode);
     74 
     75 		if ((tmp_id == id) &&
     76 		    (tmp_bus == bus)) {
     77 			break;
     78 		}
     79 
     80 		pnode = dev_next_node(pnode, "pci");
     81 	}
     82 	return (pnode);
     83 }
     84 
     85 /*
     86  * get_pci_bus
     87  *
     88  * Determines the PCI bus, either A (0) or B (1). If the function cannot
     89  * find the bus-ranges property, it returns -1.
     90  */
     91 int
     92 get_pci_bus(Prom_node *pnode)
     93 {
     94 	int *value;
     95 
     96 	/* look up the bus-range property */
     97 	if ((value = (int *)get_prop_val(find_prop(pnode, "bus-range"))) ==
     98 	    NULL) {
     99 		return (-1);
    100 	}
    101 
    102 	if (*value == 0) {
    103 		return (1);	/* B bus has a bus-range value = 0 */
    104 	} else {
    105 		return (0);
    106 	}
    107 }
    108 
    109 
    110 
    111 /*
    112  * Find the PCI device number of this PCI device. If no device number can
    113  * be determined, then return -1.
    114  */
    115 int
    116 get_pci_device(Prom_node *pnode)
    117 {
    118 	void *value;
    119 
    120 	if ((value = get_prop_val(find_prop(pnode, "assigned-addresses"))) !=
    121 		NULL) {
    122 		return (PCI_DEVICE(*(int *)value));
    123 	} else {
    124 		return (-1);
    125 	}
    126 }
    127 
    128 /*
    129  * Find the PCI device number of this PCI device. If no device number can
    130  * be determined, then return -1.
    131  */
    132 int
    133 get_pci_to_pci_device(Prom_node *pnode)
    134 {
    135 	void *value;
    136 
    137 	if ((value = get_prop_val(find_prop(pnode, "reg"))) !=
    138 		NULL) {
    139 		return (PCI_DEVICE(*(int *)value));
    140 	} else {
    141 		return (-1);
    142 	}
    143 }
    144 
    145 /*
    146  * free_io_cards
    147  * Frees the memory allocated for an io card list.
    148  */
    149 void
    150 free_io_cards(struct io_card *card_list)
    151 {
    152 	/* Free the list */
    153 	if (card_list != NULL) {
    154 		struct io_card *p, *q;
    155 
    156 		for (p = card_list, q = NULL; p != NULL; p = q) {
    157 			q = p->next;
    158 			free(p);
    159 		}
    160 	}
    161 }
    162 
    163 
    164 /*
    165  * insert_io_card
    166  * Inserts an io_card structure into the list.  The list is maintained
    167  * in order based on board number and slot number.  Also, the storage
    168  * for the "card" argument is assumed to be handled by the caller,
    169  * so we won't touch it.
    170  */
    171 struct io_card *
    172 insert_io_card(struct io_card *list, struct io_card *card)
    173 {
    174 	struct io_card *newcard;
    175 	struct io_card *p, *q;
    176 
    177 	if (card == NULL)
    178 		return (list);
    179 
    180 	/* Copy the card to be added into new storage */
    181 	newcard = (struct io_card *)malloc(sizeof (struct io_card));
    182 	if (newcard == NULL) {
    183 		perror("malloc");
    184 		exit(2);
    185 	}
    186 	(void) memcpy(newcard, card, sizeof (struct io_card));
    187 	newcard->next = NULL;
    188 
    189 	if (list == NULL)
    190 	return (newcard);
    191 
    192 	/* Find the proper place in the list for the new card */
    193 	for (p = list, q = NULL; p != NULL; q = p, p = p->next) {
    194 		if (newcard->board < p->board)
    195 			break;
    196 		if ((newcard->board == p->board) && (newcard->slot < p->slot))
    197 			break;
    198 	}
    199 
    200 	/* Insert the new card into the list */
    201 	if (q == NULL) {
    202 		newcard->next = p;
    203 		return (newcard);
    204 	} else {
    205 		newcard->next = p;
    206 		q->next = newcard;
    207 		return (list);
    208 	}
    209 }
    210 
    211 
    212 char *
    213 fmt_manf_id(unsigned int encoded_id, char *outbuf)
    214 {
    215 	union manuf manuf;
    216 
    217 	/*
    218 	 * Format the manufacturer's info.  Note a small inconsistency we
    219 	 * have to work around - Brooktree has it's part number in decimal,
    220 	 * while Mitsubishi has it's part number in hex.
    221 	 */
    222 	manuf.encoded_id = encoded_id;
    223 	switch (manuf.fld.manf) {
    224 	case MANF_BROOKTREE:
    225 		(void) sprintf(outbuf, "%s %d, version %d", "Brooktree",
    226 			manuf.fld.partno, manuf.fld.version);
    227 		break;
    228 
    229 	case MANF_MITSUBISHI:
    230 		(void) sprintf(outbuf, "%s %x, version %d", "Mitsubishi",
    231 			manuf.fld.partno, manuf.fld.version);
    232 		break;
    233 
    234 	default:
    235 		(void) sprintf(outbuf, "JED code %d, Part num 0x%x, version %d",
    236 			manuf.fld.manf, manuf.fld.partno, manuf.fld.version);
    237 	}
    238 	return (outbuf);
    239 }
    240 
    241 
    242 /*
    243  * Find the sbus slot number of this Sbus device. If no slot number can
    244  * be determined, then return -1.
    245  */
    246 int
    247 get_sbus_slot(Prom_node *pnode)
    248 {
    249 	void *value;
    250 
    251 	if ((value = get_prop_val(find_prop(pnode, "reg"))) != NULL) {
    252 		return (*(int *)value);
    253 	} else {
    254 		return (-1);
    255 	}
    256 }
    257 
    258 
    259 /*
    260  * This routine is the generic link into displaying system IO
    261  * configuration. It displays the table header, then displays
    262  * all the SBus cards, then displays all fo the PCI IO cards.
    263  */
    264 void
    265 display_io_devices(Sys_tree *tree)
    266 {
    267 	Board_node *bnode;
    268 
    269 	/*
    270 	 * TRANSLATION_NOTE
    271 	 * Following string is used as a table header.
    272 	 * Please maintain the current alignment in
    273 	 * translation.
    274 	 */
    275 	log_printf("\n", 0);
    276 	log_printf("=========================", 0);
    277 	log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
    278 	log_printf("=========================", 0);
    279 	log_printf("\n", 0);
    280 	log_printf("\n", 0);
    281 	bnode = tree->bd_list;
    282 	while (bnode != NULL) {
    283 		display_sbus(bnode);
    284 		display_pci(bnode);
    285 		display_ffb(bnode, 1);
    286 		bnode = bnode->next;
    287 	}
    288 }
    289 
    290 void
    291 display_pci(Board_node *bnode)
    292 {
    293 #ifdef  lint
    294 	bnode = bnode;
    295 #endif
    296 	/*
    297 	 * This function is intentionally empty
    298 	 */
    299 }
    300 
    301 
    302 /*
    303  * Print out all the io cards in the list.  Also print the column
    304  * headers if told to do so.
    305  */
    306 void
    307 display_io_cards(struct io_card *list)
    308 {
    309 	static int banner = 0; /* Have we printed the column headings? */
    310 	struct io_card *p;
    311 
    312 	if (list == NULL)
    313 		return;
    314 
    315 	if (banner == 0) {
    316 		log_printf("     Bus   Freq\n", 0);
    317 		log_printf("Brd  Type  MHz   Slot        "
    318 			"Name                          "
    319 			"Model", 0);
    320 		log_printf("\n", 0);
    321 		log_printf("---  ----  ----  ----------  "
    322 			"----------------------------  "
    323 			"--------------------", 0);
    324 		log_printf("\n", 0);
    325 		banner = 1;
    326 	}
    327 
    328 	for (p = list; p != NULL; p = p -> next) {
    329 		log_printf("%2d   ", p->board, 0);
    330 		log_printf("%-4s  ", p->bus_type, 0);
    331 		log_printf("%3d   ", p->freq, 0);
    332 		/*
    333 		 * We check to see if it's an int or
    334 		 * a char string to display for slot.
    335 		 */
    336 		if (p->slot == PCI_SLOT_IS_STRING)
    337 			log_printf("%10s  ", p->slot_str, 0);
    338 		else
    339 			log_printf("%10d  ", p->slot, 0);
    340 
    341 		log_printf("%-28.28s", p->name, 0);
    342 		if (strlen(p->name) > 28)
    343 			log_printf("+ ", 0);
    344 		else
    345 			log_printf("  ", 0);
    346 		log_printf("%-19.19s", p->model, 0);
    347 		if (strlen(p->model) > 19)
    348 			log_printf("+", 0);
    349 		log_printf("\n", 0);
    350 	}
    351 }
    352 
    353 /*
    354  * Display all FFBs on this board.  It can either be in tabular format,
    355  * or a more verbose format.
    356  */
    357 void
    358 display_ffb(Board_node *board, int table)
    359 {
    360 	Prom_node *fb;
    361 	void *value;
    362 	struct io_card *card_list = NULL;
    363 	struct io_card card;
    364 	char *type;
    365 	char *label;
    366 
    367 	if (board == NULL)
    368 		return;
    369 
    370 	/* Fill in common information */
    371 	card.display = 1;
    372 	card.board = board->board_num;
    373 	(void) sprintf(card.bus_type, BUS_TYPE);
    374 	card.freq = sys_clk;
    375 
    376 	for (fb = dev_find_node_by_type(board->nodes, "device_type", "display");
    377 	    fb != NULL;
    378 	    fb = dev_next_node_by_type(fb, "device_type", "display")) {
    379 		value = get_prop_val(find_prop(fb, "name"));
    380 		if (value != NULL) {
    381 			if ((strcmp(FFB_NAME, value)) == 0) {
    382 				type = FFB_NAME;
    383 				label = "FFB";
    384 			} else if ((strcmp(AFB_NAME, value)) == 0) {
    385 				type = AFB_NAME;
    386 				label = "AFB";
    387 			} else
    388 				continue;
    389 		} else
    390 			continue;
    391 		if (table == 1) {
    392 			/* Print out in table format */
    393 
    394 			/* XXX - Get the slot number (hack) */
    395 			card.slot = get_id(fb);
    396 
    397 			/* Find out if it's single or double buffered */
    398 			(void) sprintf(card.name, "%s", label);
    399 			value = get_prop_val(find_prop(fb, "board_type"));
    400 			if (value != NULL)
    401 				if ((*(int *)value) & FFB_B_BUFF)
    402 					(void) sprintf(card.name,
    403 						"%s, Double Buffered", label);
    404 				else
    405 					(void) sprintf(card.name,
    406 						"%s, Single Buffered", label);
    407 
    408 			/*
    409 			 * Print model number only if board_type bit 2
    410 			 * is not set and it is not SUNW,XXX-XXXX.
    411 			 */
    412 			card.model[0] = '\0';
    413 
    414 			if (strcmp(type, AFB_NAME) == 0) {
    415 				if (((*(int *)value) & 0x4) != 0x4) {
    416 					value = get_prop_val(find_prop(fb,
    417 						    "model"));
    418 					if ((value != NULL) &&
    419 					    (strcmp(value,
    420 					    "SUNW,XXX-XXXX") != 0)) {
    421 						(void) sprintf(card.model, "%s",
    422 						    (char *)value);
    423 					}
    424 				}
    425 			} else {
    426 				value = get_prop_val(find_prop(fb, "model"));
    427 				if (value != NULL)
    428 					(void) sprintf(card.model, "%s",
    429 					    (char *)value);
    430 			}
    431 
    432 			card_list = insert_io_card(card_list, &card);
    433 		} else {
    434 			/* print in long format */
    435 			char device[MAXSTRLEN];
    436 			int fd = -1;
    437 			struct dirent *direntp;
    438 			DIR *dirp;
    439 			union strap_un strap;
    440 			struct ffb_sys_info fsi;
    441 
    442 			/* Find the device node using upa-portid/portid */
    443 			value = get_prop_val(find_prop(fb, "upa-portid"));
    444 			if (value == NULL)
    445 				value = get_prop_val(find_prop(fb, "portid"));
    446 
    447 			if (value == NULL)
    448 			    continue;
    449 
    450 			(void) sprintf(device, "%s@%x", type,
    451 				*(int *)value);
    452 			if ((dirp = opendir("/devices")) == NULL)
    453 				continue;
    454 
    455 			while ((direntp = readdir(dirp)) != NULL) {
    456 				if (strstr(direntp->d_name, device) != NULL) {
    457 					(void) sprintf(device, "/devices/%s",
    458 						direntp->d_name);
    459 					fd = open(device, O_RDWR, 0666);
    460 					break;
    461 				}
    462 			}
    463 			(void) closedir(dirp);
    464 
    465 			if (fd == -1)
    466 				continue;
    467 
    468 			if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
    469 				continue;
    470 
    471 			log_printf("%s Hardware Configuration:\n", label, 0);
    472 			log_printf("-----------------------------------\n", 0);
    473 
    474 			strap.ffb_strap_bits = fsi.ffb_strap_bits;
    475 			log_printf("\tBoard rev: %d\n",
    476 				(int)strap.fld.board_rev, 0);
    477 			log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
    478 			log_printf("\tDAC: %s\n",
    479 				fmt_manf_id(fsi.dac_version, device), 0);
    480 			log_printf("\t3DRAM: %s\n",
    481 				fmt_manf_id(fsi.fbram_version, device), 0);
    482 			log_printf("\n", 0);
    483 		}
    484 
    485 	}
    486 	display_io_cards(card_list);
    487 	free_io_cards(card_list);
    488 }
    489 
    490 
    491 /*
    492  * Display all the SBus IO cards on this board.
    493  */
    494 void
    495 display_sbus(Board_node *board)
    496 {
    497 	struct io_card card;
    498 	struct io_card *card_list = NULL;
    499 	int freq;
    500 	int card_num;
    501 	void *value;
    502 	Prom_node *sbus;
    503 	Prom_node *card_node;
    504 
    505 	if (board == NULL)
    506 		return;
    507 
    508 	for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
    509 	    sbus = dev_next_node(sbus, SBUS_NAME)) {
    510 
    511 		/* Skip failed nodes for now */
    512 		if (node_failed(sbus))
    513 			continue;
    514 
    515 		/* Calculate SBus frequency in MHz */
    516 		value = get_prop_val(find_prop(sbus, "clock-frequency"));
    517 		if (value != NULL)
    518 			freq = ((*(int *)value) + 500000) / 1000000;
    519 		else
    520 			freq = -1;
    521 
    522 		for (card_node = sbus->child; card_node != NULL;
    523 		    card_node = card_node->sibling) {
    524 			char *model;
    525 			char *name;
    526 			char *child_name;
    527 
    528 			card_num = get_sbus_slot(card_node);
    529 			if (card_num == -1)
    530 				continue;
    531 
    532 			/* Fill in card information */
    533 			card.display = 1;
    534 			card.freq = freq;
    535 			card.board = board->board_num;
    536 			(void) sprintf(card.bus_type, "SBus");
    537 			card.slot = card_num;
    538 			card.status[0] = '\0';
    539 
    540 			/* Try and get card status */
    541 			value = get_prop_val(find_prop(card_node, "status"));
    542 			if (value != NULL)
    543 				(void) strncpy(card.status, (char *)value,
    544 					MAXSTRLEN);
    545 
    546 			/* XXX - For now, don't display failed cards */
    547 			if (strstr(card.status, "fail") != NULL)
    548 				continue;
    549 
    550 			/* Now gather all of the node names for that card */
    551 			model = (char *)get_prop_val(find_prop(card_node,
    552 				"model"));
    553 			name = get_node_name(card_node);
    554 
    555 			if (name == NULL)
    556 				continue;
    557 
    558 			card.name[0] = '\0';
    559 			card.model[0] = '\0';
    560 
    561 			/* Figure out how we want to display the name */
    562 			child_name = get_node_name(card_node->child);
    563 			if ((card_node->child != NULL) &&
    564 			    (child_name != NULL)) {
    565 				value = get_prop_val(find_prop(card_node->child,
    566 					"device_type"));
    567 				if (value != NULL)
    568 					(void) sprintf(card.name, "%s/%s (%s)",
    569 						name, child_name,
    570 						(char *)value);
    571 				else
    572 					(void) sprintf(card.name, "%s/%s", name,
    573 						child_name);
    574 			} else {
    575 				(void) strncpy(card.name, name, MAXSTRLEN);
    576 			}
    577 
    578 			if (model != NULL)
    579 				(void) strncpy(card.model, model, MAXSTRLEN);
    580 
    581 			card_list = insert_io_card(card_list, &card);
    582 		}
    583 	}
    584 
    585 	/* We're all done gathering card info, now print it out */
    586 	display_io_cards(card_list);
    587 	free_io_cards(card_list);
    588 }
    589 
    590 
    591 /*
    592  * Get slot-names properties from parent node and
    593  * store them in an array.
    594  */
    595 int
    596 populate_slot_name_arr(Prom_node *pci, int *slot_name_bits,
    597 			char **slot_name_arr, int num_slots)
    598 {
    599 	int	i, j, bit_mask;
    600 	char	*value;
    601 
    602 	value = (char *)get_prop_val(find_prop(pci, "slot-names"));
    603 	D_PRINTF("\n populate_slot_name_arr: value = [0x%x]\n", value);
    604 
    605 	if (value != NULL) {
    606 		char	*strings_arr[MAX_SLOTS_PER_IO_BD];
    607 		bit_mask = *slot_name_bits = *(int *)value;
    608 		D_PRINTF("\nslot_names 1st integer = [0x%x]", *slot_name_bits);
    609 
    610 		/* array starts after first int */
    611 		strings_arr[0] = value + sizeof (int);
    612 
    613 		/*
    614 		 * break the array out into num_slots number of strings
    615 		 */
    616 		for (i = 1; i < num_slots; i++) {
    617 			strings_arr[i] = (char *)strings_arr[i - 1]
    618 			    + strlen(strings_arr[i - 1]) + 1;
    619 		}
    620 
    621 		/*
    622 		 * process array of slot_names to remove blanks
    623 		 */
    624 		j = 0;
    625 		for (i = 0; i < num_slots; i++) {
    626 			if ((bit_mask >> i) & 0x1)
    627 				slot_name_arr[i] = strings_arr[j++];
    628 			else
    629 				slot_name_arr[i] = "";
    630 
    631 			D_PRINTF("\nslot_name_arr[%d] = [%s]", i,
    632 				slot_name_arr[i]);
    633 		}
    634 		return (0);
    635 	} else {
    636 		D_PRINTF("\n populate_slot_name_arr: - psycho with no "
    637 		    "slot-names\n");
    638 		return (0);
    639 	}
    640 }
    641 
    642 int
    643 get_card_frequency(Prom_node *pci)
    644 {
    645 	char	*value = get_prop_val(find_prop(pci, "clock-frequency"));
    646 
    647 	if (value == NULL)
    648 		return (-1);
    649 	else
    650 		return (int)(((*(int *)value) + 500000) / 1000000);
    651 
    652 }
    653 
    654 void
    655 get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no)
    656 {
    657 
    658 	void	*value = get_prop_val(find_prop(card_node, "reg"));
    659 
    660 	if (value != NULL) {
    661 		int int_val = *(int *)value;
    662 		*dev_no = PCI_REG_TO_DEV(int_val);
    663 		*func_no = PCI_REG_TO_FUNC(int_val);
    664 	} else {
    665 		*dev_no = -1;
    666 		*func_no = -1;
    667 	}
    668 }
    669 
    670 void
    671 get_pci_class_codes(Prom_node *card_node, int *class_code, int *subclass_code)
    672 {
    673 	int	class_code_reg = get_pci_class_code_reg(card_node);
    674 
    675 	*class_code = CLASS_REG_TO_CLASS(class_code_reg);
    676 	*subclass_code = CLASS_REG_TO_SUBCLASS(class_code_reg);
    677 }
    678 
    679 int
    680 is_pci_bridge(Prom_node *card_node, char *name)
    681 {
    682 	int class_code, subclass_code;
    683 
    684 	if (card_node == NULL)
    685 		return (FALSE);
    686 
    687 	get_pci_class_codes(card_node, &class_code, &subclass_code);
    688 
    689 	if ((strncmp(name, "pci", 3) == 0) &&
    690 	    (class_code == PCI_BRIDGE_CLASS) &&
    691 	    (subclass_code == PCI_PCI_BRIDGE_SUBCLASS))
    692 		return (TRUE);
    693 	else
    694 		return (FALSE);
    695 }
    696 
    697 int
    698 is_pci_bridge_other(Prom_node *card_node, char *name)
    699 {
    700 	int class_code, subclass_code;
    701 
    702 	if (card_node == NULL)
    703 		return (FALSE);
    704 
    705 	get_pci_class_codes(card_node, &class_code, &subclass_code);
    706 
    707 	if ((strncmp(name, "pci", 3) == 0) &&
    708 	    (class_code == PCI_BRIDGE_CLASS) &&
    709 	    (subclass_code == PCI_SUBCLASS_OTHER))
    710 		return (TRUE);
    711 	else
    712 		return (FALSE);
    713 }
    714 void
    715 get_pci_card_model(Prom_node *card_node, char *model)
    716 {
    717 	char	*name = get_prop_val(find_prop(card_node, "name"));
    718 	char	*value = get_prop_val(find_prop(card_node, "model"));
    719 	int 	pci_bridge = is_pci_bridge(card_node, name);
    720 
    721 	if (value == NULL)
    722 		model[0] = '\0';
    723 	else
    724 		(void) sprintf(model, "%s",
    725 			(char *)value);
    726 
    727 	if (pci_bridge) {
    728 		if (strlen(model) == 0)
    729 			(void) sprintf(model,
    730 				"%s", "pci-bridge");
    731 		else
    732 			(void) sprintf(model,
    733 				"%s/pci-bridge", model);
    734 	}
    735 }
    736 
    737 void
    738 create_io_card_name(Prom_node *card_node, char *name, char *card_name)
    739 {
    740 	char	*value = get_prop_val(find_prop(card_node, "compatible"));
    741 	char	*child_name;
    742 	char	buf[MAXSTRLEN];
    743 
    744 	if (value != NULL) {
    745 		(void) sprintf(buf, "%s-%s", name,
    746 			(char *)value);
    747 	} else
    748 		(void) sprintf(buf, "%s", name);
    749 
    750 	name = buf;
    751 
    752 	child_name = (char *)get_node_name(card_node->child);
    753 
    754 	if ((card_node->child != NULL) &&
    755 	    (child_name != NULL)) {
    756 		value = get_prop_val(find_prop(card_node->child,
    757 			"device_type"));
    758 		if (value != NULL)
    759 			(void) sprintf(card_name, "%s/%s (%s)",
    760 				name, child_name,
    761 				(char *)value);
    762 		else
    763 			(void) sprintf(card_name, "%s/%s", name,
    764 				child_name);
    765 	} else {
    766 		(void) sprintf(card_name, "%s", (char *)name);
    767 	}
    768 }
    769 
    770 
    771 /*
    772  * Desktop display_psycho_pci
    773  * Display all the psycho based PCI IO cards on this board.
    774  */
    775 
    776 /* ARGSUSED */
    777 void
    778 display_psycho_pci(Board_node *board)
    779 {
    780 	struct io_card	*card_list = NULL;
    781 	struct io_card	card;
    782 	void		*value;
    783 
    784 	Prom_node	*pci, *card_node, *pci_bridge_node = NULL;
    785 	char		*name;
    786 	int		slot_name_bits, pci_bridge_dev_no,
    787 			class_code, subclass_code,
    788 			pci_pci_bridge;
    789 	char		*slot_name_arr[MAX_SLOTS_PER_IO_BD];
    790 
    791 	if (board == NULL)
    792 		return;
    793 
    794 	/* Initialize all the common information */
    795 	card.display = 1;
    796 	card.board = board->board_num;
    797 	(void) sprintf(card.bus_type, "PCI");
    798 
    799 	for (pci = dev_find_node_by_type(board->nodes, "model", "SUNW,psycho");
    800 	    pci != NULL;
    801 	    pci = dev_next_node_by_type(pci, "model", "SUNW,psycho")) {
    802 
    803 		/*
    804 		 * If we have reached a pci-to-pci bridge node,
    805 		 * we are one level below the 'pci' nodes level
    806 		 * in the device tree. To get back to that level,
    807 		 * the search should continue with the sibling of
    808 		 * the parent or else the remaining 'pci' cards
    809 		 * will not show up in the output.
    810 		 */
    811 		if (find_prop(pci, "upa-portid") == NULL) {
    812 			if ((pci->parent->sibling != NULL) &&
    813 				(strcmp(get_prop_val(
    814 				find_prop(pci->parent->sibling,
    815 				"name")), PCI_NAME) == 0))
    816 				pci = pci->parent->sibling;
    817 			else {
    818 				pci = pci->parent->sibling;
    819 				continue;
    820 			}
    821 		}
    822 
    823 		D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n",
    824 		    PCI_NAME, *((int *)get_prop_val(find_prop(
    825 			pci, "upa-portid"))),
    826 			get_prop_val(find_prop(pci, "model")));
    827 
    828 		/* Skip all failed nodes for now */
    829 		if (node_failed(pci))
    830 			continue;
    831 
    832 		/* Fill in frequency */
    833 		card.freq = get_card_frequency(pci);
    834 
    835 		/*
    836 		 * Each PSYCHO device has a slot-names property that can be
    837 		 * used to determine the slot-name string for each IO
    838 		 * device under this node. We get this array now and use
    839 		 * it later when looking at the children of this PSYCHO.
    840 		 */
    841 		if ((populate_slot_name_arr(pci, &slot_name_bits,
    842 		    (char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0)
    843 			goto next_card;
    844 
    845 		/* Walk through the PSYCHO children */
    846 		card_node = pci->child;
    847 		while (card_node != NULL) {
    848 
    849 			pci_pci_bridge = FALSE;
    850 
    851 			/* If it doesn't have a name, skip it */
    852 			name = (char *)get_prop_val(
    853 				find_prop(card_node, "name"));
    854 			if (name == NULL)
    855 				goto next_card;
    856 
    857 			/* get dev# and func# for this card. */
    858 			get_dev_func_num(card_node, &card.dev_no,
    859 			    &card.func_no);
    860 
    861 			/* get class/subclass code for this card. */
    862 			get_pci_class_codes(card_node, &class_code,
    863 			    &subclass_code);
    864 
    865 			D_PRINTF("\nName [%s] - ", name);
    866 			D_PRINTF("device no [%d] - ", card.dev_no);
    867 			D_PRINTF("class_code [%d] subclass_code [%d] - ",
    868 			    class_code, subclass_code);
    869 
    870 			/*
    871 			 * Weed out PCI Bridge, subclass 'other' and
    872 			 * ebus nodes.
    873 			 */
    874 			if (((class_code == PCI_BRIDGE_CLASS) &&
    875 			    (subclass_code == PCI_SUBCLASS_OTHER)) ||
    876 			    (strstr(name, "ebus"))) {
    877 				D_PRINTF("\nSkip ebus/class-other nodes [%s]",
    878 				    name);
    879 				goto next_card;
    880 			}
    881 
    882 			/*
    883 			 * If this is a PCI bridge, then we store it's dev_no
    884 			 * so that it's children can use it for getting at
    885 			 * the slot_name.
    886 			 */
    887 			if (is_pci_bridge(card_node, name)) {
    888 				pci_bridge_dev_no = card.dev_no;
    889 				pci_bridge_node = card_node;
    890 				pci_pci_bridge = TRUE;
    891 				D_PRINTF("\nPCI Bridge detected\n");
    892 			}
    893 
    894 			/*
    895 			 * If we are the child of a pci_bridge we use the
    896 			 * dev# of the pci_bridge as an index to get
    897 			 * the slot number. We know that we are a child of
    898 			 * a pci-bridge if our parent is the same as the last
    899 			 * pci_bridge node found above.
    900 			 */
    901 			if (card_node->parent == pci_bridge_node)
    902 				card.dev_no = pci_bridge_dev_no;
    903 
    904 			/* Get slot-names property from slot_names_arr. */
    905 			get_slot_number_str(&card, (char **)slot_name_arr,
    906 			    slot_name_bits);
    907 
    908 			if (slot_name_bits)
    909 				D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr "
    910 				    "[%s] slot [%s]", name, card.dev_no,
    911 				    slot_name_arr[card.dev_no],
    912 				    card.slot_str);
    913 
    914 			/* XXX - Don't know how to get status for PCI cards */
    915 			card.status[0] = '\0';
    916 
    917 			/* Get the model of this card */
    918 			get_pci_card_model(card_node, (char *)&card.model);
    919 
    920 			/*
    921 			 * If we haven't figured out the frequency yet,
    922 			 * try and get it from the card.
    923 			 */
    924 			value = get_prop_val(find_prop(pci, "clock-frequency"));
    925 			if (value != NULL && card.freq == -1)
    926 				card.freq = ((*(int *)value) + 500000)
    927 					/ 1000000;
    928 
    929 
    930 			/* Figure out how we want to display the name */
    931 			create_io_card_name(card_node, name,
    932 				(char *)&card.name);
    933 
    934 			if (card.freq != -1)
    935 				card_list = insert_io_card(card_list, &card);
    936 
    937 next_card:
    938 			/*
    939 			 * If we are done with the children of the pci bridge,
    940 			 * we must continue with the remaining siblings of
    941 			 * the pci-to-pci bridge - otherwise we move onto our
    942 			 * own sibling.
    943 			 */
    944 			if (pci_pci_bridge) {
    945 				if (card_node->child != NULL)
    946 					card_node = card_node->child;
    947 				else
    948 					card_node = card_node->sibling;
    949 			} else {
    950 				if ((card_node->parent == pci_bridge_node) &&
    951 				    (card_node->sibling == NULL))
    952 					card_node = pci_bridge_node->sibling;
    953 				else
    954 					card_node = card_node->sibling;
    955 			}
    956 		} /* end-while */
    957 	} /* end-for */
    958 
    959 	D_PRINTF("\n\n");
    960 
    961 	display_io_cards(card_list);
    962 	free_io_cards(card_list);
    963 }
    964 
    965 void
    966 get_slot_number_str(struct io_card *card, char **slot_name_arr,
    967 	int slot_name_bits)
    968 {
    969 	if (card->dev_no != -1) {
    970 		char	*slot;
    971 		/*
    972 		 * slot_name_bits is a mask of the plug-in slots so if our
    973 		 * dev_no does not appear in this mask we must be an
    974 		 * on_board device so set the slot to 'On-Board'
    975 		 */
    976 		if (slot_name_bits & (1 << card->dev_no)) {
    977 			/* we are a plug-in card */
    978 			slot = slot_name_arr[card->dev_no];
    979 			if (strlen(slot) != 0) {
    980 				(void) sprintf(card->slot_str, "%s",
    981 				    slot);
    982 			} else
    983 				(void) sprintf(card->slot_str, "-");
    984 		} else {
    985 			/* this is an on-board dev. */
    986 			sprintf(card->slot_str, "On-Board");
    987 		}
    988 
    989 	} else {
    990 		(void) sprintf(card->slot_str, "%c", '-');
    991 	}
    992 
    993 	/* Informs display_io_cards to print slot_str instead of slot */
    994 	card->slot = PCI_SLOT_IS_STRING;
    995 }
    996 
    997 
    998 /*
    999  * The output of a number of I/O cards are identical so we need to
   1000  * differentiate between them.
   1001  *
   1002  * This function is called by the platform specific code and it decides
   1003  * if the card needs further processing.
   1004  *
   1005  * It can be extended in the future if card types other than QLC have
   1006  * the same problems.
   1007  */
   1008 void
   1009 distinguish_identical_io_cards(char *name, Prom_node *node,
   1010 				struct io_card *card)
   1011 {
   1012 	if ((name == NULL) || (node == NULL))
   1013 		return;
   1014 
   1015 	if (strcmp(name, "SUNW,qlc") == 0)
   1016 		decode_qlc_card_model_prop(node, card);
   1017 }
   1018 
   1019 
   1020 /*
   1021  * The name/model properties for a number of the QLC FCAL PCI cards are
   1022  * identical (*), so we need to distinguish them using the subsystem-id
   1023  * and modify the model string to be more informative.
   1024  *
   1025  * (*) Currently the problem cards are:
   1026  *	Amber
   1027  *	Crystal+
   1028  */
   1029 void
   1030 decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card)
   1031 {
   1032 	void	*value = NULL;
   1033 
   1034 	if (card_node == NULL)
   1035 		return;
   1036 
   1037 	value = get_prop_val(find_prop(card_node, "subsystem-id"));
   1038 	if (value != NULL) {
   1039 		int	id = *(int *)value;
   1040 
   1041 		switch (id) {
   1042 		case AMBER_SUBSYSTEM_ID:
   1043 			(void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
   1044 				AMBER_CARD_NAME);
   1045 			break;
   1046 
   1047 		case CRYSTAL_SUBSYSTEM_ID:
   1048 			(void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
   1049 				CRYSTAL_CARD_NAME);
   1050 			break;
   1051 
   1052 		default:
   1053 			/*
   1054 			 * If information has been saved into the model field
   1055 			 * before this function was called we will keep it as
   1056 			 * it probably will be more meaningful that the
   1057 			 * subsystem-id, otherwise we save the subsystem-id in
   1058 			 * the hope that it will distinguish the cards.
   1059 			 */
   1060 			if (strcmp(card->model, "") == 0) {
   1061 				(void) snprintf(card->model, MAX_QLC_MODEL_LEN,
   1062 					"0x%x", id);
   1063 			}
   1064 			break;
   1065 		}
   1066 	}
   1067 }
   1068