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