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 #pragma ident "%Z%%M% %I% %E% SMI"
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <sys/param.h>
337c478bd9Sstevel@tonic-gate #include <errno.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <dirent.h>
367c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
377c478bd9Sstevel@tonic-gate #include <fcntl.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <sys/stat.h>
407c478bd9Sstevel@tonic-gate #include <sys/pci.h>
417c478bd9Sstevel@tonic-gate #include <sys/biosdisk.h>
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate * structure used for searching device tree for a node matching
467c478bd9Sstevel@tonic-gate * pci bus/dev/fn
477c478bd9Sstevel@tonic-gate */
487c478bd9Sstevel@tonic-gate typedef struct pcibdf {
497c478bd9Sstevel@tonic-gate int busnum;
507c478bd9Sstevel@tonic-gate int devnum;
517c478bd9Sstevel@tonic-gate int funcnum;
527c478bd9Sstevel@tonic-gate di_node_t di_node;
537c478bd9Sstevel@tonic-gate } pcibdf_t;
547c478bd9Sstevel@tonic-gate
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate * structure used for searching device tree for a node matching
577c478bd9Sstevel@tonic-gate * USB serial number.
587c478bd9Sstevel@tonic-gate */
597c478bd9Sstevel@tonic-gate typedef struct {
607c478bd9Sstevel@tonic-gate uint64_t serialno;
617c478bd9Sstevel@tonic-gate di_node_t node;
627c478bd9Sstevel@tonic-gate } usbser_t;
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate * structure for holding the mapping info
667c478bd9Sstevel@tonic-gate */
677c478bd9Sstevel@tonic-gate typedef struct {
687c478bd9Sstevel@tonic-gate int disklist_index; /* index to disk_list of the mapped path */
697c478bd9Sstevel@tonic-gate int matchcount; /* number of matches per this device number */
707c478bd9Sstevel@tonic-gate } mapinfo_t;
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #define DEVFS_PREFIX "/devices"
737c478bd9Sstevel@tonic-gate #define DISKS_LIST_INCR 20 /* increment for resizing disk_list */
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate #define BIOSPROPNAME_TMPL "biosdev-0x%x"
767c478bd9Sstevel@tonic-gate #define BIOSPROPNAME_TMPL_LEN 13
777c478bd9Sstevel@tonic-gate #define BIOSDEV_NUM 8
787c478bd9Sstevel@tonic-gate #define STARTING_DRVNUM 0x80
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * array to hold mappings. Element at index X corresponds to BIOS device
827c478bd9Sstevel@tonic-gate * number 0x80 + X
837c478bd9Sstevel@tonic-gate */
847c478bd9Sstevel@tonic-gate static mapinfo_t mapinfo[BIOSDEV_NUM];
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate /*
877c478bd9Sstevel@tonic-gate * Cache copy of kernel device tree snapshot root handle, includes devices
887c478bd9Sstevel@tonic-gate * that are detached
897c478bd9Sstevel@tonic-gate */
907c478bd9Sstevel@tonic-gate static di_node_t root_node = DI_NODE_NIL;
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate * kernel device tree snapshot with currently attached devices. Detached
947c478bd9Sstevel@tonic-gate * devices are not included.
957c478bd9Sstevel@tonic-gate */
967c478bd9Sstevel@tonic-gate static di_node_t root_allnode = DI_NODE_NIL;
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate * handle to retrieve prom properties
1007c478bd9Sstevel@tonic-gate */
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate static char **disk_list = NULL; /* array of physical device pathnames */
1057c478bd9Sstevel@tonic-gate static int disk_list_len = 0; /* length of disk_list */
1067c478bd9Sstevel@tonic-gate static int disk_list_valid = 0; /* number of valid entries in disk_list */
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate static int debug = 0; /* used for enabling debug output */
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /* Local function prototypes */
1127c478bd9Sstevel@tonic-gate static void new_disk_list_entry(di_node_t node);
113d155f3feSshidokht static int i_disktype(di_node_t node, di_minor_t minor, void *arg);
1147c478bd9Sstevel@tonic-gate static void build_disk_list();
115d155f3feSshidokht static int search_disklist_match_path(char *path);
1167c478bd9Sstevel@tonic-gate static void free_disks();
117d155f3feSshidokht static void cleanup_and_exit(int);
118d155f3feSshidokht
1197c478bd9Sstevel@tonic-gate static int match_edd(biosdev_data_t *bd);
1207c478bd9Sstevel@tonic-gate static int match_first_block(biosdev_data_t *bd);
121d155f3feSshidokht
122d155f3feSshidokht static di_node_t search_tree_match_pcibdf(di_node_t node, int bus, int dev,
123d155f3feSshidokht int fn);
124d155f3feSshidokht static int i_match_pcibdf(di_node_t node, void *arg);
125d155f3feSshidokht
126d155f3feSshidokht static di_node_t search_tree_match_usbserialno(di_node_t node,
127d155f3feSshidokht uint64_t serialno);
128d155f3feSshidokht static int i_match_usbserialno(di_node_t node, void *arg);
129d155f3feSshidokht
130d155f3feSshidokht static di_node_t search_children_match_busaddr(di_node_t node,
131d155f3feSshidokht char *matchbusaddr);
132d155f3feSshidokht
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate static void
new_disk_list_entry(di_node_t node)1367c478bd9Sstevel@tonic-gate new_disk_list_entry(di_node_t node)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate size_t newsize;
1397c478bd9Sstevel@tonic-gate char **newlist;
1407c478bd9Sstevel@tonic-gate int newlen;
1417c478bd9Sstevel@tonic-gate char *devfspath;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate if (disk_list_valid >= disk_list_len) {
1447c478bd9Sstevel@tonic-gate /* valid should never really be larger than len */
1457c478bd9Sstevel@tonic-gate /* if they are equal we need to init or realloc */
1467c478bd9Sstevel@tonic-gate newlen = disk_list_len + DISKS_LIST_INCR;
1477c478bd9Sstevel@tonic-gate newsize = newlen * sizeof (*disk_list);
1487c478bd9Sstevel@tonic-gate
1497c478bd9Sstevel@tonic-gate newlist = (char **)realloc(disk_list, newsize);
1507c478bd9Sstevel@tonic-gate if (newlist == NULL) {
1517c478bd9Sstevel@tonic-gate (void) printf("realloc failed to resize disk table\n");
1527c478bd9Sstevel@tonic-gate cleanup_and_exit(1);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate disk_list = newlist;
1557c478bd9Sstevel@tonic-gate disk_list_len = newlen;
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate devfspath = di_devfs_path(node);
1597c478bd9Sstevel@tonic-gate disk_list[disk_list_valid] = devfspath;
1607c478bd9Sstevel@tonic-gate if (debug)
1617c478bd9Sstevel@tonic-gate (void) printf("adding %s\n", devfspath);
1627c478bd9Sstevel@tonic-gate disk_list_valid++;
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /* ARGSUSED */
1667c478bd9Sstevel@tonic-gate static int
i_disktype(di_node_t node,di_minor_t minor,void * arg)167d155f3feSshidokht i_disktype(di_node_t node, di_minor_t minor, void *arg)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate char *minortype;
1707c478bd9Sstevel@tonic-gate
1717c478bd9Sstevel@tonic-gate if (di_minor_spectype(minor) == S_IFCHR) {
1727c478bd9Sstevel@tonic-gate minortype = di_minor_nodetype(minor);
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate /* exclude CD's */
1757c478bd9Sstevel@tonic-gate if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0)
1767c478bd9Sstevel@tonic-gate /* only take p0 raw device */
1777c478bd9Sstevel@tonic-gate if (strcmp(di_minor_name(minor), "q,raw") == 0)
1787c478bd9Sstevel@tonic-gate new_disk_list_entry(node);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate static void
build_disk_list()1847c478bd9Sstevel@tonic-gate build_disk_list()
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate int ret;
1877c478bd9Sstevel@tonic-gate ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL,
188d155f3feSshidokht i_disktype);
1897c478bd9Sstevel@tonic-gate if (ret != 0) {
1907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_walk_minor failed errno %d\n",
1917c478bd9Sstevel@tonic-gate errno);
1927c478bd9Sstevel@tonic-gate cleanup_and_exit(1);
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate static void
free_disks()1977c478bd9Sstevel@tonic-gate free_disks()
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate int i;
2007c478bd9Sstevel@tonic-gate
2017c478bd9Sstevel@tonic-gate if (disk_list) {
2027c478bd9Sstevel@tonic-gate for (i = 0; i < disk_list_valid; i++)
2037c478bd9Sstevel@tonic-gate di_devfs_path_free(disk_list[i]);
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate free(disk_list);
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate static int
i_match_pcibdf(di_node_t node,void * arg)210d155f3feSshidokht i_match_pcibdf(di_node_t node, void *arg)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate pcibdf_t *pbp;
2137c478bd9Sstevel@tonic-gate int len;
2147c478bd9Sstevel@tonic-gate uint32_t regval;
2157c478bd9Sstevel@tonic-gate uint32_t busnum, funcnum, devicenum;
2167c478bd9Sstevel@tonic-gate char *devtype;
2177c478bd9Sstevel@tonic-gate uint32_t *regbuf = NULL;
2187c478bd9Sstevel@tonic-gate di_node_t parentnode;
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate pbp = (pcibdf_t *)arg;
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate parentnode = di_parent_node(node);
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
2257c478bd9Sstevel@tonic-gate "device_type", (char **)&devtype);
2267c478bd9Sstevel@tonic-gate
22770025d76Sjohnny if ((len <= 0) ||
22870025d76Sjohnny ((strcmp(devtype, "pci") != 0) && (strcmp(devtype, "pciex") != 0)))
2297c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg",
2327c478bd9Sstevel@tonic-gate (int **)®buf);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate if (len <= 0) {
2357c478bd9Sstevel@tonic-gate /* Try PROM property */
2367c478bd9Sstevel@tonic-gate len = di_prom_prop_lookup_ints(prom_hdl, node, "reg",
2377c478bd9Sstevel@tonic-gate (int **)®buf);
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate
2417c478bd9Sstevel@tonic-gate if (len > 0) {
2427c478bd9Sstevel@tonic-gate regval = regbuf[0];
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate busnum = PCI_REG_BUS_G(regval);
2457c478bd9Sstevel@tonic-gate devicenum = PCI_REG_DEV_G(regval);
2467c478bd9Sstevel@tonic-gate funcnum = PCI_REG_FUNC_G(regval);
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate if ((busnum == pbp->busnum) &&
2497c478bd9Sstevel@tonic-gate (devicenum == pbp->devnum) &&
2507c478bd9Sstevel@tonic-gate (funcnum == pbp->funcnum)) {
2517c478bd9Sstevel@tonic-gate /* found it */
2527c478bd9Sstevel@tonic-gate pbp->di_node = node;
2537c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate static di_node_t
search_tree_match_pcibdf(di_node_t node,int bus,int dev,int fn)261d155f3feSshidokht search_tree_match_pcibdf(di_node_t node, int bus, int dev, int fn)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate pcibdf_t pb;
2647c478bd9Sstevel@tonic-gate pb.busnum = bus;
2657c478bd9Sstevel@tonic-gate pb.devnum = dev;
2667c478bd9Sstevel@tonic-gate pb.funcnum = fn;
2677c478bd9Sstevel@tonic-gate pb.di_node = DI_NODE_NIL;
2687c478bd9Sstevel@tonic-gate
269d155f3feSshidokht (void) di_walk_node(node, DI_WALK_CLDFIRST, &pb, i_match_pcibdf);
2707c478bd9Sstevel@tonic-gate return (pb.di_node);
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate static int
i_match_usbserialno(di_node_t node,void * arg)275d155f3feSshidokht i_match_usbserialno(di_node_t node, void *arg)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate int len;
2787c478bd9Sstevel@tonic-gate char *serialp;
2797c478bd9Sstevel@tonic-gate usbser_t *usbsp;
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate usbsp = (usbser_t *)arg;
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno",
2847c478bd9Sstevel@tonic-gate (uchar_t **)&serialp);
2857c478bd9Sstevel@tonic-gate
286d155f3feSshidokht if ((len > 0) && (strncmp((char *)&usbsp->serialno, serialp,
287d155f3feSshidokht sizeof (uint64_t)) == 0)) {
2887c478bd9Sstevel@tonic-gate usbsp->node = node;
2897c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE);
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate static di_node_t
search_tree_match_usbserialno(di_node_t node,uint64_t serialno)295d155f3feSshidokht search_tree_match_usbserialno(di_node_t node, uint64_t serialno)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate usbser_t usbs;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate usbs.serialno = serialno;
3017c478bd9Sstevel@tonic-gate usbs.node = DI_NODE_NIL;
3027c478bd9Sstevel@tonic-gate
303d155f3feSshidokht (void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, i_match_usbserialno);
3047c478bd9Sstevel@tonic-gate return (usbs.node);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate
307d155f3feSshidokht /*
308d155f3feSshidokht * returns the index to the disklist to the disk with matching path
309d155f3feSshidokht */
3107c478bd9Sstevel@tonic-gate static int
search_disklist_match_path(char * path)311d155f3feSshidokht search_disklist_match_path(char *path)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate int i;
3147c478bd9Sstevel@tonic-gate for (i = 0; i < disk_list_valid; i++)
3157c478bd9Sstevel@tonic-gate if (strcmp(disk_list[i], path) == 0) {
3167c478bd9Sstevel@tonic-gate return (i);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate return (-1);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate
321d155f3feSshidokht /*
322d155f3feSshidokht * Find first child of 'node' whose unit address is 'matchbusaddr'
323d155f3feSshidokht */
324d155f3feSshidokht static di_node_t
search_children_match_busaddr(di_node_t node,char * matchbusaddr)325d155f3feSshidokht search_children_match_busaddr(di_node_t node, char *matchbusaddr)
326d155f3feSshidokht {
327d155f3feSshidokht di_node_t cnode;
328d155f3feSshidokht char *busaddr;
32944d788f4Sgap di_path_t pi = DI_PATH_NIL;
330d155f3feSshidokht
331d155f3feSshidokht if (matchbusaddr == NULL)
332d155f3feSshidokht return (DI_NODE_NIL);
333d155f3feSshidokht
334*602ca9eaScth while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) {
335*602ca9eaScth busaddr = di_path_bus_addr(pi);
336*602ca9eaScth if (busaddr == NULL)
337*602ca9eaScth continue;
338*602ca9eaScth if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
33944d788f4Sgap return (di_path_client_node(pi));
340*602ca9eaScth }
341d155f3feSshidokht
342d155f3feSshidokht for (cnode = di_child_node(node); cnode != DI_NODE_NIL;
343d155f3feSshidokht cnode = di_sibling_node(cnode)) {
344d155f3feSshidokht busaddr = di_bus_addr(cnode);
345d155f3feSshidokht if (busaddr == NULL)
346d155f3feSshidokht continue;
347d155f3feSshidokht if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0)
348d155f3feSshidokht return (cnode);
349d155f3feSshidokht }
3507c478bd9Sstevel@tonic-gate
351*602ca9eaScth return (DI_NODE_NIL);
352*602ca9eaScth }
353*602ca9eaScth
3547c478bd9Sstevel@tonic-gate /*
3557c478bd9Sstevel@tonic-gate * Construct a physical device pathname from EDD and verify the
3567c478bd9Sstevel@tonic-gate * path exists. Return the index of in disk_list for the mapped
3577c478bd9Sstevel@tonic-gate * path on success, -1 on failure.
3587c478bd9Sstevel@tonic-gate */
3597c478bd9Sstevel@tonic-gate static int
match_edd(biosdev_data_t * bdata)3607c478bd9Sstevel@tonic-gate match_edd(biosdev_data_t *bdata)
3617c478bd9Sstevel@tonic-gate {
362d155f3feSshidokht di_node_t node, cnode = DI_NODE_NIL;
363d155f3feSshidokht char *devfspath = NULL;
3647c478bd9Sstevel@tonic-gate fn48_t *bd;
3657c478bd9Sstevel@tonic-gate int index;
366d155f3feSshidokht char busaddrbuf[MAXNAMELEN];
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate if (!bdata->edd_valid) {
3697c478bd9Sstevel@tonic-gate if (debug)
3707c478bd9Sstevel@tonic-gate (void) printf("edd not valid\n");
3717c478bd9Sstevel@tonic-gate return (-1);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate
3747c478bd9Sstevel@tonic-gate bd = &bdata->fn48_dev_params;
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) {
3777c478bd9Sstevel@tonic-gate /* EDD extensions for devicepath not present */
3787c478bd9Sstevel@tonic-gate if (debug)
3797c478bd9Sstevel@tonic-gate (void) printf("magic not valid %x pathinfolen %d\n",
3807c478bd9Sstevel@tonic-gate bd->magic, bd->pathinfo_len);
3817c478bd9Sstevel@tonic-gate return (-1);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate /* we handle only PCI scsi, ata or sata for now */
3857c478bd9Sstevel@tonic-gate if (strncmp(bd->bustype, "PCI", 3) != 0) {
3867c478bd9Sstevel@tonic-gate if (debug)
3877c478bd9Sstevel@tonic-gate (void) printf("was not pci %s\n", bd->bustype);
3887c478bd9Sstevel@tonic-gate return (-1);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate if (debug)
3917c478bd9Sstevel@tonic-gate (void) printf("match_edd bdf %d %d %d\n",
3927c478bd9Sstevel@tonic-gate bd->interfacepath.pci.bus,
3937c478bd9Sstevel@tonic-gate bd->interfacepath.pci.device,
3947c478bd9Sstevel@tonic-gate bd->interfacepath.pci.function);
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /* look into devinfo tree and find a node with matching pci b/d/f */
397d155f3feSshidokht node = search_tree_match_pcibdf(root_node, bd->interfacepath.pci.bus,
398d155f3feSshidokht bd->interfacepath.pci.device, bd->interfacepath.pci.function);
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate if (node == DI_NODE_NIL) {
4017c478bd9Sstevel@tonic-gate if (debug)
4027c478bd9Sstevel@tonic-gate (void) printf(" could not find a node in tree "
4037c478bd9Sstevel@tonic-gate "matching bdf\n");
4047c478bd9Sstevel@tonic-gate return (-1);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
407801d74ddSshidokht if (debug) {
408801d74ddSshidokht int i;
409801d74ddSshidokht (void) printf("interface type ");
410801d74ddSshidokht for (i = 0; i < 8; i++)
411801d74ddSshidokht (void) printf("%c", bd->interface_type[i]);
412801d74ddSshidokht (void) printf(" pci channel %x target %x\n",
413801d74ddSshidokht bd->interfacepath.pci.channel,
414d155f3feSshidokht bd->devicepath.scsi.target);
415801d74ddSshidokht }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate if (strncmp(bd->interface_type, "SCSI", 4) == 0) {
4187c478bd9Sstevel@tonic-gate
419d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,%x",
4207c478bd9Sstevel@tonic-gate bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo);
4217c478bd9Sstevel@tonic-gate
422d155f3feSshidokht cnode = search_children_match_busaddr(node, busaddrbuf);
4237c478bd9Sstevel@tonic-gate
424d155f3feSshidokht } else if ((strncmp(bd->interface_type, "ATAPI", 5) == 0) ||
425d155f3feSshidokht (strncmp(bd->interface_type, "ATA", 3) == 0) ||
426d155f3feSshidokht (strncmp(bd->interface_type, "SATA", 4) == 0)) {
427d155f3feSshidokht
428d155f3feSshidokht if (strncmp(di_node_name(node), "pci-ide", 7) == 0) {
429d155f3feSshidokht /*
430d155f3feSshidokht * Legacy using pci-ide
431d155f3feSshidokht * the child should be ide@<x>, where x is
432d155f3feSshidokht * the channel number
433d155f3feSshidokht */
434d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%d",
435d155f3feSshidokht bd->interfacepath.pci.channel);
436d155f3feSshidokht
437d155f3feSshidokht if ((cnode = search_children_match_busaddr(node,
438d155f3feSshidokht busaddrbuf)) != DI_NODE_NIL) {
439d155f3feSshidokht
440d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
441d155f3feSshidokht bd->devicepath.ata.chan);
442d155f3feSshidokht cnode = search_children_match_busaddr(cnode,
443d155f3feSshidokht busaddrbuf);
444d155f3feSshidokht
445d155f3feSshidokht if (cnode == DI_NODE_NIL)
446d155f3feSshidokht if (debug)
447d155f3feSshidokht (void) printf("Interface %s "
448d155f3feSshidokht "using pci-ide no "
449d155f3feSshidokht "grandchild at %s\n",
450d155f3feSshidokht bd->interface_type,
451d155f3feSshidokht busaddrbuf);
452d155f3feSshidokht } else {
453d155f3feSshidokht if (debug)
454d155f3feSshidokht (void) printf("Interface %s using "
455d155f3feSshidokht "pci-ide, with no child at %s\n",
456d155f3feSshidokht bd->interface_type, busaddrbuf);
457d155f3feSshidokht }
458d155f3feSshidokht } else {
459d155f3feSshidokht if (strncmp(bd->interface_type, "SATA", 4) == 0) {
460d155f3feSshidokht /*
461d155f3feSshidokht * The current EDD (EDD-2) spec does not
462d155f3feSshidokht * address port number. This is work in
463d155f3feSshidokht * progress.
464d155f3feSshidokht * Interprete the first field of device path
465d155f3feSshidokht * as port number. Needs to be revisited
466d155f3feSshidokht * with port multiplier support.
467d155f3feSshidokht */
468d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0",
4697c478bd9Sstevel@tonic-gate bd->devicepath.ata.chan);
4707c478bd9Sstevel@tonic-gate
471d155f3feSshidokht cnode = search_children_match_busaddr(node,
472d155f3feSshidokht busaddrbuf);
473d155f3feSshidokht } else {
474d155f3feSshidokht if (debug)
475d155f3feSshidokht (void) printf("Interface %s, not using"
476d155f3feSshidokht " pci-ide\n", bd->interface_type);
477d155f3feSshidokht }
478d155f3feSshidokht }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate } else if (strncmp(bd->interface_type, "USB", 3) == 0) {
481d155f3feSshidokht cnode = search_tree_match_usbserialno(node,
482d155f3feSshidokht bd->devicepath.usb.usb_serial_id);
4837c478bd9Sstevel@tonic-gate } else {
4847c478bd9Sstevel@tonic-gate if (debug)
4857c478bd9Sstevel@tonic-gate (void) printf("sorry not supported interface %s\n",
4867c478bd9Sstevel@tonic-gate bd->interface_type);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate
489d155f3feSshidokht if (cnode != DI_NODE_NIL) {
490d155f3feSshidokht devfspath = di_devfs_path(cnode);
491d155f3feSshidokht index = search_disklist_match_path(devfspath);
492d155f3feSshidokht di_devfs_path_free(devfspath);
493d155f3feSshidokht if (index >= 0)
4947c478bd9Sstevel@tonic-gate return (index);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate return (-1);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate * For each disk in list of disks, compare the first block with the
5027c478bd9Sstevel@tonic-gate * one from bdd. On the first match, return the index of path in
5037c478bd9Sstevel@tonic-gate * disk_list. If none matched return -1.
5047c478bd9Sstevel@tonic-gate */
5057c478bd9Sstevel@tonic-gate static int
match_first_block(biosdev_data_t * bd)5067c478bd9Sstevel@tonic-gate match_first_block(biosdev_data_t *bd)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate char diskpath[MAXPATHLEN];
5107c478bd9Sstevel@tonic-gate int fd;
5117c478bd9Sstevel@tonic-gate char buf[512];
5127c478bd9Sstevel@tonic-gate ssize_t num_read;
5137c478bd9Sstevel@tonic-gate int i;
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate if (!bd->first_block_valid)
5167c478bd9Sstevel@tonic-gate return (-1);
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate for (i = 0; i < disk_list_valid; i++) {
5197c478bd9Sstevel@tonic-gate (void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw",
5207c478bd9Sstevel@tonic-gate DEVFS_PREFIX, disk_list[i]);
5217c478bd9Sstevel@tonic-gate fd = open(diskpath, O_RDONLY);
5227c478bd9Sstevel@tonic-gate if (fd < 0) {
5237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "opening %s failed errno %d\n",
5247c478bd9Sstevel@tonic-gate diskpath, errno);
5257c478bd9Sstevel@tonic-gate continue;
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate num_read = read(fd, buf, 512);
5287c478bd9Sstevel@tonic-gate if (num_read != 512) {
5297c478bd9Sstevel@tonic-gate (void) printf("read only %d bytes from %s\n", num_read,
5307c478bd9Sstevel@tonic-gate diskpath);
5317c478bd9Sstevel@tonic-gate continue;
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate if (memcmp(buf, bd->first_block, 512) == 0) {
5357c478bd9Sstevel@tonic-gate /* found it */
5367c478bd9Sstevel@tonic-gate return (i);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate return (-1);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate
5437c478bd9Sstevel@tonic-gate static void
cleanup_and_exit(int exitcode)5447c478bd9Sstevel@tonic-gate cleanup_and_exit(int exitcode)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate free_disks();
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate if (root_node != DI_NODE_NIL)
5507c478bd9Sstevel@tonic-gate di_fini(root_node);
5517c478bd9Sstevel@tonic-gate
5527c478bd9Sstevel@tonic-gate if (root_allnode != DI_NODE_NIL)
5537c478bd9Sstevel@tonic-gate di_fini(root_allnode);
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate if (prom_hdl != DI_PROM_HANDLE_NIL)
5567c478bd9Sstevel@tonic-gate di_prom_fini(prom_hdl);
5577c478bd9Sstevel@tonic-gate exit(exitcode);
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])5637c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate biosdev_data_t *biosdata;
566801d74ddSshidokht int i, c, j;
5677c478bd9Sstevel@tonic-gate int matchedindex = -1;
5687c478bd9Sstevel@tonic-gate char biospropname[BIOSPROPNAME_TMPL_LEN];
5697c478bd9Sstevel@tonic-gate int totalmatches = 0;
570801d74ddSshidokht biosdev_data_t *biosdataarray[BIOSDEV_NUM];
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d")) != -1) {
5747c478bd9Sstevel@tonic-gate switch (c) {
5757c478bd9Sstevel@tonic-gate case 'd':
5767c478bd9Sstevel@tonic-gate debug = 1;
5777c478bd9Sstevel@tonic-gate break;
5787c478bd9Sstevel@tonic-gate default:
5797c478bd9Sstevel@tonic-gate (void) printf("unknown option %c\n", c);
5807c478bd9Sstevel@tonic-gate exit(1);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
5857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_prom_init failed\n");
5867c478bd9Sstevel@tonic-gate cleanup_and_exit(1);
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
5907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_init failed\n");
5917c478bd9Sstevel@tonic-gate cleanup_and_exit(1);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
5957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_init failed\n");
5967c478bd9Sstevel@tonic-gate cleanup_and_exit(1);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate (void) memset(mapinfo, 0, sizeof (mapinfo));
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /* get a list of all disks in the system */
6027c478bd9Sstevel@tonic-gate build_disk_list();
6037c478bd9Sstevel@tonic-gate
604801d74ddSshidokht /* Get property values that were created at boot up time */
6057c478bd9Sstevel@tonic-gate for (i = 0; i < BIOSDEV_NUM; i++) {
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate (void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN,
6087c478bd9Sstevel@tonic-gate BIOSPROPNAME_TMPL, i + STARTING_DRVNUM);
609801d74ddSshidokht if (di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode,
610801d74ddSshidokht biospropname, (uchar_t **)&biosdataarray[i]) <= 0)
611801d74ddSshidokht biosdataarray[i] = NULL;
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate
614801d74ddSshidokht /* Try to match based on device/interface path info from BIOS */
615801d74ddSshidokht for (i = 0; i < BIOSDEV_NUM; i++) {
616801d74ddSshidokht
617801d74ddSshidokht if ((biosdata = biosdataarray[i]) == NULL)
618801d74ddSshidokht continue;
6197c478bd9Sstevel@tonic-gate if (debug)
620801d74ddSshidokht (void) printf("matching edd 0x%x\n",
621801d74ddSshidokht i + STARTING_DRVNUM);
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate matchedindex = match_edd(biosdata);
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate if (matchedindex != -1) {
626801d74ddSshidokht if (debug) {
627801d74ddSshidokht (void) printf("matched by edd\n");
6287c478bd9Sstevel@tonic-gate (void) printf("0x%x %s\n", i + STARTING_DRVNUM,
6297c478bd9Sstevel@tonic-gate disk_list[matchedindex]);
630801d74ddSshidokht }
631801d74ddSshidokht
632801d74ddSshidokht mapinfo[i].disklist_index = matchedindex;
633801d74ddSshidokht mapinfo[i].matchcount++;
634801d74ddSshidokht
6357c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) {
6367c478bd9Sstevel@tonic-gate if (mapinfo[j].matchcount > 0 &&
6377c478bd9Sstevel@tonic-gate mapinfo[j].disklist_index == matchedindex) {
6387c478bd9Sstevel@tonic-gate mapinfo[j].matchcount++;
6397c478bd9Sstevel@tonic-gate mapinfo[i].matchcount++;
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
643801d74ddSshidokht } else
644801d74ddSshidokht if (debug)
645801d74ddSshidokht (void) printf("No matches by edd\n");
6467c478bd9Sstevel@tonic-gate }
6477c478bd9Sstevel@tonic-gate
648801d74ddSshidokht /*
649801d74ddSshidokht * Go through the list and ignore any found matches that are dups.
650801d74ddSshidokht * This is to workaround issues with BIOSes that do not implement
651801d74ddSshidokht * providing interface/device path info correctly.
652801d74ddSshidokht */
653801d74ddSshidokht
654801d74ddSshidokht for (i = 0; i < BIOSDEV_NUM; i++) {
655801d74ddSshidokht if (mapinfo[i].matchcount > 1) {
656801d74ddSshidokht if (debug)
657801d74ddSshidokht (void) printf("Ignoring dup match_edd\n(count "
658801d74ddSshidokht "%d): 0x%x %s\n", mapinfo[i].matchcount,
659801d74ddSshidokht i + STARTING_DRVNUM,
660801d74ddSshidokht disk_list[mapinfo[i].disklist_index]);
661801d74ddSshidokht
662801d74ddSshidokht mapinfo[i].matchcount = 0;
663801d74ddSshidokht mapinfo[i].disklist_index = 0;
664801d74ddSshidokht }
665801d74ddSshidokht }
666801d74ddSshidokht
667801d74ddSshidokht
668801d74ddSshidokht /*
669801d74ddSshidokht * For each bios dev number that we do not have exactly one match
670801d74ddSshidokht * already, try to match based on first block
671801d74ddSshidokht */
672801d74ddSshidokht for (i = 0; i < BIOSDEV_NUM; i++) {
673801d74ddSshidokht if (mapinfo[i].matchcount == 1)
674801d74ddSshidokht continue;
675801d74ddSshidokht
676801d74ddSshidokht if ((biosdata = biosdataarray[i]) == NULL)
677801d74ddSshidokht continue;
678801d74ddSshidokht
679801d74ddSshidokht if (debug)
680801d74ddSshidokht (void) printf("matching first block 0x%x\n",
681801d74ddSshidokht i + STARTING_DRVNUM);
682801d74ddSshidokht
683801d74ddSshidokht matchedindex = match_first_block(biosdata);
684801d74ddSshidokht if (matchedindex != -1) {
685801d74ddSshidokht if (debug) {
686801d74ddSshidokht (void) printf("matched by first block\n");
687801d74ddSshidokht (void) printf("0x%x %s\n", i + STARTING_DRVNUM,
688801d74ddSshidokht disk_list[matchedindex]);
689801d74ddSshidokht }
690801d74ddSshidokht
691801d74ddSshidokht mapinfo[i].disklist_index = matchedindex;
692801d74ddSshidokht mapinfo[i].matchcount++;
693801d74ddSshidokht
694801d74ddSshidokht for (j = 0; j < i; j++) {
695801d74ddSshidokht if (mapinfo[j].matchcount > 0 &&
696801d74ddSshidokht mapinfo[j].disklist_index == matchedindex) {
697801d74ddSshidokht mapinfo[j].matchcount++;
698801d74ddSshidokht mapinfo[i].matchcount++;
699801d74ddSshidokht }
700801d74ddSshidokht }
701801d74ddSshidokht } else
702801d74ddSshidokht if (debug) {
703801d74ddSshidokht (void) printf(" No matches by first block\n");
704801d74ddSshidokht (void) fprintf(stderr, "Could not match 0x%x\n",
705801d74ddSshidokht i + STARTING_DRVNUM);
706801d74ddSshidokht }
707801d74ddSshidokht }
708801d74ddSshidokht
709801d74ddSshidokht
7107c478bd9Sstevel@tonic-gate for (i = 0; i < BIOSDEV_NUM; i++) {
7117c478bd9Sstevel@tonic-gate if (mapinfo[i].matchcount == 1) {
7127c478bd9Sstevel@tonic-gate (void) printf("0x%x %s\n", i + STARTING_DRVNUM,
7137c478bd9Sstevel@tonic-gate disk_list[mapinfo[i].disklist_index]);
7147c478bd9Sstevel@tonic-gate totalmatches++;
7157c478bd9Sstevel@tonic-gate } else if (debug && mapinfo[i].matchcount > 1) {
7167c478bd9Sstevel@tonic-gate (void) printf("0x%x %s matchcount %d\n",
7177c478bd9Sstevel@tonic-gate i + STARTING_DRVNUM,
7187c478bd9Sstevel@tonic-gate disk_list[mapinfo[i].disklist_index],
7197c478bd9Sstevel@tonic-gate mapinfo[i].matchcount);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate
7237c478bd9Sstevel@tonic-gate if (totalmatches == 0) {
7247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "biosdev: Could not match any!!\n");
7257c478bd9Sstevel@tonic-gate cleanup_and_exit(1);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate cleanup_and_exit(0);
7297c478bd9Sstevel@tonic-gate /* NOTREACHED */
7307c478bd9Sstevel@tonic-gate return (0);
7317c478bd9Sstevel@tonic-gate }
732