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 (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 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * Opl platform specific PICL functions.
     26  *
     27  * 	called when :
     28  *	machine_type == MTYPE_OPL
     29  */
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <unistd.h>
     36 #include <kstat.h>
     37 #include <fcntl.h>
     38 #include <string.h>
     39 #include <assert.h>
     40 #include <libintl.h>
     41 #include <note.h>
     42 #include <dlfcn.h>
     43 #include <errno.h>
     44 #include <sys/systeminfo.h>
     45 #include <sys/openpromio.h>
     46 #include <sys/sysmacros.h>
     47 #include <picl.h>
     48 #include "picldefs.h"
     49 #include <pdevinfo.h>
     50 #include <display.h>
     51 #include <libprtdiag.h>
     52 #include <alloca.h>
     53 #include "opl_picl.h"
     54 #include <sys/pci.h>
     55 #include <sys/pci_tools.h>
     56 #include <sys/types.h>
     57 
     58 #if !defined(TEXT_DOMAIN)
     59 #define	TEXT_DOMAIN	"SYS_TEST"
     60 #endif
     61 
     62 static picl_errno_t do_walk(picl_nodehdl_t rooth, const char *classname,
     63     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args));
     64 static int opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
     65     picl_nodehdl_t *nodeh);
     66 static picl_errno_t get_lane_width(char *device_path, int bus_no, int func_no,
     67     int dev_no, int *actual, int *maximum, uint32_t *speed_max,
     68     uint32_t *speed_at, int *type);
     69 static int	opl_display_pci(int syserrlog, picl_nodehdl_t plafh);
     70 static picl_errno_t opl_pci_callback(picl_nodehdl_t pcih, void *args);
     71 static int opl_get_first_compatible_value(picl_nodehdl_t nodeh,
     72     char **outbuf);
     73 static int picldiag_get_clock_freq(picl_nodehdl_t modh,
     74     uint32_t *freq);
     75 static uint64_t picldiag_get_uint_propval(picl_nodehdl_t modh,
     76     char *prop_name, int *ret);
     77 static uint32_t	read_long(int fd, int bus, int dev, int func,
     78     int offset, int *ret);
     79 static uint8_t read_byte(int fd, int bus, int dev, int func, int offset,
     80     int *ret);
     81 static uint16_t read_word(int fd, int bus, int dev, int func, int offset,
     82     int *ret);
     83 
     84 
     85 /*
     86  * Collect I/O nodes information.
     87  */
     88 /* ARGSUSED */
     89 static picl_errno_t
     90 opl_pci_callback(picl_nodehdl_t pcih, void *args)
     91 {
     92 	picl_errno_t	err = PICL_SUCCESS;
     93 	picl_nodehdl_t	nodeh;
     94 	picl_prophdl_t  proph;
     95 	picl_propinfo_t pinfo;
     96 	char		path[MAXSTRLEN];
     97 	char		parent_path[MAXSTRLEN];
     98 	static char	root_path[MAXSTRLEN];
     99 	char		piclclass[PICL_CLASSNAMELEN_MAX];
    100 	char		name[MAXSTRLEN];
    101 	char		model[MAXSTRLEN];
    102 	char		*compatible;
    103 	char		binding_name[MAXSTRLEN];
    104 	struct io_card	pci_card;
    105 	char		status[6] = "N/A";
    106 	int		portid = PROP_INVALID;
    107 	int		*reg_val;
    108 	int		board = PROP_INVALID;
    109 	static int	saved_board = PROP_INVALID;
    110 	static int	saved_portid = PROP_INVALID;
    111 	int 		actual = PROP_INVALID, maximum = PROP_INVALID;
    112 	int 		bus_type;
    113 	int 		rev_id = PROP_INVALID, dev_id = PROP_INVALID;
    114 	int		ven_id = PROP_INVALID;
    115 	size_t		prop_size;
    116 
    117 	(void) memset(&pci_card, 0, sizeof (pci_card));
    118 
    119 	err = picl_get_propval_by_name(pcih, PICL_PROP_CLASSNAME,
    120 	    piclclass, sizeof (piclclass));
    121 
    122 	if (err !=  PICL_SUCCESS)
    123 		/* Do not proceed to parse this branch */
    124 		return (err);
    125 
    126 	if (!IS_PCI(piclclass))
    127 		/* Do not parse non-pci nodes */
    128 		return (PICL_INVALIDARG);
    129 
    130 	err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
    131 	    sizeof (parent_path));
    132 	if (err != PICL_SUCCESS)
    133 		/* Do not proceed to parse this branch */
    134 		return (err);
    135 	err = picl_get_propval_by_name(pcih, OBP_PROP_BOARD_NUM, &board,
    136 	    sizeof (board));
    137 
    138 	if (err == PICL_NORESPONSE)
    139 		/* Do not proceed to parse this branch */
    140 		return (err);
    141 	else if (err != PICL_PROPNOTFOUND) {
    142 		saved_board = board;
    143 		/* Save board node's pathname */
    144 		prop_size = sizeof (parent_path) + 1;
    145 		if (prop_size > MAXSTRLEN)
    146 			prop_size = MAXSTRLEN;
    147 		(void) strlcpy(root_path, parent_path, prop_size);
    148 	}
    149 
    150 	err = picl_get_propval_by_name
    151 	    (pcih, OBP_PROP_PORTID, &portid, sizeof (portid));
    152 
    153 	if (err != PICL_PROPNOTFOUND)
    154 		saved_portid = portid;
    155 
    156 	/* Walk through the children */
    157 
    158 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
    159 	    sizeof (picl_nodehdl_t));
    160 
    161 	while (err == PICL_SUCCESS) {
    162 		uint32_t	freq_max = 0, freq_at = 0;
    163 
    164 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
    165 		    piclclass, sizeof (piclclass));
    166 		if (err !=  PICL_SUCCESS)
    167 			/* Do not proceed to parse this node */
    168 			return (err);
    169 
    170 		if (IS_EBUS(piclclass)) {
    171 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
    172 			    &nodeh, sizeof (picl_nodehdl_t));
    173 			continue;
    174 		}
    175 
    176 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
    177 		    path, sizeof (path));
    178 		if (err != PICL_SUCCESS) {
    179 			/* Do not proceed to parse this node */
    180 			return (err);
    181 		}
    182 
    183 		prop_size = sizeof (path) + 1;
    184 		if (prop_size > MAXSTRLEN)
    185 			prop_size = MAXSTRLEN;
    186 		(void) strlcpy(pci_card.notes, path, prop_size);
    187 
    188 		pci_card.board = saved_board;
    189 		pci_card.schizo_portid = saved_portid;
    190 
    191 		/*
    192 		 * Get bus#, dev# and func# for this card from 'reg' property.
    193 		 */
    194 
    195 		err = picl_get_propinfo_by_name
    196 		    (nodeh, OBP_PROP_REG, &pinfo, &proph);
    197 		if (err == PICL_SUCCESS) {
    198 			/* All of the array of bytes of "reg" have to be read */
    199 			reg_val = malloc(pinfo.size);
    200 			if (reg_val == NULL)
    201 				return (PICL_FAILURE);
    202 
    203 
    204 			err = picl_get_propval_by_name
    205 			    (nodeh, OBP_PROP_REG, reg_val, pinfo.size);
    206 
    207 			if (err != PICL_SUCCESS) {
    208 				free(reg_val);
    209 				/* Do not proceed to parse this node */
    210 				return (err);
    211 			}
    212 
    213 			if (reg_val[0] != 0) {
    214 				pci_card.dev_no =
    215 				    (((reg_val[0]) & PCI_DEV_MASK) >> 11);
    216 				pci_card.func_no =
    217 				    (((reg_val[0]) & PCI_FUNC_MASK) >> 8);
    218 				pci_card.slot =
    219 				    (((reg_val[0]) & PCI_BUS_MASK) >> 16);
    220 			} else
    221 				free(reg_val);
    222 		}
    223 
    224 		err = get_lane_width(root_path, pci_card.slot, pci_card.dev_no,
    225 		    pci_card.func_no, &actual, &maximum, &freq_max, &freq_at,
    226 		    &bus_type);
    227 
    228 		if (err != PICL_SUCCESS) {
    229 			/*
    230 			 * get_lane_width will fail when run as non-root.
    231 			 * Set bus_type to PCI_UNKN so that bus frequency,
    232 			 * bus type and lane width will print as "--" or UNKN.
    233 			 */
    234 			bus_type = PCI_UNKN;
    235 		}
    236 
    237 
    238 		err = picl_get_propval_by_name
    239 		    (nodeh, PICL_PROP_NAME, name, sizeof (name));
    240 		if (err != PICL_SUCCESS)
    241 			(void) strcpy(name, "");
    242 
    243 		/*
    244 		 * Get the name of this card. If binding_name is found,
    245 		 * name will be <nodename>-<binding_name>
    246 		 */
    247 
    248 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
    249 		    binding_name, sizeof (binding_name));
    250 		if (err == PICL_PROPNOTFOUND) {
    251 			/*
    252 			 * if compatible prop is found, name will be
    253 			 * <nodename>-<compatible>
    254 			 */
    255 			err = opl_get_first_compatible_value(nodeh,
    256 			    &compatible);
    257 			if (err == PICL_SUCCESS) {
    258 				(void) strlcat(name, "-", MAXSTRLEN);
    259 				(void) strlcat(name, compatible, MAXSTRLEN);
    260 				free(compatible);
    261 			}
    262 		} else if (err != PICL_SUCCESS) {
    263 			/* No binding-name or compatible */
    264 			(void) strcpy(binding_name, "N/A");
    265 		} else if (strcmp(name, binding_name) != 0) {
    266 			(void) strlcat(name, "-", MAXSTRLEN);
    267 			(void) strlcat(name, binding_name, MAXSTRLEN);
    268 		}
    269 
    270 
    271 		prop_size = sizeof (name) + 1;
    272 		if (prop_size > MAXSTRLEN)
    273 			prop_size =  MAXSTRLEN;
    274 		(void) strlcpy(pci_card.name, name, prop_size);
    275 
    276 		/* Get the status of the card */
    277 		err = picl_get_propval_by_name
    278 		    (nodeh, PICL_PROP_STATUS, status, sizeof (status));
    279 
    280 
    281 		/* Get the model of this card */
    282 
    283 		err = picl_get_propval_by_name
    284 		    (nodeh, OBP_PROP_MODEL, model, sizeof (model));
    285 		prop_size = sizeof (model) + 1;
    286 		if (prop_size > MAXSTRLEN)
    287 			prop_size =  MAXSTRLEN;
    288 		if (err != PICL_SUCCESS)
    289 			(void) strcpy(model, "N/A");
    290 		(void) strlcpy(pci_card.model, model, prop_size);
    291 
    292 		if (bus_type == PCI)
    293 			(void) strlcpy(pci_card.bus_type,
    294 			    "PCI", sizeof (pci_card.bus_type));
    295 		else if (bus_type == PCIX)
    296 			(void) strlcpy(pci_card.bus_type,
    297 			    "PCIx", sizeof (pci_card.bus_type));
    298 		else if (bus_type == PCIE)
    299 			(void) strlcpy(pci_card.bus_type,
    300 			    "PCIe", sizeof (pci_card.bus_type));
    301 		else
    302 			(void) strlcpy(pci_card.bus_type,
    303 			    "UNKN", sizeof (pci_card.bus_type));
    304 
    305 		/* Get revision id */
    306 		err = picl_get_propval_by_name
    307 		    (nodeh, OBP_PROP_REVISION_ID, &rev_id, sizeof (rev_id));
    308 
    309 		/* Get device id */
    310 		err = picl_get_propval_by_name
    311 		    (nodeh, OBP_PROP_DEVICE_ID, &dev_id, sizeof (dev_id));
    312 
    313 		/* Get vendor id */
    314 		err = picl_get_propval_by_name
    315 		    (nodeh, OBP_PROP_VENDOR_ID, &ven_id, sizeof (ven_id));
    316 
    317 		/*
    318 		 * prtdiag -v prints all devices
    319 		 */
    320 
    321 		/* Print board number */
    322 		log_printf("%02d  ", pci_card.board);
    323 		/* Print IO Type */
    324 		log_printf("%-5.5s ", pci_card.bus_type);
    325 
    326 		log_printf("%-3d  ", pci_card.schizo_portid);
    327 		log_printf("%4x, %4x, %4x     ", rev_id, dev_id, ven_id);
    328 
    329 		log_printf("%3d, %2d, %2d",
    330 		    pci_card.slot, pci_card.dev_no, pci_card.func_no);
    331 
    332 		/* Print status */
    333 		log_printf("  %-5.5s ", status);
    334 
    335 		/* Print Lane widths, Max/Sup Freq, Speed */
    336 		if (bus_type == PCIE) {
    337 			PRINT_FMT(actual, maximum);
    338 		} else if (bus_type == PCIX) {
    339 			PRINT_FREQ_FMT(freq_at, freq_max);
    340 		} else if (bus_type == PCI) {
    341 			err = picldiag_get_clock_freq(nodeh, &freq_at);
    342 			PRINT_FREQ_FMT(freq_at, freq_max);
    343 		} else
    344 			log_printf(" -- , --   ");
    345 
    346 		/* Print Card Name */
    347 		log_printf("%-30.30s", pci_card.name);
    348 
    349 		/* Print Card Model */
    350 		log_printf(" %-20.20s", pci_card.model);
    351 
    352 		log_printf("\n");
    353 
    354 		log_printf("%4s%-100.100s", " ", pci_card.notes);
    355 		log_printf("\n");
    356 		log_printf("\n");
    357 
    358 
    359 		err = picl_get_propval_by_name
    360 		    (nodeh, PICL_PROP_PEER, &nodeh, sizeof (picl_nodehdl_t));
    361 
    362 	}
    363 
    364 	return (PICL_WALK_CONTINUE);
    365 }
    366 
    367 /*
    368  * opl_display_pci
    369  * Display all the PCI IO cards on this board.
    370  */
    371 static int
    372 opl_display_pci(int syserrlog, picl_nodehdl_t plafh)
    373 {
    374 	picl_errno_t err;
    375 	char	*fmt = "%-3s %-5s %-4s %-20s %-11s %-5s %-11s %-30s %-20s";
    376 	char 	*fmt2 = "%-16s";
    377 	static int banner = FALSE; /* Have we printed the column headings? */
    378 
    379 	if (banner == FALSE) {
    380 		log_printf("\n", 0);
    381 		log_printf("=========================", 0);
    382 		log_printf(dgettext(TEXT_DOMAIN, " IO Devices "), 0);
    383 		log_printf("=========================", 0);
    384 		log_printf("\n", 0);
    385 		log_printf("\n", 0);
    386 		log_printf(fmt, "", "IO", "", "", "", "", "Lane/Frq",
    387 		    "", "", 0);
    388 		log_printf("\n", 0);
    389 
    390 		log_printf(fmt, "LSB", "Type", "LPID", "  RvID,DvID,VnID",
    391 		    "  BDF", "State", "Act,  Max", "Name", "Model", 0);
    392 
    393 		log_printf("\n");
    394 
    395 		log_printf(fmt,
    396 		    "---", "-----", "----", "  ------------------",
    397 		    "  ---------", "-----", "-----------",
    398 		    "------------------------------",
    399 		    "--------------------", 0);
    400 		log_printf("\n");
    401 		log_printf(fmt2, "    Logical Path");
    402 		log_printf("\n");
    403 		log_printf(fmt2, "    ------------");
    404 		log_printf("\n");
    405 		banner = TRUE;
    406 	}
    407 
    408 	err = do_walk(plafh, PICL_CLASS_PCI, PICL_CLASS_PCI, opl_pci_callback);
    409 	return (err);
    410 }
    411 
    412 
    413 /*
    414  * return the first compatible value
    415  */
    416 static int
    417 opl_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
    418 {
    419 	picl_errno_t	err;
    420 	picl_prophdl_t	proph;
    421 	picl_propinfo_t	pinfo;
    422 	picl_prophdl_t	tblh;
    423 	picl_prophdl_t	rowproph;
    424 	char		*pval;
    425 
    426 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
    427 	    &pinfo, &proph);
    428 	if (err != PICL_SUCCESS)
    429 		return (err);
    430 
    431 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
    432 		pval = malloc(pinfo.size);
    433 		if (pval == NULL)
    434 			return (PICL_FAILURE);
    435 		err = picl_get_propval(proph, pval, pinfo.size);
    436 		if (err != PICL_SUCCESS) {
    437 			free(pval);
    438 			return (err);
    439 		}
    440 		*outbuf = pval;
    441 		return (PICL_SUCCESS);
    442 	}
    443 
    444 	if (pinfo.type != PICL_PTYPE_TABLE)
    445 		return (PICL_FAILURE);
    446 
    447 	/* get first string from table */
    448 	err = picl_get_propval(proph, &tblh, pinfo.size);
    449 	if (err != PICL_SUCCESS)
    450 		return (err);
    451 
    452 	err = picl_get_next_by_row(tblh, &rowproph);
    453 	if (err != PICL_SUCCESS)
    454 		return (err);
    455 
    456 	err = picl_get_propinfo(rowproph, &pinfo);
    457 	if (err != PICL_SUCCESS)
    458 		return (err);
    459 
    460 	pval = malloc(pinfo.size);
    461 	if (pval == NULL)
    462 		return (PICL_FAILURE);
    463 
    464 	err = picl_get_propval(rowproph, pval, pinfo.size);
    465 	if (err != PICL_SUCCESS) {
    466 		free(pval);
    467 		return (err);
    468 	}
    469 
    470 	*outbuf = pval;
    471 	return (PICL_SUCCESS);
    472 }
    473 
    474 int
    475 do_piclinfo(int syserrlog)
    476 {
    477 	picl_nodehdl_t rooth;		/* root PICL node for IO display */
    478 	picl_nodehdl_t plafh;		/* Platform PICL node for IO display */
    479 
    480 	picl_errno_t err;
    481 
    482 	err = picl_initialize();
    483 	if (err != PICL_SUCCESS) {
    484 		(void) log_printf("picl_initialize failed: %s\n",
    485 		    picl_strerror(err));
    486 		return (err);
    487 	}
    488 
    489 
    490 	err = picl_get_root(&rooth);
    491 	if (err != PICL_SUCCESS) {
    492 		(void) log_printf("Getting root node failed: %s\n",
    493 		    picl_strerror(err));
    494 		return (err);
    495 	}
    496 
    497 	err = opl_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
    498 
    499 	if (err != PICL_SUCCESS) {
    500 		(void) log_printf("Getting nodes by name failed: %s\n",
    501 		    picl_strerror(err));
    502 		return (err);
    503 	}
    504 
    505 	err = opl_display_pci(syserrlog, plafh);
    506 
    507 	(void) picl_shutdown();
    508 
    509 	return (err);
    510 }
    511 
    512 /*
    513  * search children to get the node by the nodename
    514  */
    515 static int
    516 opl_get_node_by_name(picl_nodehdl_t rooth, char *name,
    517     picl_nodehdl_t *nodeh)
    518 {
    519 	picl_nodehdl_t	childh;
    520 	int		err;
    521 	char		*nodename;
    522 
    523 	nodename = alloca(strlen(name) + 1);
    524 	if (nodename == NULL)
    525 		return (PICL_FAILURE);
    526 
    527 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
    528 	    sizeof (picl_nodehdl_t));
    529 
    530 	while (err == PICL_SUCCESS) {
    531 		err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
    532 		    nodename, (strlen(name) + 1));
    533 		if (err != PICL_SUCCESS) {
    534 			err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
    535 			    &childh, sizeof (picl_nodehdl_t));
    536 			continue;
    537 		}
    538 
    539 		if (strcmp(nodename, name) == 0) {
    540 			*nodeh = childh;
    541 			return (PICL_SUCCESS);
    542 		}
    543 
    544 		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
    545 		    &childh, sizeof (picl_nodehdl_t));
    546 	}
    547 
    548 	return (err);
    549 }
    550 
    551 static int
    552 open_root_complex(char *root_complex)
    553 {
    554 	char *path;
    555 	static char device_str[] = {"/devices"};
    556 	static char devctl_str[] = {":reg"};
    557 	int fd;
    558 
    559 	path = malloc(
    560 	    strlen(root_complex) + sizeof (device_str) + sizeof (devctl_str));
    561 	if (path == NULL)
    562 		return (PICL_FAILURE);
    563 	(void) strcpy(path, device_str);
    564 	(void) strcat(path, root_complex);
    565 	(void) strcat(path, devctl_str);
    566 
    567 	if ((fd = open(path, O_RDWR)) == -1) {
    568 		return (-1);
    569 	}
    570 	return (fd);
    571 }
    572 
    573 static uint32_t
    574 read_long(int fd, int bus, int dev, int func, int offset, int *ret)
    575 {
    576 	int rval;
    577 	pcitool_reg_t prg;
    578 
    579 	prg.user_version = PCITOOL_VERSION;
    580 	prg.barnum = 0;
    581 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_4 +
    582 	    PCITOOL_ACC_ATTR_ENDN_LTL;
    583 	prg.bus_no = bus;
    584 	prg.dev_no = dev;
    585 	prg.func_no = func;
    586 	prg.offset = offset;
    587 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
    588 	if (rval != 0) {
    589 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
    590 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
    591 	}
    592 	*ret = rval;
    593 	return ((uint32_t)prg.data);
    594 }
    595 
    596 static uint16_t
    597 read_word(int fd, int bus, int dev, int func, int offset, int *ret)
    598 {
    599 	int rval;
    600 	pcitool_reg_t prg;
    601 
    602 	prg.user_version = PCITOOL_VERSION;
    603 	prg.barnum = 0;
    604 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_2 +
    605 	    PCITOOL_ACC_ATTR_ENDN_LTL;
    606 	prg.bus_no = bus;
    607 	prg.dev_no = dev;
    608 	prg.func_no = func;
    609 	prg.offset = offset;
    610 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
    611 	if (rval != 0) {
    612 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
    613 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
    614 	}
    615 	*ret = rval;
    616 	return ((uint16_t)prg.data);
    617 }
    618 
    619 static uint8_t
    620 read_byte(int fd, int bus, int dev, int func, int offset, int *ret)
    621 {
    622 	int rval;
    623 	pcitool_reg_t prg;
    624 
    625 	prg.user_version = PCITOOL_VERSION;
    626 	prg.barnum = 0;
    627 	prg.acc_attr = PCITOOL_ACC_ATTR_SIZE_1 +
    628 	    PCITOOL_ACC_ATTR_ENDN_LTL;
    629 	prg.bus_no = bus;
    630 	prg.dev_no = dev;
    631 	prg.func_no = func;
    632 	prg.offset = offset;
    633 	rval = ioctl(fd, PCITOOL_DEVICE_GET_REG, &prg);
    634 	if (rval != 0) {
    635 		log_printf("DEV_GET failed %d %s\n", rval, strerror(errno));
    636 		log_printf("%d.%d.%d offset 0x%x\n", bus, dev, func, offset);
    637 	}
    638 	*ret = rval;
    639 	return ((uint8_t)prg.data);
    640 }
    641 
    642 
    643 static picl_errno_t
    644 get_lane_width
    645 	(char *device_path, int bus, int dev, int func, int *actual,
    646 	int *maximum, uint32_t *speed_max, uint32_t *speed_at, int *type)
    647 {
    648 	uint_t cap_ptr, cap_reg, link_status, link_cap, capid;
    649 	int fd, ret;
    650 
    651 	if (device_path == NULL)
    652 		return (PICL_FAILURE);
    653 
    654 	fd = open_root_complex(device_path);
    655 	if (fd == -1)
    656 		return (PICL_FAILURE);
    657 
    658 	/*
    659 	 * Link Capabilities and Link Status registers are in the
    660 	 * PCI-E capabilities register.  They are at offset
    661 	 * 0xc and 0x12 respectively. They are documented in section
    662 	 * 7.8 of the PCI Express Base Specification. The address of
    663 	 * that structure is not fixed, it's kind of a linked list.
    664 	 * The Capabilities Pointer reg (8 bits) is always at 0x34.
    665 	 * It contains a pointer to the first capabilities structure.
    666 	 * For each capability structure, the first 8 bits is the capability
    667 	 * ID. The next 8 bits is the pointer to the next structure.
    668 	 * If the Next Cap register is zero, it's the end of the list.
    669 	 * The capability ID for the PCI-E strucutre is 0x10.  The idea
    670 	 * is to follow the links until you find a Cap ID of 0x10, then
    671 	 * read the registers at 0xc and 0x12 from there.
    672 	 * If there's no Cap ID 0x10, then it's not a PCI-E device.
    673 	 */
    674 
    675 	cap_ptr = read_byte(fd, bus, dev, func, PCI_CONF_CAP_PTR, &ret);
    676 	if (ret != 0) {
    677 		/* ioctl failure */
    678 		close(fd);
    679 		return (PICL_FAILURE);
    680 	}
    681 	cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
    682 	if (ret != 0) {
    683 		/* ioctl failure */
    684 		close(fd);
    685 		return (PICL_FAILURE);
    686 	}
    687 	*type = PCI;
    688 	capid = cap_reg & PCI_CAP_MASK;
    689 	while (cap_ptr != 0) {
    690 
    691 		if (capid == PCI_CAP_ID_PCI_E) {
    692 			link_cap = read_long(fd, bus, dev, func, cap_ptr +
    693 			    PCIE_LINKCAP, &ret);
    694 			if (ret != 0) {
    695 				close(fd);
    696 				return (PICL_FAILURE);
    697 			}
    698 			link_status = read_word(fd, bus, dev, func,
    699 			    cap_ptr + PCIE_LINKSTS, &ret);
    700 			if (ret != 0) {
    701 				close(fd);
    702 				return (PICL_FAILURE);
    703 			}
    704 			*actual = ((link_status >> PCI_LINK_SHIFT) &
    705 			    PCI_LINK_MASK);
    706 			*maximum = ((link_cap >> PCI_LINK_SHIFT) &
    707 			    PCI_LINK_MASK);
    708 			*type = PCIE;
    709 		} else if (capid == PCI_CAP_ID_PCIX) {
    710 			uint32_t pcix_status;
    711 			uint8_t hdr_type;
    712 			int max_speed = PCI_FREQ_66;
    713 
    714 			hdr_type = read_byte
    715 			    (fd, bus, dev, func, PCI_CONF_HEADER, &ret);
    716 			if (ret != 0) {
    717 				/* ioctl failure */
    718 				close(fd);
    719 				return (PICL_FAILURE);
    720 			}
    721 			*type = PCIX;
    722 			if ((hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
    723 				/* This is a PCI-X bridge */
    724 				uint16_t sec_status, mode;
    725 				sec_status = read_word(fd, bus, dev, func,
    726 				    cap_ptr + PCI_PCIX_SEC_STATUS, &ret);
    727 				if (ret != 0) {
    728 					/* ioctl failure */
    729 					close(fd);
    730 					return (PICL_FAILURE);
    731 				}
    732 				if (sec_status & PCI_SEC_133)
    733 					max_speed = PCI_FREQ_133;
    734 				if (sec_status & PCI_SEC_266)
    735 					max_speed = PCI_FREQ_266;
    736 				if (sec_status & PCI_SEC_533)
    737 					max_speed = PCI_FREQ_533;
    738 				*speed_max = max_speed;
    739 				mode = (sec_status >> PCI_CLASS_BRIDGE) &
    740 				    PCI_BRIDGE_MC;
    741 				if (mode) {
    742 					int speed;
    743 					if (mode == PCI_MODE_66)
    744 						speed = PCI_FREQ_66;
    745 					else if (mode == PCI_MODE_100)
    746 						speed = PCI_FREQ_100;
    747 					else if (mode == PCI_MODE_133)
    748 						speed = PCI_FREQ_133;
    749 					*speed_at = speed;
    750 				}
    751 
    752 			} else {  /* Leaf device */
    753 				pcix_status = read_long(fd, bus, dev, func,
    754 				    cap_ptr + PCI_PCIX_STATUS, &ret);
    755 				if (ret != 0) {
    756 					/* ioctl failure */
    757 					close(fd);
    758 					return (PICL_FAILURE);
    759 				}
    760 				if (pcix_status &
    761 				    (PCI_LEAF_ULONG << PCI_SHIFT_133))
    762 					max_speed = PCI_FREQ_133;
    763 				if (pcix_status &
    764 				    (PCI_LEAF_ULONG << PCI_SHIFT_266))
    765 					max_speed = PCI_FREQ_266;
    766 				if (pcix_status &
    767 				    (PCI_LEAF_ULONG << PCI_SHIFT_533))
    768 					max_speed = PCI_FREQ_533;
    769 				*speed_max = max_speed;
    770 			}
    771 		}
    772 		cap_ptr = (cap_reg >> PCI_REG_FUNC_SHIFT);
    773 		cap_reg = read_word(fd, bus, dev, func, cap_ptr, &ret);
    774 		if (ret != 0) {
    775 			/* ioctl failure */
    776 			close(fd);
    777 			return (PICL_FAILURE);
    778 		}
    779 		capid = cap_reg & PCI_CAP_MASK;
    780 	}
    781 
    782 	if (close(fd) == -1) {
    783 		return (PICL_FAILURE);
    784 	}
    785 
    786 	return (PICL_SUCCESS);
    787 }
    788 
    789 /*
    790  * get the clock frequency
    791  */
    792 static int
    793 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
    794 {
    795 	int		err;
    796 	uint64_t	clk_freq;
    797 
    798 	clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
    799 	if (err != PICL_SUCCESS)
    800 		return (err);
    801 
    802 	*freq = ROUND_TO_MHZ(clk_freq);
    803 
    804 	return (PICL_SUCCESS);
    805 }
    806 
    807 static uint64_t
    808 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
    809 {
    810 	int		err;
    811 	picl_prophdl_t	proph;
    812 	picl_propinfo_t pinfo;
    813 	uint8_t		uint8v;
    814 	uint16_t	uint16v;
    815 	uint32_t	uint32v;
    816 	uint64_t	uint64v;
    817 
    818 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
    819 	if (err != PICL_SUCCESS) {
    820 		*ret = err;
    821 		return (0);
    822 	}
    823 
    824 	/*
    825 	 * If it is not an int or uint prop, return failure
    826 	 */
    827 	if ((pinfo.type != PICL_PTYPE_INT) &&
    828 	    (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
    829 		*ret = PICL_FAILURE;
    830 		return (0);
    831 	}
    832 
    833 
    834 	/* uint prop */
    835 
    836 	switch (pinfo.size) {
    837 	case sizeof (uint8_t):
    838 		err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
    839 		*ret = err;
    840 		return (uint8v);
    841 	case sizeof (uint16_t):
    842 		err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
    843 		*ret = err;
    844 		return (uint16v);
    845 	case sizeof (uint32_t):
    846 		err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
    847 		*ret = err;
    848 		return (uint32v);
    849 	case sizeof (uint64_t):
    850 		err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
    851 		*ret = err;
    852 		return (uint64v);
    853 	default:	/* not supported size */
    854 		*ret = PICL_FAILURE;
    855 		return (0);
    856 	}
    857 }
    858 
    859 /*
    860  * recursively visit all nodes
    861  */
    862 static picl_errno_t
    863 do_walk(picl_nodehdl_t rooth, const char *classname,
    864     void *c_args, picl_errno_t (*callback_fn)(picl_nodehdl_t hdl, void *args))
    865 {
    866 	picl_errno_t	err;
    867 	picl_nodehdl_t  chdh;
    868 	char		classval[PICL_CLASSNAMELEN_MAX];
    869 
    870 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &chdh,
    871 	    sizeof (chdh));
    872 	while (err == PICL_SUCCESS) {
    873 		err = picl_get_propval_by_name(chdh, PICL_PROP_NAME,
    874 		    classval, sizeof (classval));
    875 		if (err != PICL_SUCCESS)
    876 			return (err);
    877 
    878 		err = callback_fn(chdh, c_args);
    879 
    880 		if ((err = do_walk(chdh, classname, c_args, callback_fn)) !=
    881 		    PICL_WALK_CONTINUE)
    882 			return (err);
    883 
    884 		err = picl_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
    885 		    sizeof (chdh));
    886 	}
    887 	if (err == PICL_PROPNOTFOUND)   /* end of a branch */
    888 		return (PICL_WALK_CONTINUE);
    889 	return (err);
    890 }
    891 
    892 int
    893 get_proc_mode(void)
    894 {
    895 	picl_nodehdl_t nodeh;
    896 	picl_prophdl_t  proph;
    897 	picl_errno_t err;
    898 
    899 	err = picl_initialize();
    900 	if (err != PICL_SUCCESS) {
    901 		(void) log_printf("picl_initialize failed: %s\n",
    902 		    picl_strerror(err));
    903 		return (err);
    904 	}
    905 
    906 	err = picl_get_node_by_path("/platform",  &nodeh);
    907 	if (err != PICL_SUCCESS) {
    908 		(void) log_printf("Getting plat node failed: %s\n",
    909 		    picl_strerror(err));
    910 		return (err);
    911 	}
    912 
    913 	err = picl_get_prop_by_name(nodeh, "SPARC64-VII-mode",  &proph);
    914 	if (err != PICL_SUCCESS) {
    915 		/* Do not display error message */
    916 		return (err);
    917 	}
    918 
    919 	(void) picl_shutdown();
    920 
    921 	return (err);
    922 }
    923