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 **)®buf);
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 **)®buf);
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