xref: /titanic_50/usr/src/cmd/biosdev/biosdev.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <string.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <unistd.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
34*7c478bd9Sstevel@tonic-gate #include <errno.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <dirent.h>
37*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
38*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/pci.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/biosdisk.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate /*
46*7c478bd9Sstevel@tonic-gate  * structure used for searching device tree for a node matching
47*7c478bd9Sstevel@tonic-gate  * pci bus/dev/fn
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate typedef struct pcibdf {
50*7c478bd9Sstevel@tonic-gate 	int busnum;
51*7c478bd9Sstevel@tonic-gate 	int devnum;
52*7c478bd9Sstevel@tonic-gate 	int funcnum;
53*7c478bd9Sstevel@tonic-gate 	di_node_t	di_node;
54*7c478bd9Sstevel@tonic-gate } pcibdf_t;
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate /*
57*7c478bd9Sstevel@tonic-gate  * structure used for searching device tree for a node matching
58*7c478bd9Sstevel@tonic-gate  * USB serial number.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate typedef struct {
61*7c478bd9Sstevel@tonic-gate 	uint64_t serialno;
62*7c478bd9Sstevel@tonic-gate 	di_node_t	node;
63*7c478bd9Sstevel@tonic-gate } usbser_t;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * structure for holding the mapping info
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate typedef struct {
69*7c478bd9Sstevel@tonic-gate 	int disklist_index;	/* index to disk_list of the mapped path */
70*7c478bd9Sstevel@tonic-gate 	int matchcount;		/* number of matches per this device number */
71*7c478bd9Sstevel@tonic-gate } mapinfo_t;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #define	DEVFS_PREFIX "/devices"
74*7c478bd9Sstevel@tonic-gate #define	DISKS_LIST_INCR		20	/* increment for resizing disk_list */
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate #define	BIOSPROPNAME_TMPL	"biosdev-0x%x"
77*7c478bd9Sstevel@tonic-gate #define	BIOSPROPNAME_TMPL_LEN	13
78*7c478bd9Sstevel@tonic-gate #define	BIOSDEV_NUM		8
79*7c478bd9Sstevel@tonic-gate #define	STARTING_DRVNUM		0x80
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * array to hold mappings. Element at index X corresponds to BIOS device
83*7c478bd9Sstevel@tonic-gate  * number 0x80 + X
84*7c478bd9Sstevel@tonic-gate  */
85*7c478bd9Sstevel@tonic-gate static mapinfo_t mapinfo[BIOSDEV_NUM];
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /*
88*7c478bd9Sstevel@tonic-gate  * Cache copy of kernel device tree snapshot root handle, includes devices
89*7c478bd9Sstevel@tonic-gate  * that are detached
90*7c478bd9Sstevel@tonic-gate  */
91*7c478bd9Sstevel@tonic-gate static di_node_t root_node = DI_NODE_NIL;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /*
94*7c478bd9Sstevel@tonic-gate  * kernel device tree snapshot with currently attached devices. Detached
95*7c478bd9Sstevel@tonic-gate  * devices are not included.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate static di_node_t root_allnode = DI_NODE_NIL;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * handle to retrieve prom properties
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate static char **disk_list = NULL;	/* array of physical device pathnames */
106*7c478bd9Sstevel@tonic-gate static int disk_list_len = 0;		/* length of disk_list */
107*7c478bd9Sstevel@tonic-gate static int disk_list_valid = 0;	/* number of valid entries in disk_list */
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static int debug = 0;			/* used for enabling debug output */
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /* Local function prototypes */
113*7c478bd9Sstevel@tonic-gate static void new_disk_list_entry(di_node_t node);
114*7c478bd9Sstevel@tonic-gate static int find_disks_callback(di_node_t node, di_minor_t minor, void *arg);
115*7c478bd9Sstevel@tonic-gate static void build_disk_list();
116*7c478bd9Sstevel@tonic-gate static void free_disks();
117*7c478bd9Sstevel@tonic-gate static int matchpcibdf(di_node_t node, void *arg);
118*7c478bd9Sstevel@tonic-gate static int matchusbserial(di_node_t node, void *arg);
119*7c478bd9Sstevel@tonic-gate static di_node_t search_tree_forpcibdf(int bus, int dev, int fn);
120*7c478bd9Sstevel@tonic-gate static int match_edd(biosdev_data_t *bd);
121*7c478bd9Sstevel@tonic-gate static int match_first_block(biosdev_data_t *bd);
122*7c478bd9Sstevel@tonic-gate static void cleanup_and_exit(int);
123*7c478bd9Sstevel@tonic-gate static int find_path_index_in_disk_list(char *path);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate static void
127*7c478bd9Sstevel@tonic-gate new_disk_list_entry(di_node_t node)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	size_t	newsize;
130*7c478bd9Sstevel@tonic-gate 	char **newlist;
131*7c478bd9Sstevel@tonic-gate 	int newlen;
132*7c478bd9Sstevel@tonic-gate 	char *devfspath;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	if (disk_list_valid >= disk_list_len)	{
135*7c478bd9Sstevel@tonic-gate 		/* valid should never really be larger than len */
136*7c478bd9Sstevel@tonic-gate 		/* if they are equal we need to init or realloc */
137*7c478bd9Sstevel@tonic-gate 		newlen = disk_list_len + DISKS_LIST_INCR;
138*7c478bd9Sstevel@tonic-gate 		newsize = newlen * sizeof (*disk_list);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		newlist = (char **)realloc(disk_list, newsize);
141*7c478bd9Sstevel@tonic-gate 		if (newlist == NULL) {
142*7c478bd9Sstevel@tonic-gate 			(void) printf("realloc failed to resize disk table\n");
143*7c478bd9Sstevel@tonic-gate 			cleanup_and_exit(1);
144*7c478bd9Sstevel@tonic-gate 		}
145*7c478bd9Sstevel@tonic-gate 		disk_list = newlist;
146*7c478bd9Sstevel@tonic-gate 		disk_list_len = newlen;
147*7c478bd9Sstevel@tonic-gate 	}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
150*7c478bd9Sstevel@tonic-gate 	disk_list[disk_list_valid] = devfspath;
151*7c478bd9Sstevel@tonic-gate 	if (debug)
152*7c478bd9Sstevel@tonic-gate 		(void) printf("adding %s\n", devfspath);
153*7c478bd9Sstevel@tonic-gate 	disk_list_valid++;
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
157*7c478bd9Sstevel@tonic-gate static int
158*7c478bd9Sstevel@tonic-gate find_disks_callback(di_node_t node, di_minor_t minor, void *arg)
159*7c478bd9Sstevel@tonic-gate {
160*7c478bd9Sstevel@tonic-gate 	char *minortype;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (di_minor_spectype(minor) == S_IFCHR) {
163*7c478bd9Sstevel@tonic-gate 		minortype = di_minor_nodetype(minor);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 		/* exclude CD's */
166*7c478bd9Sstevel@tonic-gate 		if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0)
167*7c478bd9Sstevel@tonic-gate 			/* only take p0 raw device */
168*7c478bd9Sstevel@tonic-gate 			if (strcmp(di_minor_name(minor), "q,raw") == 0)
169*7c478bd9Sstevel@tonic-gate 				new_disk_list_entry(node);
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
172*7c478bd9Sstevel@tonic-gate }
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate static void
175*7c478bd9Sstevel@tonic-gate build_disk_list()
176*7c478bd9Sstevel@tonic-gate {
177*7c478bd9Sstevel@tonic-gate 	int ret;
178*7c478bd9Sstevel@tonic-gate 	ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL,
179*7c478bd9Sstevel@tonic-gate 	    find_disks_callback);
180*7c478bd9Sstevel@tonic-gate 	if (ret != 0) {
181*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_walk_minor failed errno %d\n",
182*7c478bd9Sstevel@tonic-gate 		    errno);
183*7c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
184*7c478bd9Sstevel@tonic-gate 	}
185*7c478bd9Sstevel@tonic-gate }
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate static void
188*7c478bd9Sstevel@tonic-gate free_disks()
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	int i;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	if (disk_list) {
193*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < disk_list_valid; i++)
194*7c478bd9Sstevel@tonic-gate 			di_devfs_path_free(disk_list[i]);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 		free(disk_list);
197*7c478bd9Sstevel@tonic-gate 	}
198*7c478bd9Sstevel@tonic-gate }
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate static int
201*7c478bd9Sstevel@tonic-gate matchpcibdf(di_node_t node, void *arg)
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate 	pcibdf_t *pbp;
204*7c478bd9Sstevel@tonic-gate 	int len;
205*7c478bd9Sstevel@tonic-gate 	uint32_t	regval;
206*7c478bd9Sstevel@tonic-gate 	uint32_t	busnum, funcnum, devicenum;
207*7c478bd9Sstevel@tonic-gate 	char *devtype;
208*7c478bd9Sstevel@tonic-gate 	uint32_t *regbuf = NULL;
209*7c478bd9Sstevel@tonic-gate 	di_node_t	parentnode;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	pbp = (pcibdf_t *)arg;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	parentnode = di_parent_node(node);
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
216*7c478bd9Sstevel@tonic-gate 	    "device_type", (char **)&devtype);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if ((len <= 0) || (strcmp(devtype, "pci") != 0))
219*7c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg",
222*7c478bd9Sstevel@tonic-gate 	    (int **)&regbuf);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	if (len <= 0) {
225*7c478bd9Sstevel@tonic-gate 		/* Try PROM property */
226*7c478bd9Sstevel@tonic-gate 		len = di_prom_prop_lookup_ints(prom_hdl, node, "reg",
227*7c478bd9Sstevel@tonic-gate 		    (int **)&regbuf);
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	if (len > 0) {
232*7c478bd9Sstevel@tonic-gate 		regval = regbuf[0];
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 		busnum = PCI_REG_BUS_G(regval);
235*7c478bd9Sstevel@tonic-gate 		devicenum = PCI_REG_DEV_G(regval);
236*7c478bd9Sstevel@tonic-gate 		funcnum = PCI_REG_FUNC_G(regval);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 		if ((busnum == pbp->busnum) &&
239*7c478bd9Sstevel@tonic-gate 		    (devicenum == pbp->devnum) &&
240*7c478bd9Sstevel@tonic-gate 		    (funcnum == pbp->funcnum)) {
241*7c478bd9Sstevel@tonic-gate 			/* found it */
242*7c478bd9Sstevel@tonic-gate 			pbp->di_node = node;
243*7c478bd9Sstevel@tonic-gate 			return (DI_WALK_TERMINATE);
244*7c478bd9Sstevel@tonic-gate 		}
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
248*7c478bd9Sstevel@tonic-gate }
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate static di_node_t
251*7c478bd9Sstevel@tonic-gate search_tree_forpcibdf(int bus, int dev, int fn)
252*7c478bd9Sstevel@tonic-gate {
253*7c478bd9Sstevel@tonic-gate 	pcibdf_t pb;
254*7c478bd9Sstevel@tonic-gate 	pb.busnum = bus;
255*7c478bd9Sstevel@tonic-gate 	pb.devnum = dev;
256*7c478bd9Sstevel@tonic-gate 	pb.funcnum = fn;
257*7c478bd9Sstevel@tonic-gate 	pb.di_node = DI_NODE_NIL;
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	(void) di_walk_node(root_node, DI_WALK_CLDFIRST, &pb, matchpcibdf);
260*7c478bd9Sstevel@tonic-gate 	return (pb.di_node);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate static int
265*7c478bd9Sstevel@tonic-gate matchusbserial(di_node_t node, void *arg)
266*7c478bd9Sstevel@tonic-gate {
267*7c478bd9Sstevel@tonic-gate 	int len;
268*7c478bd9Sstevel@tonic-gate 	char *serialp;
269*7c478bd9Sstevel@tonic-gate 	usbser_t *usbsp;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	usbsp = (usbser_t *)arg;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno",
274*7c478bd9Sstevel@tonic-gate 		(uchar_t **)&serialp);
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	if ((len > 0) && (strcmp((char *)&usbsp->serialno, serialp) == 0)) {
277*7c478bd9Sstevel@tonic-gate 		usbsp->node = node;
278*7c478bd9Sstevel@tonic-gate 		return (DI_WALK_TERMINATE);
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
281*7c478bd9Sstevel@tonic-gate }
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate static di_node_t
284*7c478bd9Sstevel@tonic-gate match_usb(di_node_t node, uint64_t serialno)
285*7c478bd9Sstevel@tonic-gate {
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	usbser_t usbs;
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	usbs.serialno = serialno;
290*7c478bd9Sstevel@tonic-gate 	usbs.node = DI_NODE_NIL;
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	(void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, matchusbserial);
293*7c478bd9Sstevel@tonic-gate 	return (usbs.node);
294*7c478bd9Sstevel@tonic-gate }
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate static int
298*7c478bd9Sstevel@tonic-gate find_path_index_in_disk_list(char *path)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate 	int i;
301*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < disk_list_valid; i++)
302*7c478bd9Sstevel@tonic-gate 		if (strcmp(disk_list[i], path) == 0) {
303*7c478bd9Sstevel@tonic-gate 			return (i);
304*7c478bd9Sstevel@tonic-gate 		}
305*7c478bd9Sstevel@tonic-gate 	return (-1);
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate /*
310*7c478bd9Sstevel@tonic-gate  * Construct a physical device pathname from EDD and verify the
311*7c478bd9Sstevel@tonic-gate  * path exists. Return the index of in disk_list for the mapped
312*7c478bd9Sstevel@tonic-gate  * path on success, -1 on failure.
313*7c478bd9Sstevel@tonic-gate  */
314*7c478bd9Sstevel@tonic-gate static int
315*7c478bd9Sstevel@tonic-gate match_edd(biosdev_data_t *bdata)
316*7c478bd9Sstevel@tonic-gate {
317*7c478bd9Sstevel@tonic-gate 	di_node_t node;
318*7c478bd9Sstevel@tonic-gate 	char *devfspath;
319*7c478bd9Sstevel@tonic-gate 	fn48_t *bd;
320*7c478bd9Sstevel@tonic-gate 	int index;
321*7c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	if (!bdata->edd_valid) {
324*7c478bd9Sstevel@tonic-gate 		if (debug)
325*7c478bd9Sstevel@tonic-gate 			(void) printf("edd not valid\n");
326*7c478bd9Sstevel@tonic-gate 		return (-1);
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	bd = &bdata->fn48_dev_params;
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) {
332*7c478bd9Sstevel@tonic-gate 		/* EDD extensions for devicepath not present */
333*7c478bd9Sstevel@tonic-gate 		if (debug)
334*7c478bd9Sstevel@tonic-gate 			(void) printf("magic not valid %x pathinfolen %d\n",
335*7c478bd9Sstevel@tonic-gate 			    bd->magic, bd->pathinfo_len);
336*7c478bd9Sstevel@tonic-gate 		return (-1);
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	/* we handle only PCI scsi, ata or sata for now */
340*7c478bd9Sstevel@tonic-gate 	if (strncmp(bd->bustype, "PCI", 3) != 0) {
341*7c478bd9Sstevel@tonic-gate 		if (debug)
342*7c478bd9Sstevel@tonic-gate 			(void) printf("was not pci %s\n", bd->bustype);
343*7c478bd9Sstevel@tonic-gate 		return (-1);
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate 	if (debug)
346*7c478bd9Sstevel@tonic-gate 		(void) printf("match_edd bdf %d %d %d\n",
347*7c478bd9Sstevel@tonic-gate 			bd->interfacepath.pci.bus,
348*7c478bd9Sstevel@tonic-gate 			bd->interfacepath.pci.device,
349*7c478bd9Sstevel@tonic-gate 			bd->interfacepath.pci.function);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	/* look into devinfo tree and find a node with matching pci b/d/f */
352*7c478bd9Sstevel@tonic-gate 	node = search_tree_forpcibdf(bd->interfacepath.pci.bus,
353*7c478bd9Sstevel@tonic-gate 		bd->interfacepath.pci.device,
354*7c478bd9Sstevel@tonic-gate 		bd->interfacepath.pci.function);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
357*7c478bd9Sstevel@tonic-gate 		if (debug)
358*7c478bd9Sstevel@tonic-gate 			(void) printf(" could not find a node in tree "
359*7c478bd9Sstevel@tonic-gate 			    "matching bdf\n");
360*7c478bd9Sstevel@tonic-gate 		return (-1);
361*7c478bd9Sstevel@tonic-gate 	}
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	/* construct a path */
364*7c478bd9Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	if (debug)
367*7c478bd9Sstevel@tonic-gate 		(void) printf("interface type %s\n", bd->interface_type);
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	if (strncmp(bd->interface_type, "SCSI", 4) == 0) {
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		/* at this time sd doesnot support luns greater than uchar_t */
372*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s/sd@%d,%d", devfspath,
373*7c478bd9Sstevel@tonic-gate 		    bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo);
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(bd->interface_type, "ATAPI", 5) == 0) {
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s/ide@%d/sd@%d,0",
378*7c478bd9Sstevel@tonic-gate 		    devfspath, bd->interfacepath.pci.channel,
379*7c478bd9Sstevel@tonic-gate 		    bd->devicepath.ata.chan);
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(bd->interface_type, "ATA", 3) == 0) {
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s/ide@%d/cmdk@%d,0",
384*7c478bd9Sstevel@tonic-gate 		    devfspath, bd->interfacepath.pci.channel,
385*7c478bd9Sstevel@tonic-gate 		    bd->devicepath.ata.chan);
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(bd->interface_type, "SATA", 4) == 0) {
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s/ide@%d/cmdk@%d,0",
390*7c478bd9Sstevel@tonic-gate 		    devfspath, bd->interfacepath.pci.channel,
391*7c478bd9Sstevel@tonic-gate 		    bd->devicepath.ata.chan);
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(bd->interface_type, "USB", 3) == 0) {
394*7c478bd9Sstevel@tonic-gate 		(void) printf("USB\n");
395*7c478bd9Sstevel@tonic-gate 		node = match_usb(node, bd->devicepath.usb.usb_serial_id);
396*7c478bd9Sstevel@tonic-gate 		if (node != DI_NODE_NIL) {
397*7c478bd9Sstevel@tonic-gate 			if (debug)
398*7c478bd9Sstevel@tonic-gate 				(void) printf("usb path %s\n",
399*7c478bd9Sstevel@tonic-gate 				    di_devfs_path(node));
400*7c478bd9Sstevel@tonic-gate 			(void) snprintf(path, MAXPATHLEN, "%s", devfspath);
401*7c478bd9Sstevel@tonic-gate 		} else
402*7c478bd9Sstevel@tonic-gate 			return (-1);
403*7c478bd9Sstevel@tonic-gate 	} else {
404*7c478bd9Sstevel@tonic-gate 		if (debug)
405*7c478bd9Sstevel@tonic-gate 			(void) printf("sorry not supported interface %s\n",
406*7c478bd9Sstevel@tonic-gate 		    bd->interface_type);
407*7c478bd9Sstevel@tonic-gate 		return (-1);
408*7c478bd9Sstevel@tonic-gate 	}
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	index = find_path_index_in_disk_list(path);
411*7c478bd9Sstevel@tonic-gate 	if (index >= 0) {
412*7c478bd9Sstevel@tonic-gate 		return (index);
413*7c478bd9Sstevel@tonic-gate 	}
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	return (-1);
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate /*
419*7c478bd9Sstevel@tonic-gate  * For each disk in list of disks, compare the first block with the
420*7c478bd9Sstevel@tonic-gate  * one from bdd. On the first match, return the index of path in
421*7c478bd9Sstevel@tonic-gate  * disk_list. If none matched return -1.
422*7c478bd9Sstevel@tonic-gate  */
423*7c478bd9Sstevel@tonic-gate static int
424*7c478bd9Sstevel@tonic-gate match_first_block(biosdev_data_t *bd)
425*7c478bd9Sstevel@tonic-gate {
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	char diskpath[MAXPATHLEN];
428*7c478bd9Sstevel@tonic-gate 	int fd;
429*7c478bd9Sstevel@tonic-gate 	char buf[512];
430*7c478bd9Sstevel@tonic-gate 	ssize_t	num_read;
431*7c478bd9Sstevel@tonic-gate 	int i;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if (!bd->first_block_valid)
434*7c478bd9Sstevel@tonic-gate 		return (-1);
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < disk_list_valid; i++) {
437*7c478bd9Sstevel@tonic-gate 		(void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw",
438*7c478bd9Sstevel@tonic-gate 		    DEVFS_PREFIX, disk_list[i]);
439*7c478bd9Sstevel@tonic-gate 		fd = open(diskpath, O_RDONLY);
440*7c478bd9Sstevel@tonic-gate 		if (fd  < 0) {
441*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "opening %s failed errno %d\n",
442*7c478bd9Sstevel@tonic-gate 			    diskpath, errno);
443*7c478bd9Sstevel@tonic-gate 			continue;
444*7c478bd9Sstevel@tonic-gate 		}
445*7c478bd9Sstevel@tonic-gate 		num_read = read(fd, buf, 512);
446*7c478bd9Sstevel@tonic-gate 		if (num_read != 512) {
447*7c478bd9Sstevel@tonic-gate 			(void) printf("read only %d bytes from %s\n", num_read,
448*7c478bd9Sstevel@tonic-gate 			    diskpath);
449*7c478bd9Sstevel@tonic-gate 			continue;
450*7c478bd9Sstevel@tonic-gate 		}
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		if (memcmp(buf, bd->first_block, 512) == 0)	 {
453*7c478bd9Sstevel@tonic-gate 			/* found it */
454*7c478bd9Sstevel@tonic-gate 			return (i);
455*7c478bd9Sstevel@tonic-gate 		}
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 	return (-1);
458*7c478bd9Sstevel@tonic-gate }
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate static void
462*7c478bd9Sstevel@tonic-gate cleanup_and_exit(int exitcode)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	free_disks();
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	if (root_node != DI_NODE_NIL)
468*7c478bd9Sstevel@tonic-gate 		di_fini(root_node);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	if (root_allnode != DI_NODE_NIL)
471*7c478bd9Sstevel@tonic-gate 		di_fini(root_allnode);
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	if (prom_hdl != DI_PROM_HANDLE_NIL)
474*7c478bd9Sstevel@tonic-gate 		di_prom_fini(prom_hdl);
475*7c478bd9Sstevel@tonic-gate 	exit(exitcode);
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate }
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate int
481*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	biosdev_data_t		*biosdata;
484*7c478bd9Sstevel@tonic-gate 	int len, i, c, j;
485*7c478bd9Sstevel@tonic-gate 	int matchedindex = -1;
486*7c478bd9Sstevel@tonic-gate 	char biospropname[BIOSPROPNAME_TMPL_LEN];
487*7c478bd9Sstevel@tonic-gate 	int totalmatches = 0;
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "d")) != -1)  {
491*7c478bd9Sstevel@tonic-gate 		switch (c) {
492*7c478bd9Sstevel@tonic-gate 		case 'd':
493*7c478bd9Sstevel@tonic-gate 			debug = 1;
494*7c478bd9Sstevel@tonic-gate 			break;
495*7c478bd9Sstevel@tonic-gate 		default:
496*7c478bd9Sstevel@tonic-gate 			(void) printf("unknown option %c\n", c);
497*7c478bd9Sstevel@tonic-gate 			exit(1);
498*7c478bd9Sstevel@tonic-gate 		}
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
502*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_prom_init failed\n");
503*7c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
507*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init failed\n");
508*7c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
509*7c478bd9Sstevel@tonic-gate 	}
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
512*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "di_init failed\n");
513*7c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	(void) memset(mapinfo, 0, sizeof (mapinfo));
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	/* get a list of all disks in the system */
519*7c478bd9Sstevel@tonic-gate 	build_disk_list();
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	/* for each property try to match with a disk */
522*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BIOSDEV_NUM; i++) {
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 		(void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN,
525*7c478bd9Sstevel@tonic-gate 		    BIOSPROPNAME_TMPL, i + STARTING_DRVNUM);
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 		len = di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode,
528*7c478bd9Sstevel@tonic-gate 		    biospropname, (uchar_t **)&biosdata);
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 		if (len <= 0) {
531*7c478bd9Sstevel@tonic-gate 			continue;
532*7c478bd9Sstevel@tonic-gate 		}
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 		if (debug)
535*7c478bd9Sstevel@tonic-gate 			(void) printf("matching %s\n", biospropname);
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 		matchedindex = match_edd(biosdata);
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 		if (matchedindex == -1) {
540*7c478bd9Sstevel@tonic-gate 			matchedindex = match_first_block(biosdata);
541*7c478bd9Sstevel@tonic-gate 			if (debug && matchedindex != -1)
542*7c478bd9Sstevel@tonic-gate 				(void) printf("matched first block\n");
543*7c478bd9Sstevel@tonic-gate 		} else if (debug)
544*7c478bd9Sstevel@tonic-gate 			(void) printf("matched thru edd\n");
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		if (matchedindex != -1) {
547*7c478bd9Sstevel@tonic-gate 			mapinfo[i].disklist_index = matchedindex;
548*7c478bd9Sstevel@tonic-gate 			mapinfo[i].matchcount++;
549*7c478bd9Sstevel@tonic-gate 			if (debug)
550*7c478bd9Sstevel@tonic-gate 				(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
551*7c478bd9Sstevel@tonic-gate 				    disk_list[matchedindex]);
552*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < i; j++) {
553*7c478bd9Sstevel@tonic-gate 				if (mapinfo[j].matchcount > 0 &&
554*7c478bd9Sstevel@tonic-gate 				    mapinfo[j].disklist_index == matchedindex) {
555*7c478bd9Sstevel@tonic-gate 					mapinfo[j].matchcount++;
556*7c478bd9Sstevel@tonic-gate 					mapinfo[i].matchcount++;
557*7c478bd9Sstevel@tonic-gate 				}
558*7c478bd9Sstevel@tonic-gate 			}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		} else if (debug)
561*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "Could not match %s\n",
562*7c478bd9Sstevel@tonic-gate 			    biospropname);
563*7c478bd9Sstevel@tonic-gate 	}
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < BIOSDEV_NUM; i++) {
566*7c478bd9Sstevel@tonic-gate 		if (mapinfo[i].matchcount == 1) {
567*7c478bd9Sstevel@tonic-gate 			(void) printf("0x%x %s\n", i + STARTING_DRVNUM,
568*7c478bd9Sstevel@tonic-gate 			    disk_list[mapinfo[i].disklist_index]);
569*7c478bd9Sstevel@tonic-gate 			totalmatches++;
570*7c478bd9Sstevel@tonic-gate 		} else if (debug && mapinfo[i].matchcount > 1) {
571*7c478bd9Sstevel@tonic-gate 			(void) printf("0x%x %s matchcount %d\n",
572*7c478bd9Sstevel@tonic-gate 			    i + STARTING_DRVNUM,
573*7c478bd9Sstevel@tonic-gate 			    disk_list[mapinfo[i].disklist_index],
574*7c478bd9Sstevel@tonic-gate 				mapinfo[i].matchcount);
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (totalmatches == 0) {
579*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "biosdev: Could not match any!!\n");
580*7c478bd9Sstevel@tonic-gate 		cleanup_and_exit(1);
581*7c478bd9Sstevel@tonic-gate 	}
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	cleanup_and_exit(0);
584*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
585*7c478bd9Sstevel@tonic-gate 	return (0);
586*7c478bd9Sstevel@tonic-gate }
587