Home | History | Annotate | Download | only in biosdev
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1782  shidokht  * Common Development and Distribution License (the "License").
      6  1782  shidokht  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  5763       gap  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel 
     26     0    stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27     0    stevel 
     28     0    stevel #include <stdio.h>
     29     0    stevel #include <string.h>
     30     0    stevel #include <stdlib.h>
     31     0    stevel #include <unistd.h>
     32     0    stevel #include <sys/param.h>
     33     0    stevel #include <errno.h>
     34     0    stevel #include <sys/types.h>
     35     0    stevel #include <dirent.h>
     36     0    stevel #include <libdevinfo.h>
     37     0    stevel #include <fcntl.h>
     38     0    stevel #include <sys/types.h>
     39     0    stevel #include <sys/stat.h>
     40     0    stevel #include <sys/pci.h>
     41     0    stevel #include <sys/biosdisk.h>
     42     0    stevel 
     43     0    stevel 
     44     0    stevel /*
     45     0    stevel  * structure used for searching device tree for a node matching
     46     0    stevel  * pci bus/dev/fn
     47     0    stevel  */
     48     0    stevel typedef struct pcibdf {
     49     0    stevel 	int busnum;
     50     0    stevel 	int devnum;
     51     0    stevel 	int funcnum;
     52     0    stevel 	di_node_t	di_node;
     53     0    stevel } pcibdf_t;
     54     0    stevel 
     55     0    stevel /*
     56     0    stevel  * structure used for searching device tree for a node matching
     57     0    stevel  * USB serial number.
     58     0    stevel  */
     59     0    stevel typedef struct {
     60     0    stevel 	uint64_t serialno;
     61     0    stevel 	di_node_t	node;
     62     0    stevel } usbser_t;
     63     0    stevel 
     64     0    stevel /*
     65     0    stevel  * structure for holding the mapping info
     66     0    stevel  */
     67     0    stevel typedef struct {
     68     0    stevel 	int disklist_index;	/* index to disk_list of the mapped path */
     69     0    stevel 	int matchcount;		/* number of matches per this device number */
     70     0    stevel } mapinfo_t;
     71     0    stevel 
     72     0    stevel #define	DEVFS_PREFIX "/devices"
     73     0    stevel #define	DISKS_LIST_INCR		20	/* increment for resizing disk_list */
     74     0    stevel 
     75     0    stevel #define	BIOSPROPNAME_TMPL	"biosdev-0x%x"
     76     0    stevel #define	BIOSPROPNAME_TMPL_LEN	13
     77     0    stevel #define	BIOSDEV_NUM		8
     78     0    stevel #define	STARTING_DRVNUM		0x80
     79     0    stevel 
     80     0    stevel /*
     81     0    stevel  * array to hold mappings. Element at index X corresponds to BIOS device
     82     0    stevel  * number 0x80 + X
     83     0    stevel  */
     84     0    stevel static mapinfo_t mapinfo[BIOSDEV_NUM];
     85     0    stevel 
     86     0    stevel /*
     87     0    stevel  * Cache copy of kernel device tree snapshot root handle, includes devices
     88     0    stevel  * that are detached
     89     0    stevel  */
     90     0    stevel static di_node_t root_node = DI_NODE_NIL;
     91     0    stevel 
     92     0    stevel /*
     93     0    stevel  * kernel device tree snapshot with currently attached devices. Detached
     94     0    stevel  * devices are not included.
     95     0    stevel  */
     96     0    stevel static di_node_t root_allnode = DI_NODE_NIL;
     97     0    stevel 
     98     0    stevel /*
     99     0    stevel  * handle to retrieve prom properties
    100     0    stevel  */
    101     0    stevel 
    102     0    stevel static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
    103     0    stevel 
    104     0    stevel static char **disk_list = NULL;	/* array of physical device pathnames */
    105     0    stevel static int disk_list_len = 0;		/* length of disk_list */
    106     0    stevel static int disk_list_valid = 0;	/* number of valid entries in disk_list */
    107     0    stevel 
    108     0    stevel static int debug = 0;			/* used for enabling debug output */
    109     0    stevel 
    110     0    stevel 
    111     0    stevel /* Local function prototypes */
    112     0    stevel static void new_disk_list_entry(di_node_t node);
    113  1782  shidokht static int i_disktype(di_node_t node, di_minor_t minor, void *arg);
    114     0    stevel static void build_disk_list();
    115  1782  shidokht static int search_disklist_match_path(char *path);
    116     0    stevel static void free_disks();
    117  1782  shidokht static void cleanup_and_exit(int);
    118  1782  shidokht 
    119     0    stevel static int match_edd(biosdev_data_t *bd);
    120     0    stevel static int match_first_block(biosdev_data_t *bd);
    121  1782  shidokht 
    122  1782  shidokht static di_node_t search_tree_match_pcibdf(di_node_t node, int bus, int dev,
    123  1782  shidokht     int fn);
    124  1782  shidokht static int i_match_pcibdf(di_node_t node, void *arg);
    125  1782  shidokht 
    126  1782  shidokht static di_node_t search_tree_match_usbserialno(di_node_t node,
    127  1782  shidokht     uint64_t serialno);
    128  1782  shidokht static int i_match_usbserialno(di_node_t node, void *arg);
    129  1782  shidokht 
    130  1782  shidokht static di_node_t search_children_match_busaddr(di_node_t node,
    131  1782  shidokht     char *matchbusaddr);
    132  1782  shidokht 
    133     0    stevel 
    134     0    stevel 
    135     0    stevel static void
    136     0    stevel new_disk_list_entry(di_node_t node)
    137     0    stevel {
    138     0    stevel 	size_t	newsize;
    139     0    stevel 	char **newlist;
    140     0    stevel 	int newlen;
    141     0    stevel 	char *devfspath;
    142     0    stevel 
    143     0    stevel 	if (disk_list_valid >= disk_list_len)	{
    144     0    stevel 		/* valid should never really be larger than len */
    145     0    stevel 		/* if they are equal we need to init or realloc */
    146     0    stevel 		newlen = disk_list_len + DISKS_LIST_INCR;
    147     0    stevel 		newsize = newlen * sizeof (*disk_list);
    148     0    stevel 
    149     0    stevel 		newlist = (char **)realloc(disk_list, newsize);
    150     0    stevel 		if (newlist == NULL) {
    151     0    stevel 			(void) printf("realloc failed to resize disk table\n");
    152     0    stevel 			cleanup_and_exit(1);
    153     0    stevel 		}
    154     0    stevel 		disk_list = newlist;
    155     0    stevel 		disk_list_len = newlen;
    156     0    stevel 	}
    157     0    stevel 
    158     0    stevel 	devfspath = di_devfs_path(node);
    159     0    stevel 	disk_list[disk_list_valid] = devfspath;
    160     0    stevel 	if (debug)
    161     0    stevel 		(void) printf("adding %s\n", devfspath);
    162     0    stevel 	disk_list_valid++;
    163     0    stevel }
    164     0    stevel 
    165     0    stevel /* ARGSUSED */
    166     0    stevel static int
    167  1782  shidokht i_disktype(di_node_t node, di_minor_t minor, void *arg)
    168     0    stevel {
    169     0    stevel 	char *minortype;
    170     0    stevel 
    171     0    stevel 	if (di_minor_spectype(minor) == S_IFCHR) {
    172     0    stevel 		minortype = di_minor_nodetype(minor);
    173     0    stevel 
    174     0    stevel 		/* exclude CD's */
    175     0    stevel 		if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0)
    176     0    stevel 			/* only take p0 raw device */
    177     0    stevel 			if (strcmp(di_minor_name(minor), "q,raw") == 0)
    178     0    stevel 				new_disk_list_entry(node);
    179     0    stevel 	}
    180     0    stevel 	return (DI_WALK_CONTINUE);
    181     0    stevel }
    182     0    stevel 
    183     0    stevel static void
    184     0    stevel build_disk_list()
    185     0    stevel {
    186     0    stevel 	int ret;
    187     0    stevel 	ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL,
    188  1782  shidokht 	    i_disktype);
    189     0    stevel 	if (ret != 0) {
    190     0    stevel 		(void) fprintf(stderr, "di_walk_minor failed errno %d\n",
    191     0    stevel 		    errno);
    192     0    stevel 		cleanup_and_exit(1);
    193     0    stevel 	}
    194     0    stevel }
    195     0    stevel 
    196     0    stevel static void
    197     0    stevel free_disks()
    198     0    stevel {
    199     0    stevel 	int i;
    200     0    stevel 
    201     0    stevel 	if (disk_list) {
    202     0    stevel 		for (i = 0; i < disk_list_valid; i++)
    203     0    stevel 			di_devfs_path_free(disk_list[i]);
    204     0    stevel 
    205     0    stevel 		free(disk_list);
    206     0    stevel 	}
    207     0    stevel }
    208     0    stevel 
    209     0    stevel static int
    210  1782  shidokht i_match_pcibdf(di_node_t node, void *arg)
    211     0    stevel {
    212     0    stevel 	pcibdf_t *pbp;
    213     0    stevel 	int len;
    214     0    stevel 	uint32_t	regval;
    215     0    stevel 	uint32_t	busnum, funcnum, devicenum;
    216     0    stevel 	char *devtype;
    217     0    stevel 	uint32_t *regbuf = NULL;
    218     0    stevel 	di_node_t	parentnode;
    219     0    stevel 
    220     0    stevel 	pbp = (pcibdf_t *)arg;
    221     0    stevel 
    222     0    stevel 	parentnode = di_parent_node(node);
    223     0    stevel 
    224     0    stevel 	len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
    225     0    stevel 	    "device_type", (char **)&devtype);
    226     0    stevel 
    227   881    johnny 	if ((len <= 0) ||
    228   881    johnny 	    ((strcmp(devtype, "pci") != 0) && (strcmp(devtype, "pciex") != 0)))
    229     0    stevel 		return (DI_WALK_CONTINUE);
    230     0    stevel 
    231     0    stevel 	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg",
    232     0    stevel 	    (int **)&regbuf);
    233     0    stevel 
    234     0    stevel 	if (len <= 0) {
    235     0    stevel 		/* Try PROM property */
    236     0    stevel 		len = di_prom_prop_lookup_ints(prom_hdl, node, "reg",
    237     0    stevel 		    (int **)&regbuf);
    238     0    stevel 	}
    239     0    stevel 
    240     0    stevel 
    241     0    stevel 	if (len > 0) {
    242     0    stevel 		regval = regbuf[0];
    243     0    stevel 
    244     0    stevel 		busnum = PCI_REG_BUS_G(regval);
    245     0    stevel 		devicenum = PCI_REG_DEV_G(regval);
    246     0    stevel 		funcnum = PCI_REG_FUNC_G(regval);
    247     0    stevel 
    248     0    stevel 		if ((busnum == pbp->busnum) &&
    249     0    stevel 		    (devicenum == pbp->devnum) &&
    250     0    stevel 		    (funcnum == pbp->funcnum)) {
    251     0    stevel 			/* found it */
    252     0    stevel 			pbp->di_node = node;
    253     0    stevel 			return (DI_WALK_TERMINATE);
    254     0    stevel 		}
    255     0    stevel 	}
    256     0    stevel 
    257     0    stevel 	return (DI_WALK_CONTINUE);
    258     0    stevel }
    259     0    stevel 
    260     0    stevel static di_node_t
    261  1782  shidokht search_tree_match_pcibdf(di_node_t node, int bus, int dev, int fn)
    262     0    stevel {
    263     0    stevel 	pcibdf_t pb;
    264     0    stevel 	pb.busnum = bus;
    265     0    stevel 	pb.devnum = dev;
    266     0    stevel 	pb.funcnum = fn;
    267     0    stevel 	pb.di_node = DI_NODE_NIL;
    268     0    stevel 
    269  1782  shidokht 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &pb, i_match_pcibdf);
    270     0    stevel 	return (pb.di_node);
    271     0    stevel 
    272     0    stevel }
    273     0    stevel 
    274     0    stevel static int
    275  1782  shidokht i_match_usbserialno(di_node_t node, void *arg)
    276     0    stevel {
    277     0    stevel 	int len;
    278     0    stevel 	char *serialp;
    279     0    stevel 	usbser_t *usbsp;
    280     0    stevel 
    281     0    stevel 	usbsp = (usbser_t *)arg;
    282     0    stevel 
    283     0    stevel 	len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno",
    284  1782  shidokht 	    (uchar_t **)&serialp);
    285     0    stevel 
    286  1782  shidokht 	if ((len > 0) && (strncmp((char *)&usbsp->serialno, serialp,
    287  1782  shidokht 	    sizeof (uint64_t)) == 0)) {
    288     0    stevel 		usbsp->node = node;
    289     0    stevel 		return (DI_WALK_TERMINATE);
    290     0    stevel 	}
    291     0    stevel 	return (DI_WALK_CONTINUE);
    292     0    stevel }
    293     0    stevel 
    294     0    stevel static di_node_t
    295  1782  shidokht search_tree_match_usbserialno(di_node_t node, uint64_t serialno)
    296     0    stevel {
    297     0    stevel 
    298     0    stevel 	usbser_t usbs;
    299     0    stevel 
    300     0    stevel 	usbs.serialno = serialno;
    301     0    stevel 	usbs.node = DI_NODE_NIL;
    302     0    stevel 
    303  1782  shidokht 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, i_match_usbserialno);
    304     0    stevel 	return (usbs.node);
    305     0    stevel }
    306     0    stevel 
    307  1782  shidokht /*
    308  1782  shidokht  * returns the index to the disklist to the disk with matching path
    309  1782  shidokht  */
    310     0    stevel static int
    311  1782  shidokht search_disklist_match_path(char *path)
    312     0    stevel {
    313     0    stevel 	int i;
    314     0    stevel 	for (i = 0; i < disk_list_valid; i++)
    315     0    stevel 		if (strcmp(disk_list[i], path) == 0) {
    316     0    stevel 			return (i);
    317     0    stevel 		}
    318     0    stevel 	return (-1);
    319     0    stevel }
    320     0    stevel 
    321  1782  shidokht /*
    322  1782  shidokht  * Find first child of 'node' whose unit address is 'matchbusaddr'
    323  1782  shidokht  */
    324  1782  shidokht static di_node_t
    325  1782  shidokht search_children_match_busaddr(di_node_t node, char *matchbusaddr)
    326  1782  shidokht {
    327  1782  shidokht 	di_node_t cnode;
    328  1782  shidokht 	char *busaddr;
    329  5763       gap 	di_path_t pi = DI_PATH_NIL;
    330  1782  shidokht 
    331  1782  shidokht 	if (matchbusaddr == NULL)
    332  1782  shidokht 		return (DI_NODE_NIL);
    333  1782  shidokht 
    334  6640       cth 	while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) {
    335  6640       cth 		busaddr = di_path_bus_addr(pi);
    336  6640       cth 		if (busaddr == NULL)
    337  6640       cth 			continue;
    338  6640       cth 		if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
    339  5763       gap 			return (di_path_client_node(pi));
    340  6640       cth 	}
    341  1782  shidokht 
    342  1782  shidokht 	for (cnode = di_child_node(node); cnode != DI_NODE_NIL;
    343  1782  shidokht 	    cnode = di_sibling_node(cnode)) {
    344  1782  shidokht 		busaddr = di_bus_addr(cnode);
    345  1782  shidokht 		if (busaddr == NULL)
    346  1782  shidokht 			continue;
    347  1782  shidokht 		if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
    348  6640       cth 			return (cnode);
    349  1782  shidokht 	}
    350  6640       cth 
    351  6640       cth 	return (DI_NODE_NIL);
    352  1782  shidokht }
    353     0    stevel 
    354     0    stevel /*
    355     0    stevel  * Construct a physical device pathname from EDD and verify the
    356     0    stevel  * path exists. Return the index of in disk_list for the mapped
    357     0    stevel  * path on success, -1 on failure.
    358     0    stevel  */
    359     0    stevel static int
    360     0    stevel match_edd(biosdev_data_t *bdata)
    361     0    stevel {
    362  1782  shidokht 	di_node_t node, cnode = DI_NODE_NIL;
    363  1782  shidokht 	char *devfspath = NULL;
    364     0    stevel 	fn48_t *bd;
    365     0    stevel 	int index;
    366  1782  shidokht 	char busaddrbuf[MAXNAMELEN];
    367     0    stevel 
    368     0    stevel 	if (!bdata->edd_valid) {
    369     0    stevel 		if (debug)
    370     0    stevel 			(void) printf("edd not valid\n");
    371     0    stevel 		return (-1);
    372     0    stevel 	}
    373     0    stevel 
    374     0    stevel 	bd = &bdata->fn48_dev_params;
    375     0    stevel 
    376     0    stevel 	if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) {
    377     0    stevel 		/* EDD extensions for devicepath not present */
    378     0    stevel 		if (debug)
    379     0    stevel 			(void) printf("magic not valid %x pathinfolen %d\n",
    380     0    stevel 			    bd->magic, bd->pathinfo_len);
    381     0    stevel 		return (-1);
    382     0    stevel 	}
    383     0    stevel 
    384     0    stevel 	/* we handle only PCI scsi, ata or sata for now */
    385     0    stevel 	if (strncmp(bd->bustype, "PCI", 3) != 0) {
    386     0    stevel 		if (debug)
    387     0    stevel 			(void) printf("was not pci %s\n", bd->bustype);
    388     0    stevel 		return (-1);
    389     0    stevel 	}
    390     0    stevel 	if (debug)
    391     0    stevel 		(void) printf("match_edd bdf %d %d %d\n",
    392  1782  shidokht 		    bd->interfacepath.pci.bus,
    393  1782  shidokht 		    bd->interfacepath.pci.device,
    394  1782  shidokht 		    bd->interfacepath.pci.function);
    395     0    stevel 
    396     0    stevel 	/* look into devinfo tree and find a node with matching pci b/d/f */
    397  1782  shidokht 	node = search_tree_match_pcibdf(root_node, bd->interfacepath.pci.bus,
    398  1782  shidokht 	    bd->interfacepath.pci.device, bd->interfacepath.pci.function);
    399     0    stevel 
    400     0    stevel 	if (node == DI_NODE_NIL) {
    401     0    stevel 		if (debug)
    402     0    stevel 			(void) printf(" could not find a node in tree "
    403     0    stevel 			    "matching bdf\n");
    404     0    stevel 		return (-1);
    405     0    stevel 	}
    406     0    stevel 
    407  5287  shidokht 	if (debug) {
    408  5287  shidokht 		int i;
    409  5287  shidokht 		(void) printf("interface type ");
    410  5287  shidokht 		for (i = 0; i < 8; i++)
    411  5287  shidokht 			(void) printf("%c", bd->interface_type[i]);
    412  5287  shidokht 		(void) printf(" pci channel %x target %x\n",
    413  5287  shidokht 		    bd->interfacepath.pci.channel,
    414  1782  shidokht 		    bd->devicepath.scsi.target);
    415  5287  shidokht 	}
    416     0    stevel 
    417     0    stevel 	if (strncmp(bd->interface_type, "SCSI", 4) == 0) {
    418     0    stevel 
    419  1782  shidokht 		(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,%x",
    420     0    stevel 		    bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo);
    421     0    stevel 
    422  1782  shidokht 		cnode = search_children_match_busaddr(node, busaddrbuf);
    423     0    stevel 
    424  1782  shidokht 	} else if ((strncmp(bd->interface_type, "ATAPI", 5) == 0) ||
    425  1782  shidokht 	    (strncmp(bd->interface_type, "ATA", 3) == 0) ||
    426  1782  shidokht 	    (strncmp(bd->interface_type, "SATA", 4) == 0)) {
    427     0    stevel 
    428  1782  shidokht 		if (strncmp(di_node_name(node), "pci-ide", 7) == 0) {
    429  1782  shidokht 			/*
    430  1782  shidokht 			 * Legacy using pci-ide
    431  1782  shidokht 			 * the child should be ide@<x>, where x is
    432  1782  shidokht 			 * the channel number
    433  1782  shidokht 			 */
    434  1782  shidokht 			(void) snprintf(busaddrbuf, MAXNAMELEN, "%d",
    435  1782  shidokht 			    bd->interfacepath.pci.channel);
    436     0    stevel 
    437  1782  shidokht 			if ((cnode = search_children_match_busaddr(node,
    438  1782  shidokht 			    busaddrbuf)) != DI_NODE_NIL) {
    439     0    stevel 
    440  1782  shidokht 				(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
    441  1782  shidokht 				    bd->devicepath.ata.chan);
    442  1782  shidokht 				cnode = search_children_match_busaddr(cnode,
    443  1782  shidokht 				    busaddrbuf);
    444     0    stevel 
    445  1782  shidokht 				if (cnode == DI_NODE_NIL)
    446  1782  shidokht 					if (debug)
    447  1782  shidokht 						(void) printf("Interface %s "
    448  1782  shidokht 						    "using pci-ide no "
    449  1782  shidokht 						    "grandchild at %s\n",
    450  1782  shidokht 						    bd->interface_type,
    451  1782  shidokht 						    busaddrbuf);
    452  1782  shidokht 			} else {
    453  1782  shidokht 				if (debug)
    454  1782  shidokht 					(void) printf("Interface %s using "
    455  1782  shidokht 					    "pci-ide, with no child at %s\n",
    456  1782  shidokht 					    bd->interface_type, busaddrbuf);
    457  1782  shidokht 			}
    458  1782  shidokht 		} else {
    459  1782  shidokht 			if (strncmp(bd->interface_type, "SATA", 4) == 0) {
    460  1782  shidokht 				/*
    461  1782  shidokht 				 * The current EDD (EDD-2) spec does not
    462  1782  shidokht 				 * address port number. This is work in
    463  1782  shidokht 				 * progress.
    464  1782  shidokht 				 * Interprete the first field of device path
    465  1782  shidokht 				 * as port number. Needs to be revisited
    466  1782  shidokht 				 * with port multiplier support.
    467  1782  shidokht 				 */
    468  1782  shidokht 				(void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
    469  1782  shidokht 				    bd->devicepath.ata.chan);
    470  1782  shidokht 
    471  1782  shidokht 				cnode = search_children_match_busaddr(node,
    472  1782  shidokht 				    busaddrbuf);
    473  1782  shidokht 			} else {
    474  1782  shidokht 				if (debug)
    475  1782  shidokht 					(void) printf("Interface %s, not using"
    476  1782  shidokht 					    " pci-ide\n", bd->interface_type);
    477  1782  shidokht 			}
    478  1782  shidokht 		}
    479     0    stevel 
    480     0    stevel 	} else if (strncmp(bd->interface_type, "USB", 3) == 0) {
    481  1782  shidokht 		cnode = search_tree_match_usbserialno(node,
    482  1782  shidokht 		    bd->devicepath.usb.usb_serial_id);
    483     0    stevel 	} else {
    484     0    stevel 		if (debug)
    485     0    stevel 			(void) printf("sorry not supported interface %s\n",
    486  1782  shidokht 			    bd->interface_type);
    487     0    stevel 	}
    488     0    stevel 
    489  1782  shidokht 	if (cnode != DI_NODE_NIL) {
    490  1782  shidokht 		devfspath = di_devfs_path(cnode);
    491  1782  shidokht 		index = search_disklist_match_path(devfspath);
    492  1782  shidokht 		di_devfs_path_free(devfspath);
    493  1782  shidokht 		if (index >= 0)
    494  1782  shidokht 			return (index);
    495     0    stevel 	}
    496     0    stevel 
    497     0    stevel 	return (-1);
    498     0    stevel }
    499     0    stevel 
    500     0    stevel /*
    501     0    stevel  * For each disk in list of disks, compare the first block with the
    502     0    stevel  * one from bdd. On the first match, return the index of path in
    503     0    stevel  * disk_list. If none matched return -1.
    504     0    stevel  */
    505     0    stevel static int
    506     0    stevel match_first_block(biosdev_data_t *bd)
    507     0    stevel {
    508     0    stevel 
    509     0    stevel 	char diskpath[MAXPATHLEN];
    510     0    stevel 	int fd;
    511     0    stevel 	char buf[512];
    512     0    stevel 	ssize_t	num_read;
    513     0    stevel 	int i;
    514     0    stevel 
    515     0    stevel 	if (!bd->first_block_valid)
    516     0    stevel 		return (-1);
    517     0    stevel 
    518     0    stevel 	for (i = 0; i < disk_list_valid; i++) {
    519     0    stevel 		(void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw",
    520     0    stevel 		    DEVFS_PREFIX, disk_list[i]);
    521     0    stevel 		fd = open(diskpath, O_RDONLY);
    522     0    stevel 		if (fd  < 0) {
    523     0    stevel 			(void) fprintf(stderr, "opening %s failed errno %d\n",
    524     0    stevel 			    diskpath, errno);
    525     0    stevel 			continue;
    526     0    stevel 		}
    527     0    stevel 		num_read = read(fd, buf, 512);
    528     0    stevel 		if (num_read != 512) {
    529     0    stevel 			(void) printf("read only %d bytes from %s\n", num_read,
    530     0    stevel 			    diskpath);
    531     0    stevel 			continue;
    532     0    stevel 		}
    533     0    stevel 
    534     0    stevel 		if (memcmp(buf, bd->first_block, 512) == 0)	 {
    535     0    stevel 			/* found it */
    536     0    stevel 			return (i);
    537     0    stevel 		}
    538     0    stevel 	}
    539     0    stevel 	return (-1);
    540     0    stevel }
    541     0    stevel 
    542     0    stevel 
    543     0    stevel static void
    544     0    stevel cleanup_and_exit(int exitcode)
    545     0    stevel {
    546     0    stevel 
    547     0    stevel 	free_disks();
    548     0    stevel 
    549     0    stevel 	if (root_node != DI_NODE_NIL)
    550     0    stevel 		di_fini(root_node);
    551     0    stevel 
    552     0    stevel 	if (root_allnode != DI_NODE_NIL)
    553     0    stevel 		di_fini(root_allnode);
    554     0    stevel 
    555     0    stevel 	if (prom_hdl != DI_PROM_HANDLE_NIL)
    556     0    stevel 		di_prom_fini(prom_hdl);
    557     0    stevel 	exit(exitcode);
    558     0    stevel 
    559     0    stevel }
    560     0    stevel 
    561     0    stevel 
    562     0    stevel int
    563     0    stevel main(int argc, char *argv[])
    564     0    stevel {
    565     0    stevel 	biosdev_data_t		*biosdata;
    566  5287  shidokht 	int i, c, j;
    567     0    stevel 	int matchedindex = -1;
    568     0    stevel 	char biospropname[BIOSPROPNAME_TMPL_LEN];
    569     0    stevel 	int totalmatches = 0;
    570  5287  shidokht 	biosdev_data_t *biosdataarray[BIOSDEV_NUM];
    571     0    stevel 
    572     0    stevel 
    573     0    stevel 	while ((c = getopt(argc, argv, "d")) != -1)  {
    574     0    stevel 		switch (c) {
    575     0    stevel 		case 'd':
    576     0    stevel 			debug = 1;
    577     0    stevel 			break;
    578     0    stevel 		default:
    579     0    stevel 			(void) printf("unknown option %c\n", c);
    580     0    stevel 			exit(1);
    581     0    stevel 		}
    582     0    stevel 	}
    583     0    stevel 
    584     0    stevel 	if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
    585     0    stevel 		(void) fprintf(stderr, "di_prom_init failed\n");
    586     0    stevel 		cleanup_and_exit(1);
    587     0    stevel 	}
    588     0    stevel 
    589     0    stevel 	if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
    590     0    stevel 		(void) fprintf(stderr, "di_init failed\n");
    591     0    stevel 		cleanup_and_exit(1);
    592     0    stevel 	}
    593     0    stevel 
    594     0    stevel 	if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
    595     0    stevel 		(void) fprintf(stderr, "di_init failed\n");
    596     0    stevel 		cleanup_and_exit(1);
    597     0    stevel 	}
    598     0    stevel 
    599     0    stevel 	(void) memset(mapinfo, 0, sizeof (mapinfo));
    600     0    stevel 
    601     0    stevel 	/* get a list of all disks in the system */
    602     0    stevel 	build_disk_list();
    603     0    stevel 
    604  5287  shidokht 	/*  Get property values that were created at boot up time */
    605     0    stevel 	for (i = 0; i < BIOSDEV_NUM; i++) {
    606     0    stevel 
    607     0    stevel 		(void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN,
    608     0    stevel 		    BIOSPROPNAME_TMPL, i + STARTING_DRVNUM);
    609  5287  shidokht 		if (di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode,
    610  5287  shidokht 		    biospropname, (uchar_t **)&biosdataarray[i]) <= 0)
    611  5287  shidokht 			biosdataarray[i] = NULL;
    612  5287  shidokht 	}
    613     0    stevel 
    614  5287  shidokht 	/* Try to match based on device/interface path info from BIOS */
    615  5287  shidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
    616     0    stevel 
    617  5287  shidokht 		if ((biosdata = biosdataarray[i]) == NULL)
    618     0    stevel 			continue;
    619     0    stevel 		if (debug)
    620  5287  shidokht 			(void) printf("matching edd 0x%x\n",
    621  5287  shidokht 			    i + STARTING_DRVNUM);
    622     0    stevel 
    623     0    stevel 		matchedindex = match_edd(biosdata);
    624     0    stevel 
    625  5287  shidokht 		if (matchedindex != -1) {
    626  5287  shidokht 			if (debug) {
    627  5287  shidokht 				(void) printf("matched by edd\n");
    628  5287  shidokht 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
    629  5287  shidokht 				    disk_list[matchedindex]);
    630  5287  shidokht 			}
    631     0    stevel 
    632     0    stevel 			mapinfo[i].disklist_index = matchedindex;
    633     0    stevel 			mapinfo[i].matchcount++;
    634  5287  shidokht 
    635     0    stevel 			for (j = 0; j < i; j++) {
    636     0    stevel 				if (mapinfo[j].matchcount > 0 &&
    637     0    stevel 				    mapinfo[j].disklist_index == matchedindex) {
    638     0    stevel 					mapinfo[j].matchcount++;
    639     0    stevel 					mapinfo[i].matchcount++;
    640     0    stevel 				}
    641     0    stevel 			}
    642     0    stevel 
    643  5287  shidokht 		} else
    644  5287  shidokht 			if (debug)
    645  5287  shidokht 				(void) printf("No matches by edd\n");
    646     0    stevel 	}
    647  5287  shidokht 
    648  5287  shidokht 	/*
    649  5287  shidokht 	 * Go through the list and ignore any found matches that are dups.
    650  5287  shidokht 	 * This is to workaround issues with BIOSes that do not implement
    651  5287  shidokht 	 * providing interface/device path info correctly.
    652  5287  shidokht 	 */
    653  5287  shidokht 
    654  5287  shidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
    655  5287  shidokht 		if (mapinfo[i].matchcount > 1) {
    656  5287  shidokht 			if (debug)
    657  5287  shidokht 				(void) printf("Ignoring dup match_edd\n(count "
    658  5287  shidokht 				    "%d): 0x%x %s\n", mapinfo[i].matchcount,
    659  5287  shidokht 				    i + STARTING_DRVNUM,
    660  5287  shidokht 				    disk_list[mapinfo[i].disklist_index]);
    661  5287  shidokht 
    662  5287  shidokht 			mapinfo[i].matchcount = 0;
    663  5287  shidokht 			mapinfo[i].disklist_index = 0;
    664  5287  shidokht 		}
    665  5287  shidokht 	}
    666  5287  shidokht 
    667  5287  shidokht 
    668  5287  shidokht 	/*
    669  5287  shidokht 	 * For each bios dev number that we do not have exactly one match
    670  5287  shidokht 	 * already, try to match based on first block
    671  5287  shidokht 	 */
    672  5287  shidokht 	for (i = 0; i < BIOSDEV_NUM; i++) {
    673  5287  shidokht 		if (mapinfo[i].matchcount == 1)
    674  5287  shidokht 			continue;
    675  5287  shidokht 
    676  5287  shidokht 		if ((biosdata = biosdataarray[i]) == NULL)
    677  5287  shidokht 			continue;
    678  5287  shidokht 
    679  5287  shidokht 		if (debug)
    680  5287  shidokht 			(void) printf("matching first block 0x%x\n",
    681  5287  shidokht 			    i + STARTING_DRVNUM);
    682  5287  shidokht 
    683  5287  shidokht 		matchedindex = match_first_block(biosdata);
    684  5287  shidokht 		if (matchedindex != -1) {
    685  5287  shidokht 			if (debug) {
    686  5287  shidokht 				(void) printf("matched by first block\n");
    687  5287  shidokht 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
    688  5287  shidokht 				    disk_list[matchedindex]);
    689  5287  shidokht 			}
    690  5287  shidokht 
    691  5287  shidokht 			mapinfo[i].disklist_index = matchedindex;
    692  5287  shidokht 			mapinfo[i].matchcount++;
    693  5287  shidokht 
    694  5287  shidokht 			for (j = 0; j < i; j++) {
    695  5287  shidokht 				if (mapinfo[j].matchcount > 0 &&
    696  5287  shidokht 				    mapinfo[j].disklist_index == matchedindex) {
    697  5287  shidokht 					mapinfo[j].matchcount++;
    698  5287  shidokht 					mapinfo[i].matchcount++;
    699  5287  shidokht 				}
    700  5287  shidokht 			}
    701  5287  shidokht 		} else
    702  5287  shidokht 			if (debug) {
    703  5287  shidokht 				(void) printf(" No matches by first block\n");
    704  5287  shidokht 				(void) fprintf(stderr, "Could not match 0x%x\n",
    705  5287  shidokht 				    i + STARTING_DRVNUM);
    706  5287  shidokht 			}
    707  5287  shidokht 	}
    708  5287  shidokht 
    709     0    stevel 
    710     0    stevel 	for (i = 0; i < BIOSDEV_NUM; i++) {
    711     0    stevel 		if (mapinfo[i].matchcount == 1) {
    712     0    stevel 			(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
    713     0    stevel 			    disk_list[mapinfo[i].disklist_index]);
    714     0    stevel 			totalmatches++;
    715     0    stevel 		} else if (debug && mapinfo[i].matchcount > 1) {
    716     0    stevel 			(void) printf("0x%x %s matchcount %d\n",
    717     0    stevel 			    i + STARTING_DRVNUM,
    718     0    stevel 			    disk_list[mapinfo[i].disklist_index],
    719  1782  shidokht 			    mapinfo[i].matchcount);
    720     0    stevel 		}
    721     0    stevel 	}
    722     0    stevel 
    723     0    stevel 	if (totalmatches == 0) {
    724     0    stevel 		(void) fprintf(stderr, "biosdev: Could not match any!!\n");
    725     0    stevel 		cleanup_and_exit(1);
    726     0    stevel 	}
    727     0    stevel 
    728     0    stevel 	cleanup_and_exit(0);
    729     0    stevel 	/* NOTREACHED */
    730     0    stevel 	return (0);
    731     0    stevel }
    732