xref: /onnv-gate/usr/src/cmd/biosdev/biosdev.c (revision 6640:c92ca9b95b9c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51782Sshidokht  * Common Development and Distribution License (the "License").
61782Sshidokht  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
225763Sgap  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <sys/param.h>
330Sstevel@tonic-gate #include <errno.h>
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <dirent.h>
360Sstevel@tonic-gate #include <libdevinfo.h>
370Sstevel@tonic-gate #include <fcntl.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/pci.h>
410Sstevel@tonic-gate #include <sys/biosdisk.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * structure used for searching device tree for a node matching
460Sstevel@tonic-gate  * pci bus/dev/fn
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate typedef struct pcibdf {
490Sstevel@tonic-gate 	int busnum;
500Sstevel@tonic-gate 	int devnum;
510Sstevel@tonic-gate 	int funcnum;
520Sstevel@tonic-gate 	di_node_t	di_node;
530Sstevel@tonic-gate } pcibdf_t;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * structure used for searching device tree for a node matching
570Sstevel@tonic-gate  * USB serial number.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate typedef struct {
600Sstevel@tonic-gate 	uint64_t serialno;
610Sstevel@tonic-gate 	di_node_t	node;
620Sstevel@tonic-gate } usbser_t;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  * structure for holding the mapping info
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate typedef struct {
680Sstevel@tonic-gate 	int disklist_index;	/* index to disk_list of the mapped path */
690Sstevel@tonic-gate 	int matchcount;		/* number of matches per this device number */
700Sstevel@tonic-gate } mapinfo_t;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #define	DEVFS_PREFIX "/devices"
730Sstevel@tonic-gate #define	DISKS_LIST_INCR		20	/* increment for resizing disk_list */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #define	BIOSPROPNAME_TMPL	"biosdev-0x%x"
760Sstevel@tonic-gate #define	BIOSPROPNAME_TMPL_LEN	13
770Sstevel@tonic-gate #define	BIOSDEV_NUM		8
780Sstevel@tonic-gate #define	STARTING_DRVNUM		0x80
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * array to hold mappings. Element at index X corresponds to BIOS device
820Sstevel@tonic-gate  * number 0x80 + X
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate static mapinfo_t mapinfo[BIOSDEV_NUM];
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /*
870Sstevel@tonic-gate  * Cache copy of kernel device tree snapshot root handle, includes devices
880Sstevel@tonic-gate  * that are detached
890Sstevel@tonic-gate  */
900Sstevel@tonic-gate static di_node_t root_node = DI_NODE_NIL;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * kernel device tree snapshot with currently attached devices. Detached
940Sstevel@tonic-gate  * devices are not included.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate static di_node_t root_allnode = DI_NODE_NIL;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * handle to retrieve prom properties
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static char **disk_list = NULL;	/* array of physical device pathnames */
1050Sstevel@tonic-gate static int disk_list_len = 0;		/* length of disk_list */
1060Sstevel@tonic-gate static int disk_list_valid = 0;	/* number of valid entries in disk_list */
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate static int debug = 0;			/* used for enabling debug output */
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /* Local function prototypes */
1120Sstevel@tonic-gate static void new_disk_list_entry(di_node_t node);
1131782Sshidokht static int i_disktype(di_node_t node, di_minor_t minor, void *arg);
1140Sstevel@tonic-gate static void build_disk_list();
1151782Sshidokht static int search_disklist_match_path(char *path);
1160Sstevel@tonic-gate static void free_disks();
1171782Sshidokht static void cleanup_and_exit(int);
1181782Sshidokht 
1190Sstevel@tonic-gate static int match_edd(biosdev_data_t *bd);
1200Sstevel@tonic-gate static int match_first_block(biosdev_data_t *bd);
1211782Sshidokht 
1221782Sshidokht static di_node_t search_tree_match_pcibdf(di_node_t node, int bus, int dev,
1231782Sshidokht     int fn);
1241782Sshidokht static int i_match_pcibdf(di_node_t node, void *arg);
1251782Sshidokht 
1261782Sshidokht static di_node_t search_tree_match_usbserialno(di_node_t node,
1271782Sshidokht     uint64_t serialno);
1281782Sshidokht static int i_match_usbserialno(di_node_t node, void *arg);
1291782Sshidokht 
1301782Sshidokht static di_node_t search_children_match_busaddr(di_node_t node,
1311782Sshidokht     char *matchbusaddr);
1321782Sshidokht 
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate static void
new_disk_list_entry(di_node_t node)1360Sstevel@tonic-gate new_disk_list_entry(di_node_t node)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	size_t	newsize;
1390Sstevel@tonic-gate 	char **newlist;
1400Sstevel@tonic-gate 	int newlen;
1410Sstevel@tonic-gate 	char *devfspath;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if (disk_list_valid >= disk_list_len)	{
1440Sstevel@tonic-gate 		/* valid should never really be larger than len */
1450Sstevel@tonic-gate 		/* if they are equal we need to init or realloc */
1460Sstevel@tonic-gate 		newlen = disk_list_len + DISKS_LIST_INCR;
1470Sstevel@tonic-gate 		newsize = newlen * sizeof (*disk_list);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 		newlist = (char **)realloc(disk_list, newsize);
1500Sstevel@tonic-gate 		if (newlist == NULL) {
1510Sstevel@tonic-gate 			(void) printf("realloc failed to resize disk table\n");
1520Sstevel@tonic-gate 			cleanup_and_exit(1);
1530Sstevel@tonic-gate 		}
1540Sstevel@tonic-gate 		disk_list = newlist;
1550Sstevel@tonic-gate 		disk_list_len = newlen;
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
1590Sstevel@tonic-gate 	disk_list[disk_list_valid] = devfspath;
1600Sstevel@tonic-gate 	if (debug)
1610Sstevel@tonic-gate 		(void) printf("adding %s\n", devfspath);
1620Sstevel@tonic-gate 	disk_list_valid++;
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /* ARGSUSED */
1660Sstevel@tonic-gate static int
i_disktype(di_node_t node,di_minor_t minor,void * arg)1671782Sshidokht i_disktype(di_node_t node, di_minor_t minor, void *arg)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	char *minortype;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	if (di_minor_spectype(minor) == S_IFCHR) {
1720Sstevel@tonic-gate 		minortype = di_minor_nodetype(minor);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 		/* exclude CD's */
1750Sstevel@tonic-gate 		if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0)
1760Sstevel@tonic-gate 			/* only take p0 raw device */
1770Sstevel@tonic-gate 			if (strcmp(di_minor_name(minor), "q,raw") == 0)
1780Sstevel@tonic-gate 				new_disk_list_entry(node);
1790Sstevel@tonic-gate 	}
1800Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static void
build_disk_list()1840Sstevel@tonic-gate build_disk_list()
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	int ret;
1870Sstevel@tonic-gate 	ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL,
1881782Sshidokht 	    i_disktype);
1890Sstevel@tonic-gate 	if (ret != 0) {
1900Sstevel@tonic-gate 		(void) fprintf(stderr, "di_walk_minor failed errno %d\n",
1910Sstevel@tonic-gate 		    errno);
1920Sstevel@tonic-gate 		cleanup_and_exit(1);
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate static void
free_disks()1970Sstevel@tonic-gate free_disks()
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate 	int i;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (disk_list) {
2020Sstevel@tonic-gate 		for (i = 0; i < disk_list_valid; i++)
2030Sstevel@tonic-gate 			di_devfs_path_free(disk_list[i]);
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 		free(disk_list);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate static int
i_match_pcibdf(di_node_t node,void * arg)2101782Sshidokht i_match_pcibdf(di_node_t node, void *arg)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	pcibdf_t *pbp;
2130Sstevel@tonic-gate 	int len;
2140Sstevel@tonic-gate 	uint32_t	regval;
2150Sstevel@tonic-gate 	uint32_t	busnum, funcnum, devicenum;
2160Sstevel@tonic-gate 	char *devtype;
2170Sstevel@tonic-gate 	uint32_t *regbuf = NULL;
2180Sstevel@tonic-gate 	di_node_t	parentnode;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	pbp = (pcibdf_t *)arg;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	parentnode = di_parent_node(node);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
2250Sstevel@tonic-gate 	    "device_type", (char **)&devtype);
2260Sstevel@tonic-gate 
227881Sjohnny 	if ((len <= 0) ||
228881Sjohnny 	    ((strcmp(devtype, "pci") != 0) && (strcmp(devtype, "pciex") != 0)))
2290Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg",
2320Sstevel@tonic-gate 	    (int **)&regbuf);
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	if (len <= 0) {
2350Sstevel@tonic-gate 		/* Try PROM property */
2360Sstevel@tonic-gate 		len = di_prom_prop_lookup_ints(prom_hdl, node, "reg",
2370Sstevel@tonic-gate 		    (int **)&regbuf);
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if (len > 0) {
2420Sstevel@tonic-gate 		regval = regbuf[0];
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		busnum = PCI_REG_BUS_G(regval);
2450Sstevel@tonic-gate 		devicenum = PCI_REG_DEV_G(regval);
2460Sstevel@tonic-gate 		funcnum = PCI_REG_FUNC_G(regval);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		if ((busnum == pbp->busnum) &&
2490Sstevel@tonic-gate 		    (devicenum == pbp->devnum) &&
2500Sstevel@tonic-gate 		    (funcnum == pbp->funcnum)) {
2510Sstevel@tonic-gate 			/* found it */
2520Sstevel@tonic-gate 			pbp->di_node = node;
2530Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
2540Sstevel@tonic-gate 		}
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate static di_node_t
search_tree_match_pcibdf(di_node_t node,int bus,int dev,int fn)2611782Sshidokht search_tree_match_pcibdf(di_node_t node, int bus, int dev, int fn)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate 	pcibdf_t pb;
2640Sstevel@tonic-gate 	pb.busnum = bus;
2650Sstevel@tonic-gate 	pb.devnum = dev;
2660Sstevel@tonic-gate 	pb.funcnum = fn;
2670Sstevel@tonic-gate 	pb.di_node = DI_NODE_NIL;
2680Sstevel@tonic-gate 
2691782Sshidokht 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &pb, i_match_pcibdf);
2700Sstevel@tonic-gate 	return (pb.di_node);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate static int
i_match_usbserialno(di_node_t node,void * arg)2751782Sshidokht i_match_usbserialno(di_node_t node, void *arg)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	int len;
2780Sstevel@tonic-gate 	char *serialp;
2790Sstevel@tonic-gate 	usbser_t *usbsp;
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	usbsp = (usbser_t *)arg;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno",
2841782Sshidokht 	    (uchar_t **)&serialp);
2850Sstevel@tonic-gate 
2861782Sshidokht 	if ((len > 0) && (strncmp((char *)&usbsp->serialno, serialp,
2871782Sshidokht 	    sizeof (uint64_t)) == 0)) {
2880Sstevel@tonic-gate 		usbsp->node = node;
2890Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate static di_node_t
search_tree_match_usbserialno(di_node_t node,uint64_t serialno)2951782Sshidokht search_tree_match_usbserialno(di_node_t node, uint64_t serialno)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	usbser_t usbs;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	usbs.serialno = serialno;
3010Sstevel@tonic-gate 	usbs.node = DI_NODE_NIL;
3020Sstevel@tonic-gate 
3031782Sshidokht 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, i_match_usbserialno);
3040Sstevel@tonic-gate 	return (usbs.node);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3071782Sshidokht /*
3081782Sshidokht  * returns the index to the disklist to the disk with matching path
3091782Sshidokht  */
3100Sstevel@tonic-gate static int
search_disklist_match_path(char * path)3111782Sshidokht search_disklist_match_path(char *path)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	int i;
3140Sstevel@tonic-gate 	for (i = 0; i < disk_list_valid; i++)
3150Sstevel@tonic-gate 		if (strcmp(disk_list[i], path) == 0) {
3160Sstevel@tonic-gate 			return (i);
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 	return (-1);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3211782Sshidokht /*
3221782Sshidokht  * Find first child of 'node' whose unit address is 'matchbusaddr'
3231782Sshidokht  */
3241782Sshidokht static di_node_t
search_children_match_busaddr(di_node_t node,char * matchbusaddr)3251782Sshidokht search_children_match_busaddr(di_node_t node, char *matchbusaddr)
3261782Sshidokht {
3271782Sshidokht 	di_node_t cnode;
3281782Sshidokht 	char *busaddr;
3295763Sgap 	di_path_t pi = DI_PATH_NIL;
3301782Sshidokht 
3311782Sshidokht 	if (matchbusaddr == NULL)
3321782Sshidokht 		return (DI_NODE_NIL);
3331782Sshidokht 
334*6640Scth 	while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) {
335*6640Scth 		busaddr = di_path_bus_addr(pi);
336*6640Scth 		if (busaddr == NULL)
337*6640Scth 			continue;
338*6640Scth 		if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
3395763Sgap 			return (di_path_client_node(pi));
340*6640Scth 	}
3411782Sshidokht 
3421782Sshidokht 	for (cnode = di_child_node(node); cnode != DI_NODE_NIL;
3431782Sshidokht 	    cnode = di_sibling_node(cnode)) {
3441782Sshidokht 		busaddr = di_bus_addr(cnode);
3451782Sshidokht 		if (busaddr == NULL)
3461782Sshidokht 			continue;
3471782Sshidokht 		if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
348*6640Scth 			return (cnode);
3491782Sshidokht 	}
350*6640Scth 
351*6640Scth 	return (DI_NODE_NIL);
3521782Sshidokht }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate  * Construct a physical device pathname from EDD and verify the
3560Sstevel@tonic-gate  * path exists. Return the index of in disk_list for the mapped
3570Sstevel@tonic-gate  * path on success, -1 on failure.
3580Sstevel@tonic-gate  */
3590Sstevel@tonic-gate static int
match_edd(biosdev_data_t * bdata)3600Sstevel@tonic-gate match_edd(biosdev_data_t *bdata)
3610Sstevel@tonic-gate {
3621782Sshidokht 	di_node_t node, cnode = DI_NODE_NIL;
3631782Sshidokht 	char *devfspath = NULL;
3640Sstevel@tonic-gate 	fn48_t *bd;
3650Sstevel@tonic-gate 	int index;
3661782Sshidokht 	char busaddrbuf[MAXNAMELEN];
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	if (!bdata->edd_valid) {
3690Sstevel@tonic-gate 		if (debug)
3700Sstevel@tonic-gate 			(void) printf("edd not valid\n");
3710Sstevel@tonic-gate 		return (-1);
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	bd = &bdata->fn48_dev_params;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) {
3770Sstevel@tonic-gate 		/* EDD extensions for devicepath not present */
3780Sstevel@tonic-gate 		if (debug)
3790Sstevel@tonic-gate 			(void) printf("magic not valid %x pathinfolen %d\n",
3800Sstevel@tonic-gate 			    bd->magic, bd->pathinfo_len);
3810Sstevel@tonic-gate 		return (-1);
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/* we handle only PCI scsi, ata or sata for now */
3850Sstevel@tonic-gate 	if (strncmp(bd->bustype, "PCI", 3) != 0) {
3860Sstevel@tonic-gate 		if (debug)
3870Sstevel@tonic-gate 			(void) printf("was not pci %s\n", bd->bustype);
3880Sstevel@tonic-gate 		return (-1);
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 	if (debug)
3910Sstevel@tonic-gate 		(void) printf("match_edd bdf %d %d %d\n",
3921782Sshidokht 		    bd->interfacepath.pci.bus,
3931782Sshidokht 		    bd->interfacepath.pci.device,
3941782Sshidokht 		    bd->interfacepath.pci.function);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* look into devinfo tree and find a node with matching pci b/d/f */
3971782Sshidokht 	node = search_tree_match_pcibdf(root_node, bd->interfacepath.pci.bus,
3981782Sshidokht 	    bd->interfacepath.pci.device, bd->interfacepath.pci.function);
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
4010Sstevel@tonic-gate 		if (debug)
4020Sstevel@tonic-gate 			(void) printf(" could not find a node in tree "
4030Sstevel@tonic-gate 			    "matching bdf\n");
4040Sstevel@tonic-gate 		return (-1);
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4075287Sshidokht 	if (debug) {
4085287Sshidokht 		int i;
4095287Sshidokht 		(void) printf("interface type ");
4105287Sshidokht 		for (i = 0; i < 8; i++)
4115287Sshidokht 			(void) printf("%c", bd->interface_type[i]);
4125287Sshidokht 		(void) printf(" pci channel %x target %x\n",
4135287Sshidokht 		    bd->interfacepath.pci.channel,
4141782Sshidokht 		    bd->devicepath.scsi.target);
4155287Sshidokht 	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	if (strncmp(bd->interface_type, "SCSI", 4) == 0) {
4180Sstevel@tonic-gate 
4191782Sshidokht 		(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,%x",
4200Sstevel@tonic-gate 		    bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo);
4210Sstevel@tonic-gate 
4221782Sshidokht 		cnode = search_children_match_busaddr(node, busaddrbuf);
4231782Sshidokht 
4241782Sshidokht 	} else if ((strncmp(bd->interface_type, "ATAPI", 5) == 0) ||
4251782Sshidokht 	    (strncmp(bd->interface_type, "ATA", 3) == 0) ||
4261782Sshidokht 	    (strncmp(bd->interface_type, "SATA", 4) == 0)) {
4270Sstevel@tonic-gate 
4281782Sshidokht 		if (strncmp(di_node_name(node), "pci-ide", 7) == 0) {
4291782Sshidokht 			/*
4301782Sshidokht 			 * Legacy using pci-ide
4311782Sshidokht 			 * the child should be ide@<x>, where x is
4321782Sshidokht 			 * the channel number
4331782Sshidokht 			 */
4341782Sshidokht 			(void) snprintf(busaddrbuf, MAXNAMELEN, "%d",
4351782Sshidokht 			    bd->interfacepath.pci.channel);
4360Sstevel@tonic-gate 
4371782Sshidokht 			if ((cnode = search_children_match_busaddr(node,
4381782Sshidokht 			    busaddrbuf)) != DI_NODE_NIL) {
4391782Sshidokht 
4401782Sshidokht 				(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
4411782Sshidokht 				    bd->devicepath.ata.chan);
4421782Sshidokht 				cnode = search_children_match_busaddr(cnode,
4431782Sshidokht 				    busaddrbuf);
4440Sstevel@tonic-gate 
4451782Sshidokht 				if (cnode == DI_NODE_NIL)
4461782Sshidokht 					if (debug)
4471782Sshidokht 						(void) printf("Interface %s "
4481782Sshidokht 						    "using pci-ide no "
4491782Sshidokht 						    "grandchild at %s\n",
4501782Sshidokht 						    bd->interface_type,
4511782Sshidokht 						    busaddrbuf);
4521782Sshidokht 			} else {
4531782Sshidokht 				if (debug)
4541782Sshidokht 					(void) printf("Interface %s using "
4551782Sshidokht 					    "pci-ide, with no child at %s\n",
4561782Sshidokht 					    bd->interface_type, busaddrbuf);
4571782Sshidokht 			}
4581782Sshidokht 		} else {
4591782Sshidokht 			if (strncmp(bd->interface_type, "SATA", 4) == 0) {
4601782Sshidokht 				/*
4611782Sshidokht 				 * The current EDD (EDD-2) spec does not
4621782Sshidokht 				 * address port number. This is work in
4631782Sshidokht 				 * progress.
4641782Sshidokht 				 * Interprete the first field of device path
4651782Sshidokht 				 * as port number. Needs to be revisited
4661782Sshidokht 				 * with port multiplier support.
4671782Sshidokht 				 */
4681782Sshidokht 				(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
4691782Sshidokht 				    bd->devicepath.ata.chan);
4700Sstevel@tonic-gate 
4711782Sshidokht 				cnode = search_children_match_busaddr(node,
4721782Sshidokht 				    busaddrbuf);
4731782Sshidokht 			} else {
4741782Sshidokht 				if (debug)
4751782Sshidokht 					(void) printf("Interface %s, not using"
4761782Sshidokht 					    " pci-ide\n", bd->interface_type);
4771782Sshidokht 			}
4781782Sshidokht 		}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	} else if (strncmp(bd->interface_type, "USB", 3) == 0) {
4811782Sshidokht 		cnode = search_tree_match_usbserialno(node,
4821782Sshidokht 		    bd->devicepath.usb.usb_serial_id);
4830Sstevel@tonic-gate 	} else {
4840Sstevel@tonic-gate 		if (debug)
4850Sstevel@tonic-gate 			(void) printf("sorry not supported interface %s\n",
4861782Sshidokht 			    bd->interface_type);
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 
4891782Sshidokht 	if (cnode != DI_NODE_NIL) {
4901782Sshidokht 		devfspath = di_devfs_path(cnode);
4911782Sshidokht 		index = search_disklist_match_path(devfspath);
4921782Sshidokht 		di_devfs_path_free(devfspath);
4931782Sshidokht 		if (index >= 0)
4941782Sshidokht 			return (index);
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	return (-1);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate /*
5010Sstevel@tonic-gate  * For each disk in list of disks, compare the first block with the
5020Sstevel@tonic-gate  * one from bdd. On the first match, return the index of path in
5030Sstevel@tonic-gate  * disk_list. If none matched return -1.
5040Sstevel@tonic-gate  */
5050Sstevel@tonic-gate static int
match_first_block(biosdev_data_t * bd)5060Sstevel@tonic-gate match_first_block(biosdev_data_t *bd)
5070Sstevel@tonic-gate {
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	char diskpath[MAXPATHLEN];
5100Sstevel@tonic-gate 	int fd;
5110Sstevel@tonic-gate 	char buf[512];
5120Sstevel@tonic-gate 	ssize_t	num_read;
5130Sstevel@tonic-gate 	int i;
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	if (!bd->first_block_valid)
5160Sstevel@tonic-gate 		return (-1);
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	for (i = 0; i < disk_list_valid; i++) {
5190Sstevel@tonic-gate 		(void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw",
5200Sstevel@tonic-gate 		    DEVFS_PREFIX, disk_list[i]);
5210Sstevel@tonic-gate 		fd = open(diskpath, O_RDONLY);
5220Sstevel@tonic-gate 		if (fd  < 0) {
5230Sstevel@tonic-gate 			(void) fprintf(stderr, "opening %s failed errno %d\n",
5240Sstevel@tonic-gate 			    diskpath, errno);
5250Sstevel@tonic-gate 			continue;
5260Sstevel@tonic-gate 		}
5270Sstevel@tonic-gate 		num_read = read(fd, buf, 512);
5280Sstevel@tonic-gate 		if (num_read != 512) {
5290Sstevel@tonic-gate 			(void) printf("read only %d bytes from %s\n", num_read,
5300Sstevel@tonic-gate 			    diskpath);
5310Sstevel@tonic-gate 			continue;
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		if (memcmp(buf, bd->first_block, 512) == 0)	 {
5350Sstevel@tonic-gate 			/* found it */
5360Sstevel@tonic-gate 			return (i);
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 	return (-1);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate static void
cleanup_and_exit(int exitcode)5440Sstevel@tonic-gate cleanup_and_exit(int exitcode)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	free_disks();
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if (root_node != DI_NODE_NIL)
5500Sstevel@tonic-gate 		di_fini(root_node);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	if (root_allnode != DI_NODE_NIL)
5530Sstevel@tonic-gate 		di_fini(root_allnode);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	if (prom_hdl != DI_PROM_HANDLE_NIL)
5560Sstevel@tonic-gate 		di_prom_fini(prom_hdl);
5570Sstevel@tonic-gate 	exit(exitcode);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate int
main(int argc,char * argv[])5630Sstevel@tonic-gate main(int argc, char *argv[])
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate 	biosdev_data_t		*biosdata;
5665287Sshidokht 	int i, c, j;
5670Sstevel@tonic-gate 	int matchedindex = -1;
5680Sstevel@tonic-gate 	char biospropname[BIOSPROPNAME_TMPL_LEN];
5690Sstevel@tonic-gate 	int totalmatches = 0;
5705287Sshidokht 	biosdev_data_t *biosdataarray[BIOSDEV_NUM];
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "d")) != -1)  {
5740Sstevel@tonic-gate 		switch (c) {
5750Sstevel@tonic-gate 		case 'd':
5760Sstevel@tonic-gate 			debug = 1;
5770Sstevel@tonic-gate 			break;
5780Sstevel@tonic-gate 		default:
5790Sstevel@tonic-gate 			(void) printf("unknown option %c\n", c);
5800Sstevel@tonic-gate 			exit(1);
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
5850Sstevel@tonic-gate 		(void) fprintf(stderr, "di_prom_init failed\n");
5860Sstevel@tonic-gate 		cleanup_and_exit(1);
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
5900Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init failed\n");
5910Sstevel@tonic-gate 		cleanup_and_exit(1);
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
5950Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init failed\n");
5960Sstevel@tonic-gate 		cleanup_and_exit(1);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	(void) memset(mapinfo, 0, sizeof (mapinfo));
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/* get a list of all disks in the system */
6020Sstevel@tonic-gate 	build_disk_list();
6030Sstevel@tonic-gate 
6045287Sshidokht 	/*  Get property values that were created at boot up time */
6050Sstevel@tonic-gate 	for (i = 0; i < BIOSDEV_NUM; i++) {
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		(void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN,
6080Sstevel@tonic-gate 		    BIOSPROPNAME_TMPL, i + STARTING_DRVNUM);
6095287Sshidokht 		if (di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode,
6105287Sshidokht 		    biospropname, (uchar_t **)&biosdataarray[i]) <= 0)
6115287Sshidokht 			biosdataarray[i] = NULL;
6125287Sshidokht 	}
6130Sstevel@tonic-gate 
6145287Sshidokht 	/* Try to match based on device/interface path info from BIOS */
6155287Sshidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
6165287Sshidokht 
6175287Sshidokht 		if ((biosdata = biosdataarray[i]) == NULL)
6180Sstevel@tonic-gate 			continue;
6190Sstevel@tonic-gate 		if (debug)
6205287Sshidokht 			(void) printf("matching edd 0x%x\n",
6215287Sshidokht 			    i + STARTING_DRVNUM);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		matchedindex = match_edd(biosdata);
6240Sstevel@tonic-gate 
6255287Sshidokht 		if (matchedindex != -1) {
6265287Sshidokht 			if (debug) {
6275287Sshidokht 				(void) printf("matched by edd\n");
6285287Sshidokht 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
6295287Sshidokht 				    disk_list[matchedindex]);
6305287Sshidokht 			}
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 			mapinfo[i].disklist_index = matchedindex;
6330Sstevel@tonic-gate 			mapinfo[i].matchcount++;
6345287Sshidokht 
6350Sstevel@tonic-gate 			for (j = 0; j < i; j++) {
6360Sstevel@tonic-gate 				if (mapinfo[j].matchcount > 0 &&
6370Sstevel@tonic-gate 				    mapinfo[j].disklist_index == matchedindex) {
6380Sstevel@tonic-gate 					mapinfo[j].matchcount++;
6390Sstevel@tonic-gate 					mapinfo[i].matchcount++;
6400Sstevel@tonic-gate 				}
6410Sstevel@tonic-gate 			}
6420Sstevel@tonic-gate 
6435287Sshidokht 		} else
6445287Sshidokht 			if (debug)
6455287Sshidokht 				(void) printf("No matches by edd\n");
6465287Sshidokht 	}
6475287Sshidokht 
6485287Sshidokht 	/*
6495287Sshidokht 	 * Go through the list and ignore any found matches that are dups.
6505287Sshidokht 	 * This is to workaround issues with BIOSes that do not implement
6515287Sshidokht 	 * providing interface/device path info correctly.
6525287Sshidokht 	 */
6535287Sshidokht 
6545287Sshidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
6555287Sshidokht 		if (mapinfo[i].matchcount > 1) {
6565287Sshidokht 			if (debug)
6575287Sshidokht 				(void) printf("Ignoring dup match_edd\n(count "
6585287Sshidokht 				    "%d): 0x%x %s\n", mapinfo[i].matchcount,
6595287Sshidokht 				    i + STARTING_DRVNUM,
6605287Sshidokht 				    disk_list[mapinfo[i].disklist_index]);
6615287Sshidokht 
6625287Sshidokht 			mapinfo[i].matchcount = 0;
6635287Sshidokht 			mapinfo[i].disklist_index = 0;
6645287Sshidokht 		}
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 
6675287Sshidokht 
6685287Sshidokht 	/*
6695287Sshidokht 	 * For each bios dev number that we do not have exactly one match
6705287Sshidokht 	 * already, try to match based on first block
6715287Sshidokht 	 */
6725287Sshidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
6735287Sshidokht 		if (mapinfo[i].matchcount == 1)
6745287Sshidokht 			continue;
6755287Sshidokht 
6765287Sshidokht 		if ((biosdata = biosdataarray[i]) == NULL)
6775287Sshidokht 			continue;
6785287Sshidokht 
6795287Sshidokht 		if (debug)
6805287Sshidokht 			(void) printf("matching first block 0x%x\n",
6815287Sshidokht 			    i + STARTING_DRVNUM);
6825287Sshidokht 
6835287Sshidokht 		matchedindex = match_first_block(biosdata);
6845287Sshidokht 		if (matchedindex != -1) {
6855287Sshidokht 			if (debug) {
6865287Sshidokht 				(void) printf("matched by first block\n");
6875287Sshidokht 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
6885287Sshidokht 				    disk_list[matchedindex]);
6895287Sshidokht 			}
6905287Sshidokht 
6915287Sshidokht 			mapinfo[i].disklist_index = matchedindex;
6925287Sshidokht 			mapinfo[i].matchcount++;
6935287Sshidokht 
6945287Sshidokht 			for (j = 0; j < i; j++) {
6955287Sshidokht 				if (mapinfo[j].matchcount > 0 &&
6965287Sshidokht 				    mapinfo[j].disklist_index == matchedindex) {
6975287Sshidokht 					mapinfo[j].matchcount++;
6985287Sshidokht 					mapinfo[i].matchcount++;
6995287Sshidokht 				}
7005287Sshidokht 			}
7015287Sshidokht 		} else
7025287Sshidokht 			if (debug) {
7035287Sshidokht 				(void) printf(" No matches by first block\n");
7045287Sshidokht 				(void) fprintf(stderr, "Could not match 0x%x\n",
7055287Sshidokht 				    i + STARTING_DRVNUM);
7065287Sshidokht 			}
7075287Sshidokht 	}
7085287Sshidokht 
7095287Sshidokht 
7100Sstevel@tonic-gate 	for (i = 0; i < BIOSDEV_NUM; i++) {
7110Sstevel@tonic-gate 		if (mapinfo[i].matchcount == 1) {
7120Sstevel@tonic-gate 			(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
7130Sstevel@tonic-gate 			    disk_list[mapinfo[i].disklist_index]);
7140Sstevel@tonic-gate 			totalmatches++;
7150Sstevel@tonic-gate 		} else if (debug && mapinfo[i].matchcount > 1) {
7160Sstevel@tonic-gate 			(void) printf("0x%x %s matchcount %d\n",
7170Sstevel@tonic-gate 			    i + STARTING_DRVNUM,
7180Sstevel@tonic-gate 			    disk_list[mapinfo[i].disklist_index],
7191782Sshidokht 			    mapinfo[i].matchcount);
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 	}
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (totalmatches == 0) {
7240Sstevel@tonic-gate 		(void) fprintf(stderr, "biosdev: Could not match any!!\n");
7250Sstevel@tonic-gate 		cleanup_and_exit(1);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	cleanup_and_exit(0);
7290Sstevel@tonic-gate 	/* NOTREACHED */
7300Sstevel@tonic-gate 	return (0);
7310Sstevel@tonic-gate }
732