xref: /illumos-gate/usr/src/cmd/biosdev/biosdev.c (revision 2a8bcb4e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d155f3feSshidokht  * Common Development and Distribution License (the "License").
6d155f3feSshidokht  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2244d788f4Sgap  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <unistd.h>
307c478bd9Sstevel@tonic-gate #include <sys/param.h>
317c478bd9Sstevel@tonic-gate #include <errno.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <dirent.h>
347c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <sys/pci.h>
397c478bd9Sstevel@tonic-gate #include <sys/biosdisk.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * structure used for searching device tree for a node matching
447c478bd9Sstevel@tonic-gate  * pci bus/dev/fn
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate typedef struct pcibdf {
477c478bd9Sstevel@tonic-gate 	int busnum;
487c478bd9Sstevel@tonic-gate 	int devnum;
497c478bd9Sstevel@tonic-gate 	int funcnum;
507c478bd9Sstevel@tonic-gate 	di_node_t	di_node;
517c478bd9Sstevel@tonic-gate } pcibdf_t;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * structure used for searching device tree for a node matching
557c478bd9Sstevel@tonic-gate  * USB serial number.
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate typedef struct {
587c478bd9Sstevel@tonic-gate 	uint64_t serialno;
597c478bd9Sstevel@tonic-gate 	di_node_t	node;
607c478bd9Sstevel@tonic-gate } usbser_t;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  * structure for holding the mapping info
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate typedef struct {
667c478bd9Sstevel@tonic-gate 	int disklist_index;	/* index to disk_list of the mapped path */
677c478bd9Sstevel@tonic-gate 	int matchcount;		/* number of matches per this device number */
687c478bd9Sstevel@tonic-gate } mapinfo_t;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	DEVFS_PREFIX "/devices"
717c478bd9Sstevel@tonic-gate #define	DISKS_LIST_INCR		20	/* increment for resizing disk_list */
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	BIOSPROPNAME_TMPL	"biosdev-0x%x"
747c478bd9Sstevel@tonic-gate #define	BIOSPROPNAME_TMPL_LEN	13
757c478bd9Sstevel@tonic-gate #define	BIOSDEV_NUM		8
767c478bd9Sstevel@tonic-gate #define	STARTING_DRVNUM		0x80
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * array to hold mappings. Element at index X corresponds to BIOS device
807c478bd9Sstevel@tonic-gate  * number 0x80 + X
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate static mapinfo_t mapinfo[BIOSDEV_NUM];
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * Cache copy of kernel device tree snapshot root handle, includes devices
867c478bd9Sstevel@tonic-gate  * that are detached
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate static di_node_t root_node = DI_NODE_NIL;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * kernel device tree snapshot with currently attached devices. Detached
927c478bd9Sstevel@tonic-gate  * devices are not included.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate static di_node_t root_allnode = DI_NODE_NIL;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * handle to retrieve prom properties
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static char **disk_list = NULL;	/* array of physical device pathnames */
1037c478bd9Sstevel@tonic-gate static int disk_list_len = 0;		/* length of disk_list */
1047c478bd9Sstevel@tonic-gate static int disk_list_valid = 0;	/* number of valid entries in disk_list */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static int debug = 0;			/* used for enabling debug output */
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /* Local function prototypes */
1107c478bd9Sstevel@tonic-gate static void new_disk_list_entry(di_node_t node);
111d155f3feSshidokht static int i_disktype(di_node_t node, di_minor_t minor, void *arg);
1127c478bd9Sstevel@tonic-gate static void build_disk_list();
113d155f3feSshidokht static int search_disklist_match_path(char *path);
1147c478bd9Sstevel@tonic-gate static void free_disks();
115d155f3feSshidokht static void cleanup_and_exit(int);
116d155f3feSshidokht 
1177c478bd9Sstevel@tonic-gate static int match_edd(biosdev_data_t *bd);
1187c478bd9Sstevel@tonic-gate static int match_first_block(biosdev_data_t *bd);
119d155f3feSshidokht 
120d155f3feSshidokht static di_node_t search_tree_match_pcibdf(di_node_t node, int bus, int dev,
121d155f3feSshidokht     int fn);
122d155f3feSshidokht static int i_match_pcibdf(di_node_t node, void *arg);
123d155f3feSshidokht 
124d155f3feSshidokht static di_node_t search_tree_match_usbserialno(di_node_t node,
125d155f3feSshidokht     uint64_t serialno);
126d155f3feSshidokht static int i_match_usbserialno(di_node_t node, void *arg);
127d155f3feSshidokht 
128d155f3feSshidokht static di_node_t search_children_match_busaddr(di_node_t node,
129d155f3feSshidokht     char *matchbusaddr);
130d155f3feSshidokht 
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate static void
new_disk_list_entry(di_node_t node)1347c478bd9Sstevel@tonic-gate new_disk_list_entry(di_node_t node)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	size_t	newsize;
1377c478bd9Sstevel@tonic-gate 	char **newlist;
1387c478bd9Sstevel@tonic-gate 	int newlen;
1397c478bd9Sstevel@tonic-gate 	char *devfspath;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	if (disk_list_valid >= disk_list_len)	{
1427c478bd9Sstevel@tonic-gate 		/* valid should never really be larger than len */
1437c478bd9Sstevel@tonic-gate 		/* if they are equal we need to init or realloc */
1447c478bd9Sstevel@tonic-gate 		newlen = disk_list_len + DISKS_LIST_INCR;
1457c478bd9Sstevel@tonic-gate 		newsize = newlen * sizeof (*disk_list);
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		newlist = (char **)realloc(disk_list, newsize);
1487c478bd9Sstevel@tonic-gate 		if (newlist == NULL) {
1497c478bd9Sstevel@tonic-gate 			(void) printf("realloc failed to resize disk table\n");
1507c478bd9Sstevel@tonic-gate 			cleanup_and_exit(1);
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 		disk_list = newlist;
1537c478bd9Sstevel@tonic-gate 		disk_list_len = newlen;
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
1577c478bd9Sstevel@tonic-gate 	disk_list[disk_list_valid] = devfspath;
1587c478bd9Sstevel@tonic-gate 	if (debug)
1597c478bd9Sstevel@tonic-gate 		(void) printf("adding %s\n", devfspath);
1607c478bd9Sstevel@tonic-gate 	disk_list_valid++;
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate /* ARGSUSED */
1647c478bd9Sstevel@tonic-gate static int
i_disktype(di_node_t node,di_minor_t minor,void * arg)165d155f3feSshidokht i_disktype(di_node_t node, di_minor_t minor, void *arg)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	char *minortype;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if (di_minor_spectype(minor) == S_IFCHR) {
1707c478bd9Sstevel@tonic-gate 		minortype = di_minor_nodetype(minor);
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 		/* exclude CD's */
1737c478bd9Sstevel@tonic-gate 		if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0)
1747c478bd9Sstevel@tonic-gate 			/* only take p0 raw device */
1757c478bd9Sstevel@tonic-gate 			if (strcmp(di_minor_name(minor), "q,raw") == 0)
1767c478bd9Sstevel@tonic-gate 				new_disk_list_entry(node);
1777c478bd9Sstevel@tonic-gate 	}
1787c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate static void
build_disk_list()1827c478bd9Sstevel@tonic-gate build_disk_list()
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	int ret;
1857c478bd9Sstevel@tonic-gate 	ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL,
186d155f3feSshidokht 	    i_disktype);
1877c478bd9Sstevel@tonic-gate 	if (ret != 0) {
1887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_walk_minor failed errno %d\n",
1897c478bd9Sstevel@tonic-gate 		    errno);
1907c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate static void
free_disks()1957c478bd9Sstevel@tonic-gate free_disks()
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	int i;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (disk_list) {
2007c478bd9Sstevel@tonic-gate 		for (i = 0; i < disk_list_valid; i++)
2017c478bd9Sstevel@tonic-gate 			di_devfs_path_free(disk_list[i]);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		free(disk_list);
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate static int
i_match_pcibdf(di_node_t node,void * arg)208d155f3feSshidokht i_match_pcibdf(di_node_t node, void *arg)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	pcibdf_t *pbp;
2117c478bd9Sstevel@tonic-gate 	int len;
2127c478bd9Sstevel@tonic-gate 	uint32_t	regval;
2137c478bd9Sstevel@tonic-gate 	uint32_t	busnum, funcnum, devicenum;
2147c478bd9Sstevel@tonic-gate 	char *devtype;
2157c478bd9Sstevel@tonic-gate 	uint32_t *regbuf = NULL;
2167c478bd9Sstevel@tonic-gate 	di_node_t	parentnode;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	pbp = (pcibdf_t *)arg;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	parentnode = di_parent_node(node);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
2237c478bd9Sstevel@tonic-gate 	    "device_type", (char **)&devtype);
2247c478bd9Sstevel@tonic-gate 
22570025d76Sjohnny 	if ((len <= 0) ||
22670025d76Sjohnny 	    ((strcmp(devtype, "pci") != 0) && (strcmp(devtype, "pciex") != 0)))
2277c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg",
2307c478bd9Sstevel@tonic-gate 	    (int **)&regbuf);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	if (len <= 0) {
2337c478bd9Sstevel@tonic-gate 		/* Try PROM property */
2347c478bd9Sstevel@tonic-gate 		len = di_prom_prop_lookup_ints(prom_hdl, node, "reg",
2357c478bd9Sstevel@tonic-gate 		    (int **)&regbuf);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (len > 0) {
2407c478bd9Sstevel@tonic-gate 		regval = regbuf[0];
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 		busnum = PCI_REG_BUS_G(regval);
2437c478bd9Sstevel@tonic-gate 		devicenum = PCI_REG_DEV_G(regval);
2447c478bd9Sstevel@tonic-gate 		funcnum = PCI_REG_FUNC_G(regval);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 		if ((busnum == pbp->busnum) &&
2477c478bd9Sstevel@tonic-gate 		    (devicenum == pbp->devnum) &&
2487c478bd9Sstevel@tonic-gate 		    (funcnum == pbp->funcnum)) {
2497c478bd9Sstevel@tonic-gate 			/* found it */
2507c478bd9Sstevel@tonic-gate 			pbp->di_node = node;
2517c478bd9Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate static di_node_t
search_tree_match_pcibdf(di_node_t node,int bus,int dev,int fn)259d155f3feSshidokht search_tree_match_pcibdf(di_node_t node, int bus, int dev, int fn)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	pcibdf_t pb;
2627c478bd9Sstevel@tonic-gate 	pb.busnum = bus;
2637c478bd9Sstevel@tonic-gate 	pb.devnum = dev;
2647c478bd9Sstevel@tonic-gate 	pb.funcnum = fn;
2657c478bd9Sstevel@tonic-gate 	pb.di_node = DI_NODE_NIL;
2667c478bd9Sstevel@tonic-gate 
267d155f3feSshidokht 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &pb, i_match_pcibdf);
2687c478bd9Sstevel@tonic-gate 	return (pb.di_node);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate static int
i_match_usbserialno(di_node_t node,void * arg)273d155f3feSshidokht i_match_usbserialno(di_node_t node, void *arg)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	int len;
2767c478bd9Sstevel@tonic-gate 	char *serialp;
2777c478bd9Sstevel@tonic-gate 	usbser_t *usbsp;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	usbsp = (usbser_t *)arg;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno",
282d155f3feSshidokht 	    (uchar_t **)&serialp);
2837c478bd9Sstevel@tonic-gate 
284d155f3feSshidokht 	if ((len > 0) && (strncmp((char *)&usbsp->serialno, serialp,
285d155f3feSshidokht 	    sizeof (uint64_t)) == 0)) {
2867c478bd9Sstevel@tonic-gate 		usbsp->node = node;
2877c478bd9Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate static di_node_t
search_tree_match_usbserialno(di_node_t node,uint64_t serialno)293d155f3feSshidokht search_tree_match_usbserialno(di_node_t node, uint64_t serialno)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	usbser_t usbs;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	usbs.serialno = serialno;
2997c478bd9Sstevel@tonic-gate 	usbs.node = DI_NODE_NIL;
3007c478bd9Sstevel@tonic-gate 
301d155f3feSshidokht 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, i_match_usbserialno);
3027c478bd9Sstevel@tonic-gate 	return (usbs.node);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
305d155f3feSshidokht /*
306d155f3feSshidokht  * returns the index to the disklist to the disk with matching path
307d155f3feSshidokht  */
3087c478bd9Sstevel@tonic-gate static int
search_disklist_match_path(char * path)309d155f3feSshidokht search_disklist_match_path(char *path)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	int i;
3127c478bd9Sstevel@tonic-gate 	for (i = 0; i < disk_list_valid; i++)
3137c478bd9Sstevel@tonic-gate 		if (strcmp(disk_list[i], path) == 0) {
3147c478bd9Sstevel@tonic-gate 			return (i);
3157c478bd9Sstevel@tonic-gate 		}
3167c478bd9Sstevel@tonic-gate 	return (-1);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
319d155f3feSshidokht /*
320d155f3feSshidokht  * Find first child of 'node' whose unit address is 'matchbusaddr'
321d155f3feSshidokht  */
322d155f3feSshidokht static di_node_t
search_children_match_busaddr(di_node_t node,char * matchbusaddr)323d155f3feSshidokht search_children_match_busaddr(di_node_t node, char *matchbusaddr)
324d155f3feSshidokht {
325d155f3feSshidokht 	di_node_t cnode;
326d155f3feSshidokht 	char *busaddr;
32744d788f4Sgap 	di_path_t pi = DI_PATH_NIL;
328d155f3feSshidokht 
329d155f3feSshidokht 	if (matchbusaddr == NULL)
330d155f3feSshidokht 		return (DI_NODE_NIL);
331d155f3feSshidokht 
332*602ca9eaScth 	while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) {
333*602ca9eaScth 		busaddr = di_path_bus_addr(pi);
334*602ca9eaScth 		if (busaddr == NULL)
335*602ca9eaScth 			continue;
336*602ca9eaScth 		if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
33744d788f4Sgap 			return (di_path_client_node(pi));
338*602ca9eaScth 	}
339d155f3feSshidokht 
340d155f3feSshidokht 	for (cnode = di_child_node(node); cnode != DI_NODE_NIL;
341d155f3feSshidokht 	    cnode = di_sibling_node(cnode)) {
342d155f3feSshidokht 		busaddr = di_bus_addr(cnode);
343d155f3feSshidokht 		if (busaddr == NULL)
344d155f3feSshidokht 			continue;
345d155f3feSshidokht 		if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
346*602ca9eaScth 			return (cnode);
347d155f3feSshidokht 	}
348*602ca9eaScth 
349*602ca9eaScth 	return (DI_NODE_NIL);
350d155f3feSshidokht }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * Construct a physical device pathname from EDD and verify the
3547c478bd9Sstevel@tonic-gate  * path exists. Return the index of in disk_list for the mapped
3557c478bd9Sstevel@tonic-gate  * path on success, -1 on failure.
3567c478bd9Sstevel@tonic-gate  */
3577c478bd9Sstevel@tonic-gate static int
match_edd(biosdev_data_t * bdata)3587c478bd9Sstevel@tonic-gate match_edd(biosdev_data_t *bdata)
3597c478bd9Sstevel@tonic-gate {
360d155f3feSshidokht 	di_node_t node, cnode = DI_NODE_NIL;
361d155f3feSshidokht 	char *devfspath = NULL;
3627c478bd9Sstevel@tonic-gate 	fn48_t *bd;
3637c478bd9Sstevel@tonic-gate 	int index;
364d155f3feSshidokht 	char busaddrbuf[MAXNAMELEN];
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if (!bdata->edd_valid) {
3677c478bd9Sstevel@tonic-gate 		if (debug)
3687c478bd9Sstevel@tonic-gate 			(void) printf("edd not valid\n");
3697c478bd9Sstevel@tonic-gate 		return (-1);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	bd = &bdata->fn48_dev_params;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) {
3757c478bd9Sstevel@tonic-gate 		/* EDD extensions for devicepath not present */
3767c478bd9Sstevel@tonic-gate 		if (debug)
3777c478bd9Sstevel@tonic-gate 			(void) printf("magic not valid %x pathinfolen %d\n",
3787c478bd9Sstevel@tonic-gate 			    bd->magic, bd->pathinfo_len);
3797c478bd9Sstevel@tonic-gate 		return (-1);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	/* we handle only PCI scsi, ata or sata for now */
3837c478bd9Sstevel@tonic-gate 	if (strncmp(bd->bustype, "PCI", 3) != 0) {
3847c478bd9Sstevel@tonic-gate 		if (debug)
3857c478bd9Sstevel@tonic-gate 			(void) printf("was not pci %s\n", bd->bustype);
3867c478bd9Sstevel@tonic-gate 		return (-1);
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	if (debug)
3897c478bd9Sstevel@tonic-gate 		(void) printf("match_edd bdf %d %d %d\n",
390d155f3feSshidokht 		    bd->interfacepath.pci.bus,
391d155f3feSshidokht 		    bd->interfacepath.pci.device,
392d155f3feSshidokht 		    bd->interfacepath.pci.function);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* look into devinfo tree and find a node with matching pci b/d/f */
395d155f3feSshidokht 	node = search_tree_match_pcibdf(root_node, bd->interfacepath.pci.bus,
396d155f3feSshidokht 	    bd->interfacepath.pci.device, bd->interfacepath.pci.function);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
3997c478bd9Sstevel@tonic-gate 		if (debug)
4007c478bd9Sstevel@tonic-gate 			(void) printf(" could not find a node in tree "
4017c478bd9Sstevel@tonic-gate 			    "matching bdf\n");
4027c478bd9Sstevel@tonic-gate 		return (-1);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
405801d74ddSshidokht 	if (debug) {
406801d74ddSshidokht 		int i;
407801d74ddSshidokht 		(void) printf("interface type ");
408801d74ddSshidokht 		for (i = 0; i < 8; i++)
409801d74ddSshidokht 			(void) printf("%c", bd->interface_type[i]);
410801d74ddSshidokht 		(void) printf(" pci channel %x target %x\n",
411801d74ddSshidokht 		    bd->interfacepath.pci.channel,
412d155f3feSshidokht 		    bd->devicepath.scsi.target);
413801d74ddSshidokht 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if (strncmp(bd->interface_type, "SCSI", 4) == 0) {
4167c478bd9Sstevel@tonic-gate 
417d155f3feSshidokht 		(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,%x",
4187c478bd9Sstevel@tonic-gate 		    bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo);
4197c478bd9Sstevel@tonic-gate 
420d155f3feSshidokht 		cnode = search_children_match_busaddr(node, busaddrbuf);
421d155f3feSshidokht 
422d155f3feSshidokht 	} else if ((strncmp(bd->interface_type, "ATAPI", 5) == 0) ||
423d155f3feSshidokht 	    (strncmp(bd->interface_type, "ATA", 3) == 0) ||
424d155f3feSshidokht 	    (strncmp(bd->interface_type, "SATA", 4) == 0)) {
425d155f3feSshidokht 
426d155f3feSshidokht 		if (strncmp(di_node_name(node), "pci-ide", 7) == 0) {
427d155f3feSshidokht 			/*
428d155f3feSshidokht 			 * Legacy using pci-ide
429d155f3feSshidokht 			 * the child should be ide@<x>, where x is
430d155f3feSshidokht 			 * the channel number
431d155f3feSshidokht 			 */
432d155f3feSshidokht 			(void) snprintf(busaddrbuf, MAXNAMELEN, "%d",
433d155f3feSshidokht 			    bd->interfacepath.pci.channel);
434d155f3feSshidokht 
435d155f3feSshidokht 			if ((cnode = search_children_match_busaddr(node,
436d155f3feSshidokht 			    busaddrbuf)) != DI_NODE_NIL) {
437d155f3feSshidokht 
438d155f3feSshidokht 				(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
439d155f3feSshidokht 				    bd->devicepath.ata.chan);
440d155f3feSshidokht 				cnode = search_children_match_busaddr(cnode,
441d155f3feSshidokht 				    busaddrbuf);
442d155f3feSshidokht 
443d155f3feSshidokht 				if (cnode == DI_NODE_NIL)
444d155f3feSshidokht 					if (debug)
445d155f3feSshidokht 						(void) printf("Interface %s "
446d155f3feSshidokht 						    "using pci-ide no "
447d155f3feSshidokht 						    "grandchild at %s\n",
448d155f3feSshidokht 						    bd->interface_type,
449d155f3feSshidokht 						    busaddrbuf);
450d155f3feSshidokht 			} else {
451d155f3feSshidokht 				if (debug)
452d155f3feSshidokht 					(void) printf("Interface %s using "
453d155f3feSshidokht 					    "pci-ide, with no child at %s\n",
454d155f3feSshidokht 					    bd->interface_type, busaddrbuf);
455d155f3feSshidokht 			}
456d155f3feSshidokht 		} else {
457d155f3feSshidokht 			if (strncmp(bd->interface_type, "SATA", 4) == 0) {
458d155f3feSshidokht 				/*
459d155f3feSshidokht 				 * The current EDD (EDD-2) spec does not
460d155f3feSshidokht 				 * address port number. This is work in
461d155f3feSshidokht 				 * progress.
462d155f3feSshidokht 				 * Interprete the first field of device path
463d155f3feSshidokht 				 * as port number. Needs to be revisited
464d155f3feSshidokht 				 * with port multiplier support.
465d155f3feSshidokht 				 */
466d155f3feSshidokht 				(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
467d155f3feSshidokht 				    bd->devicepath.ata.chan);
468d155f3feSshidokht 
469d155f3feSshidokht 				cnode = search_children_match_busaddr(node,
470d155f3feSshidokht 				    busaddrbuf);
471d155f3feSshidokht 			} else {
472d155f3feSshidokht 				if (debug)
473d155f3feSshidokht 					(void) printf("Interface %s, not using"
474d155f3feSshidokht 					    " pci-ide\n", bd->interface_type);
475d155f3feSshidokht 			}
476d155f3feSshidokht 		}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	} else if (strncmp(bd->interface_type, "USB", 3) == 0) {
479d155f3feSshidokht 		cnode = search_tree_match_usbserialno(node,
480d155f3feSshidokht 		    bd->devicepath.usb.usb_serial_id);
4817c478bd9Sstevel@tonic-gate 	} else {
4827c478bd9Sstevel@tonic-gate 		if (debug)
4837c478bd9Sstevel@tonic-gate 			(void) printf("sorry not supported interface %s\n",
484d155f3feSshidokht 			    bd->interface_type);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
487d155f3feSshidokht 	if (cnode != DI_NODE_NIL) {
488d155f3feSshidokht 		devfspath = di_devfs_path(cnode);
489d155f3feSshidokht 		index = search_disklist_match_path(devfspath);
490d155f3feSshidokht 		di_devfs_path_free(devfspath);
491d155f3feSshidokht 		if (index >= 0)
492d155f3feSshidokht 			return (index);
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	return (-1);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate  * For each disk in list of disks, compare the first block with the
5007c478bd9Sstevel@tonic-gate  * one from bdd. On the first match, return the index of path in
5017c478bd9Sstevel@tonic-gate  * disk_list. If none matched return -1.
5027c478bd9Sstevel@tonic-gate  */
5037c478bd9Sstevel@tonic-gate static int
match_first_block(biosdev_data_t * bd)5047c478bd9Sstevel@tonic-gate match_first_block(biosdev_data_t *bd)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	char diskpath[MAXPATHLEN];
5087c478bd9Sstevel@tonic-gate 	int fd;
5097c478bd9Sstevel@tonic-gate 	char buf[512];
5107c478bd9Sstevel@tonic-gate 	ssize_t	num_read;
5117c478bd9Sstevel@tonic-gate 	int i;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (!bd->first_block_valid)
5147c478bd9Sstevel@tonic-gate 		return (-1);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	for (i = 0; i < disk_list_valid; i++) {
5177c478bd9Sstevel@tonic-gate 		(void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw",
5187c478bd9Sstevel@tonic-gate 		    DEVFS_PREFIX, disk_list[i]);
5197c478bd9Sstevel@tonic-gate 		fd = open(diskpath, O_RDONLY);
5207c478bd9Sstevel@tonic-gate 		if (fd  < 0) {
5217c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "opening %s failed errno %d\n",
5227c478bd9Sstevel@tonic-gate 			    diskpath, errno);
5237c478bd9Sstevel@tonic-gate 			continue;
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 		num_read = read(fd, buf, 512);
5267c478bd9Sstevel@tonic-gate 		if (num_read != 512) {
5277c478bd9Sstevel@tonic-gate 			(void) printf("read only %d bytes from %s\n", num_read,
5287c478bd9Sstevel@tonic-gate 			    diskpath);
5297c478bd9Sstevel@tonic-gate 			continue;
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 		if (memcmp(buf, bd->first_block, 512) == 0)	 {
5337c478bd9Sstevel@tonic-gate 			/* found it */
5347c478bd9Sstevel@tonic-gate 			return (i);
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 	return (-1);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate static void
cleanup_and_exit(int exitcode)5427c478bd9Sstevel@tonic-gate cleanup_and_exit(int exitcode)
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	free_disks();
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	if (root_node != DI_NODE_NIL)
5487c478bd9Sstevel@tonic-gate 		di_fini(root_node);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	if (root_allnode != DI_NODE_NIL)
5517c478bd9Sstevel@tonic-gate 		di_fini(root_allnode);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	if (prom_hdl != DI_PROM_HANDLE_NIL)
5547c478bd9Sstevel@tonic-gate 		di_prom_fini(prom_hdl);
5557c478bd9Sstevel@tonic-gate 	exit(exitcode);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])5617c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 	biosdev_data_t		*biosdata;
564801d74ddSshidokht 	int i, c, j;
5657c478bd9Sstevel@tonic-gate 	int matchedindex = -1;
5667c478bd9Sstevel@tonic-gate 	char biospropname[BIOSPROPNAME_TMPL_LEN];
5677c478bd9Sstevel@tonic-gate 	int totalmatches = 0;
568801d74ddSshidokht 	biosdev_data_t *biosdataarray[BIOSDEV_NUM];
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "d")) != -1)  {
5727c478bd9Sstevel@tonic-gate 		switch (c) {
5737c478bd9Sstevel@tonic-gate 		case 'd':
5747c478bd9Sstevel@tonic-gate 			debug = 1;
5757c478bd9Sstevel@tonic-gate 			break;
5767c478bd9Sstevel@tonic-gate 		default:
5777c478bd9Sstevel@tonic-gate 			(void) printf("unknown option %c\n", c);
5787c478bd9Sstevel@tonic-gate 			exit(1);
5797c478bd9Sstevel@tonic-gate 		}
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
5837c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_prom_init failed\n");
5847c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
5857c478bd9Sstevel@tonic-gate 	}
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
5887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init failed\n");
5897c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
5937c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init failed\n");
5947c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	(void) memset(mapinfo, 0, sizeof (mapinfo));
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	/* get a list of all disks in the system */
6007c478bd9Sstevel@tonic-gate 	build_disk_list();
6017c478bd9Sstevel@tonic-gate 
602801d74ddSshidokht 	/*  Get property values that were created at boot up time */
6037c478bd9Sstevel@tonic-gate 	for (i = 0; i < BIOSDEV_NUM; i++) {
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 		(void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN,
6067c478bd9Sstevel@tonic-gate 		    BIOSPROPNAME_TMPL, i + STARTING_DRVNUM);
607801d74ddSshidokht 		if (di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode,
608801d74ddSshidokht 		    biospropname, (uchar_t **)&biosdataarray[i]) <= 0)
609801d74ddSshidokht 			biosdataarray[i] = NULL;
610801d74ddSshidokht 	}
6117c478bd9Sstevel@tonic-gate 
612801d74ddSshidokht 	/* Try to match based on device/interface path info from BIOS */
613801d74ddSshidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
6147c478bd9Sstevel@tonic-gate 
615801d74ddSshidokht 		if ((biosdata = biosdataarray[i]) == NULL)
6167c478bd9Sstevel@tonic-gate 			continue;
6177c478bd9Sstevel@tonic-gate 		if (debug)
618801d74ddSshidokht 			(void) printf("matching edd 0x%x\n",
619801d74ddSshidokht 			    i + STARTING_DRVNUM);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 		matchedindex = match_edd(biosdata);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		if (matchedindex != -1) {
624801d74ddSshidokht 			if (debug) {
625801d74ddSshidokht 				(void) printf("matched by edd\n");
626801d74ddSshidokht 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
627801d74ddSshidokht 				    disk_list[matchedindex]);
628801d74ddSshidokht 			}
629801d74ddSshidokht 
6307c478bd9Sstevel@tonic-gate 			mapinfo[i].disklist_index = matchedindex;
6317c478bd9Sstevel@tonic-gate 			mapinfo[i].matchcount++;
632801d74ddSshidokht 
633801d74ddSshidokht 			for (j = 0; j < i; j++) {
634801d74ddSshidokht 				if (mapinfo[j].matchcount > 0 &&
635801d74ddSshidokht 				    mapinfo[j].disklist_index == matchedindex) {
636801d74ddSshidokht 					mapinfo[j].matchcount++;
637801d74ddSshidokht 					mapinfo[i].matchcount++;
638801d74ddSshidokht 				}
639801d74ddSshidokht 			}
640801d74ddSshidokht 
641801d74ddSshidokht 		} else
642801d74ddSshidokht 			if (debug)
643801d74ddSshidokht 				(void) printf("No matches by edd\n");
644801d74ddSshidokht 	}
645801d74ddSshidokht 
646801d74ddSshidokht 	/*
647801d74ddSshidokht 	 * Go through the list and ignore any found matches that are dups.
648801d74ddSshidokht 	 * This is to workaround issues with BIOSes that do not implement
649801d74ddSshidokht 	 * providing interface/device path info correctly.
650801d74ddSshidokht 	 */
651801d74ddSshidokht 
652801d74ddSshidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
653801d74ddSshidokht 		if (mapinfo[i].matchcount > 1) {
6547c478bd9Sstevel@tonic-gate 			if (debug)
655801d74ddSshidokht 				(void) printf("Ignoring dup match_edd\n(count "
656801d74ddSshidokht 				    "%d): 0x%x %s\n", mapinfo[i].matchcount,
657801d74ddSshidokht 				    i + STARTING_DRVNUM,
658801d74ddSshidokht 				    disk_list[mapinfo[i].disklist_index]);
659801d74ddSshidokht 
660801d74ddSshidokht 			mapinfo[i].matchcount = 0;
661801d74ddSshidokht 			mapinfo[i].disklist_index = 0;
662801d74ddSshidokht 		}
663801d74ddSshidokht 	}
664801d74ddSshidokht 
665801d74ddSshidokht 
666801d74ddSshidokht 	/*
667801d74ddSshidokht 	 * For each bios dev number that we do not have exactly one match
668801d74ddSshidokht 	 * already, try to match based on first block
669801d74ddSshidokht 	 */
670801d74ddSshidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
671801d74ddSshidokht 		if (mapinfo[i].matchcount == 1)
672801d74ddSshidokht 			continue;
673801d74ddSshidokht 
674801d74ddSshidokht 		if ((biosdata = biosdataarray[i]) == NULL)
675801d74ddSshidokht 			continue;
676801d74ddSshidokht 
677801d74ddSshidokht 		if (debug)
678801d74ddSshidokht 			(void) printf("matching first block 0x%x\n",
679801d74ddSshidokht 			    i + STARTING_DRVNUM);
680801d74ddSshidokht 
681801d74ddSshidokht 		matchedindex = match_first_block(biosdata);
682801d74ddSshidokht 		if (matchedindex != -1) {
683801d74ddSshidokht 			if (debug) {
684801d74ddSshidokht 				(void) printf("matched by first block\n");
6857c478bd9Sstevel@tonic-gate 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
6867c478bd9Sstevel@tonic-gate 				    disk_list[matchedindex]);
687801d74ddSshidokht 			}
688801d74ddSshidokht 
689801d74ddSshidokht 			mapinfo[i].disklist_index = matchedindex;
690801d74ddSshidokht 			mapinfo[i].matchcount++;
691801d74ddSshidokht 
6927c478bd9Sstevel@tonic-gate 			for (j = 0; j < i; j++) {
6937c478bd9Sstevel@tonic-gate 				if (mapinfo[j].matchcount > 0 &&
6947c478bd9Sstevel@tonic-gate 				    mapinfo[j].disklist_index == matchedindex) {
6957c478bd9Sstevel@tonic-gate 					mapinfo[j].matchcount++;
6967c478bd9Sstevel@tonic-gate 					mapinfo[i].matchcount++;
6977c478bd9Sstevel@tonic-gate 				}
6987c478bd9Sstevel@tonic-gate 			}
699801d74ddSshidokht 		} else
700801d74ddSshidokht 			if (debug) {
701801d74ddSshidokht 				(void) printf(" No matches by first block\n");
702801d74ddSshidokht 				(void) fprintf(stderr, "Could not match 0x%x\n",
703801d74ddSshidokht 				    i + STARTING_DRVNUM);
704801d74ddSshidokht 			}
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
707801d74ddSshidokht 
7087c478bd9Sstevel@tonic-gate 	for (i = 0; i < BIOSDEV_NUM; i++) {
7097c478bd9Sstevel@tonic-gate 		if (mapinfo[i].matchcount == 1) {
7107c478bd9Sstevel@tonic-gate 			(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
7117c478bd9Sstevel@tonic-gate 			    disk_list[mapinfo[i].disklist_index]);
7127c478bd9Sstevel@tonic-gate 			totalmatches++;
7137c478bd9Sstevel@tonic-gate 		} else if (debug && mapinfo[i].matchcount > 1) {
7147c478bd9Sstevel@tonic-gate 			(void) printf("0x%x %s matchcount %d\n",
7157c478bd9Sstevel@tonic-gate 			    i + STARTING_DRVNUM,
7167c478bd9Sstevel@tonic-gate 			    disk_list[mapinfo[i].disklist_index],
717d155f3feSshidokht 			    mapinfo[i].matchcount);
7187c478bd9Sstevel@tonic-gate 		}
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	if (totalmatches == 0) {
7227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "biosdev: Could not match any!!\n");
7237c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	cleanup_and_exit(0);
7277c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
7287c478bd9Sstevel@tonic-gate 	return (0);
7297c478bd9Sstevel@tonic-gate }
730