1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte /*
22*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*fcf3ce44SJohn Forte  * Use is subject to license terms.
24*fcf3ce44SJohn Forte  */
25*fcf3ce44SJohn Forte 
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte /*LINTLIBRARY*/
28*fcf3ce44SJohn Forte 
29*fcf3ce44SJohn Forte /*
30*fcf3ce44SJohn Forte  * I18N message number ranges
31*fcf3ce44SJohn Forte  *  This file: 12000 - 12499
32*fcf3ce44SJohn Forte  *  Shared common messages: 1 - 1999
33*fcf3ce44SJohn Forte  */
34*fcf3ce44SJohn Forte 
35*fcf3ce44SJohn Forte /*
36*fcf3ce44SJohn Forte  *	This module is part of the Fibre Channel Interface library.
37*fcf3ce44SJohn Forte  */
38*fcf3ce44SJohn Forte 
39*fcf3ce44SJohn Forte /* #define		_POSIX_SOURCE 1 */
40*fcf3ce44SJohn Forte 
41*fcf3ce44SJohn Forte 
42*fcf3ce44SJohn Forte /*	Includes	*/
43*fcf3ce44SJohn Forte #include	<stdlib.h>
44*fcf3ce44SJohn Forte #include	<stdio.h>
45*fcf3ce44SJohn Forte #include	<sys/file.h>
46*fcf3ce44SJohn Forte #include	<sys/types.h>
47*fcf3ce44SJohn Forte #include	<sys/stat.h>
48*fcf3ce44SJohn Forte #include	<sys/mkdev.h>
49*fcf3ce44SJohn Forte #include	<sys/param.h>
50*fcf3ce44SJohn Forte #include	<fcntl.h>
51*fcf3ce44SJohn Forte #include	<unistd.h>
52*fcf3ce44SJohn Forte #include	<string.h>
53*fcf3ce44SJohn Forte #include	<sys/scsi/scsi.h>
54*fcf3ce44SJohn Forte #include	<dirent.h>		/* for DIR */
55*fcf3ce44SJohn Forte #include	<sys/vtoc.h>
56*fcf3ce44SJohn Forte #include	<nl_types.h>
57*fcf3ce44SJohn Forte #include	<strings.h>
58*fcf3ce44SJohn Forte #include	<errno.h>
59*fcf3ce44SJohn Forte #include	<sys/ddi.h>		/* for max */
60*fcf3ce44SJohn Forte #include	<fnmatch.h>
61*fcf3ce44SJohn Forte #include	<l_common.h>
62*fcf3ce44SJohn Forte #include	<stgcom.h>
63*fcf3ce44SJohn Forte #include	<l_error.h>
64*fcf3ce44SJohn Forte #include	<g_state.h>
65*fcf3ce44SJohn Forte #include	<g_scsi.h>
66*fcf3ce44SJohn Forte #include	<sys/fibre-channel/ulp/fcp_util.h>
67*fcf3ce44SJohn Forte #include	<sys/fibre-channel/impl/fc_error.h>
68*fcf3ce44SJohn Forte #include	<sys/fibre-channel/impl/fcph.h>
69*fcf3ce44SJohn Forte #include	<sys/socalio.h>
70*fcf3ce44SJohn Forte #include	<libdevinfo.h>
71*fcf3ce44SJohn Forte #include	<ctype.h>
72*fcf3ce44SJohn Forte #include	<devid.h>
73*fcf3ce44SJohn Forte 
74*fcf3ce44SJohn Forte /* Some forward declarations of static functions */
75*fcf3ce44SJohn Forte /*
76*fcf3ce44SJohn Forte  * becomes extern interface for Tapestry.
77*fcf3ce44SJohn Forte  * static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *);
78*fcf3ce44SJohn Forte  * static int g_get_dev_list(char *, fc_port_dev_t **, int *, int);
79*fcf3ce44SJohn Forte  */
80*fcf3ce44SJohn Forte static int	g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
81*fcf3ce44SJohn Forte static int	g_set_port_state(char *, int);
82*fcf3ce44SJohn Forte static int	g_dev_log_in_out(char *, la_wwn_t, uint16_t);
83*fcf3ce44SJohn Forte static int	g_get_dev_port_state(char *, la_wwn_t, uint32_t *);
84*fcf3ce44SJohn Forte static void	g_free_rls(AL_rls *);
85*fcf3ce44SJohn Forte static int	g_scsi_inquiry_cmd80(int, uchar_t *, int);
86*fcf3ce44SJohn Forte static int	get_fca_inq_dtype(char *, la_wwn_t, uchar_t *);
87*fcf3ce44SJohn Forte static int	g_find_supported_inq_page(int, int);
88*fcf3ce44SJohn Forte static int	wwn_list_name_compare(const void *, const void *);
89*fcf3ce44SJohn Forte static int	devid_get_all(ddi_devid_t, di_node_t, char *,
90*fcf3ce44SJohn Forte 			struct mplist_struct **);
91*fcf3ce44SJohn Forte static int	get_multipath(char *, struct dlist **,
92*fcf3ce44SJohn Forte 			struct wwn_list_struct *);
93*fcf3ce44SJohn Forte static int	get_multipath_disk(char *, struct dlist **,
94*fcf3ce44SJohn Forte 			struct wwn_list_struct *);
95*fcf3ce44SJohn Forte static void	mplist_free(struct mplist_struct *);
96*fcf3ce44SJohn Forte static int	get_wwn_data(di_node_t, uchar_t **, uchar_t **);
97*fcf3ce44SJohn Forte static int	get_dev_path(struct wwn_list_struct **, char *, char *);
98*fcf3ce44SJohn Forte static int	insert_missing_pwwn(char *, struct wwn_list_struct **);
99*fcf3ce44SJohn Forte static int	get_scsi_vhci_port_wwn(char *, uchar_t *);
100*fcf3ce44SJohn Forte static int	search_wwn_entry(struct wwn_list_found_struct *, uchar_t *,
101*fcf3ce44SJohn Forte 		uchar_t *);
102*fcf3ce44SJohn Forte static int	add_wwn_entry(struct wwn_list_found_struct **, uchar_t *,
103*fcf3ce44SJohn Forte 		uchar_t *);
104*fcf3ce44SJohn Forte static int	string_to_wwn(uchar_t *, uchar_t *);
105*fcf3ce44SJohn Forte static int	get_wwns(char *, uchar_t *, uchar_t *, int *,
106*fcf3ce44SJohn Forte 		struct wwn_list_found_struct **);
107*fcf3ce44SJohn Forte 
108*fcf3ce44SJohn Forte /* type for g_dev_map_init related routines */
109*fcf3ce44SJohn Forte 
110*fcf3ce44SJohn Forte #define	S_FREE(x)	(((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
111*fcf3ce44SJohn Forte 
112*fcf3ce44SJohn Forte typedef struct impl_map_dev_prop {
113*fcf3ce44SJohn Forte 	char	prop_name[MAXNAMELEN];
114*fcf3ce44SJohn Forte 	int	prop_type;
115*fcf3ce44SJohn Forte 	int	prop_size;
116*fcf3ce44SJohn Forte 	void 	*prop_data;
117*fcf3ce44SJohn Forte 	int 	prop_error;
118*fcf3ce44SJohn Forte 	struct impl_map_dev_prop	*next;
119*fcf3ce44SJohn Forte } impl_map_dev_prop_t;
120*fcf3ce44SJohn Forte 
121*fcf3ce44SJohn Forte typedef struct impl_map_dev {
122*fcf3ce44SJohn Forte 	int			flag;
123*fcf3ce44SJohn Forte 	uint_t			topo;
124*fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*prop_list;
125*fcf3ce44SJohn Forte 	struct impl_map_dev	*parent;
126*fcf3ce44SJohn Forte 	struct impl_map_dev	*child;
127*fcf3ce44SJohn Forte 	struct impl_map_dev 	*next;
128*fcf3ce44SJohn Forte } impl_map_dev_t;
129*fcf3ce44SJohn Forte 
130*fcf3ce44SJohn Forte /*	Defines 	*/
131*fcf3ce44SJohn Forte #define	VERBPRINT	if (verbose) (void) printf
132*fcf3ce44SJohn Forte 
133*fcf3ce44SJohn Forte #define	DIR_MATCH_ST		"*[0-9+]n"
134*fcf3ce44SJohn Forte #define	DIR_MATCH_SSD		"*s2"
135*fcf3ce44SJohn Forte 
136*fcf3ce44SJohn Forte #define	PROP_NOEXIST		0
137*fcf3ce44SJohn Forte #define	PROP_EXIST		1
138*fcf3ce44SJohn Forte 
139*fcf3ce44SJohn Forte /*	Prototypes	*/
140*fcf3ce44SJohn Forte static int create_map(char *, gfc_map_t *, int, int);
141*fcf3ce44SJohn Forte static char ctoi(char);
142*fcf3ce44SJohn Forte static int	lilp_map_cmp(const void*, const void*);
143*fcf3ce44SJohn Forte static int	devices_get_all(di_node_t, char *, char *,
144*fcf3ce44SJohn Forte 			struct wwn_list_struct **);
145*fcf3ce44SJohn Forte static char	*my_devfs_path(di_node_t);
146*fcf3ce44SJohn Forte static void	my_devfs_path_free(char *path);
147*fcf3ce44SJohn Forte static void	copy_wwn_data_to_str(char *, const uchar_t *);
148*fcf3ce44SJohn Forte static void	init_drv(char *, char *, char *);
149*fcf3ce44SJohn Forte 
150*fcf3ce44SJohn Forte /* static for g_dev_map_init related routines */
151*fcf3ce44SJohn Forte 
152*fcf3ce44SJohn Forte static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t,
153*fcf3ce44SJohn Forte 	uchar_t *, uchar_t *, int, int);
154*fcf3ce44SJohn Forte static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int);
155*fcf3ce44SJohn Forte static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **);
156*fcf3ce44SJohn Forte static void free_prop_list(impl_map_dev_prop_t **);
157*fcf3ce44SJohn Forte static void free_child_list(impl_map_dev_t **);
158*fcf3ce44SJohn Forte static u_longlong_t wwnConversion(uchar_t *wwn);
159*fcf3ce44SJohn Forte 
160*fcf3ce44SJohn Forte uchar_t g_switch_to_alpa[] = {
161*fcf3ce44SJohn Forte 	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
162*fcf3ce44SJohn Forte 	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
163*fcf3ce44SJohn Forte 	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
164*fcf3ce44SJohn Forte 	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
165*fcf3ce44SJohn Forte 	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
166*fcf3ce44SJohn Forte 	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
167*fcf3ce44SJohn Forte 	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
168*fcf3ce44SJohn Forte 	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
169*fcf3ce44SJohn Forte 	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
170*fcf3ce44SJohn Forte 	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
171*fcf3ce44SJohn Forte 	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
172*fcf3ce44SJohn Forte 	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
173*fcf3ce44SJohn Forte 	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
174*fcf3ce44SJohn Forte };
175*fcf3ce44SJohn Forte 
176*fcf3ce44SJohn Forte uchar_t g_sf_alpa_to_switch[] = {
177*fcf3ce44SJohn Forte 	0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
178*fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
179*fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
180*fcf3ce44SJohn Forte 	0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
181*fcf3ce44SJohn Forte 	0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
182*fcf3ce44SJohn Forte 	0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
183*fcf3ce44SJohn Forte 	0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
184*fcf3ce44SJohn Forte 	0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
185*fcf3ce44SJohn Forte 	0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
186*fcf3ce44SJohn Forte 	0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
187*fcf3ce44SJohn Forte 	0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
188*fcf3ce44SJohn Forte 	0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
189*fcf3ce44SJohn Forte 	0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
190*fcf3ce44SJohn Forte 	0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
191*fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
192*fcf3ce44SJohn Forte 	0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
193*fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
194*fcf3ce44SJohn Forte 	0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
195*fcf3ce44SJohn Forte 	0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
196*fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
197*fcf3ce44SJohn Forte 	0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
198*fcf3ce44SJohn Forte 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
199*fcf3ce44SJohn Forte 	0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
200*fcf3ce44SJohn Forte 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
201*fcf3ce44SJohn Forte };
202*fcf3ce44SJohn Forte 
203*fcf3ce44SJohn Forte 
204*fcf3ce44SJohn Forte 
205*fcf3ce44SJohn Forte /*
206*fcf3ce44SJohn Forte  * Check if device is in the map.
207*fcf3ce44SJohn Forte  *
208*fcf3ce44SJohn Forte  * PARAMS:
209*fcf3ce44SJohn Forte  *	map - loop map returned from fc port
210*fcf3ce44SJohn Forte  *	tid - device ID for private map or 24-bit alpa for fabric map
211*fcf3ce44SJohn Forte  *
212*fcf3ce44SJohn Forte  * RETURNS:
213*fcf3ce44SJohn Forte  *	 1 if device present in the map.
214*fcf3ce44SJohn Forte  *	 0 otherwise.
215*fcf3ce44SJohn Forte  *
216*fcf3ce44SJohn Forte  */
217*fcf3ce44SJohn Forte int
218*fcf3ce44SJohn Forte g_device_in_map(gfc_map_t *map, int tid)
219*fcf3ce44SJohn Forte {
220*fcf3ce44SJohn Forte 	int i, j;
221*fcf3ce44SJohn Forte 	gfc_port_dev_info_t	*dev_ptr;
222*fcf3ce44SJohn Forte 
223*fcf3ce44SJohn Forte 	dev_ptr = map->dev_addr;
224*fcf3ce44SJohn Forte 	if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) ||
225*fcf3ce44SJohn Forte 		(map->hba_addr.port_topology == FC_TOP_FABRIC)) {
226*fcf3ce44SJohn Forte 		for (i = 0; i < map->count; i++, dev_ptr++) {
227*fcf3ce44SJohn Forte 			if (dev_ptr->
228*fcf3ce44SJohn Forte 				gfc_port_dev.pub_port.dev_did.port_id == tid) {
229*fcf3ce44SJohn Forte 				/* Does not count if WWN == 0 */
230*fcf3ce44SJohn Forte 				for (j = 0; j < FC_WWN_SIZE; j++)
231*fcf3ce44SJohn Forte 					if (dev_ptr->gfc_port_dev.pub_port.
232*fcf3ce44SJohn Forte 						dev_pwwn.raw_wwn[j] != 0)
233*fcf3ce44SJohn Forte 						return (1);
234*fcf3ce44SJohn Forte 			}
235*fcf3ce44SJohn Forte 		}
236*fcf3ce44SJohn Forte 	} else {
237*fcf3ce44SJohn Forte 		for (i = 0; i < map->count; i++, dev_ptr++) {
238*fcf3ce44SJohn Forte 			if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa ==
239*fcf3ce44SJohn Forte 				(int)g_switch_to_alpa[tid]) {
240*fcf3ce44SJohn Forte 				/* Does not count if WWN == 0 */
241*fcf3ce44SJohn Forte 				for (j = 0; j < WWN_SIZE; j++)
242*fcf3ce44SJohn Forte 					if (dev_ptr->gfc_port_dev.priv_port.
243*fcf3ce44SJohn Forte 						sf_port_wwn[j] != 0)
244*fcf3ce44SJohn Forte 						return (1);
245*fcf3ce44SJohn Forte 			}
246*fcf3ce44SJohn Forte 		}
247*fcf3ce44SJohn Forte 	}
248*fcf3ce44SJohn Forte 	return (0);
249*fcf3ce44SJohn Forte }
250*fcf3ce44SJohn Forte 
251*fcf3ce44SJohn Forte /*
252*fcf3ce44SJohn Forte  * Inserts any missing port wwns for mpxio device paths
253*fcf3ce44SJohn Forte  * which are in ONLINE or STANDBY state.
254*fcf3ce44SJohn Forte  */
255*fcf3ce44SJohn Forte static int
256*fcf3ce44SJohn Forte insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr)
257*fcf3ce44SJohn Forte {
258*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
259*fcf3ce44SJohn Forte int	i, pathcnt, match;
260*fcf3ce44SJohn Forte struct	wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found;
261*fcf3ce44SJohn Forte char	pwwn1[WWN_S_LEN];
262*fcf3ce44SJohn Forte 
263*fcf3ce44SJohn Forte 	/*
264*fcf3ce44SJohn Forte 	 * Now check each scsi_vhci device path to find any missed
265*fcf3ce44SJohn Forte 	 * port wwns and insert a new wwn list entry for the missed
266*fcf3ce44SJohn Forte 	 * port wwn
267*fcf3ce44SJohn Forte 	 */
268*fcf3ce44SJohn Forte 	if (g_get_pathlist(phys_path, &pathlist)) {
269*fcf3ce44SJohn Forte 		/* Free memory for pathlist before return */
270*fcf3ce44SJohn Forte 		S_FREE(pathlist.path_info);
271*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
272*fcf3ce44SJohn Forte 	}
273*fcf3ce44SJohn Forte 
274*fcf3ce44SJohn Forte 	pathcnt = pathlist.path_count;
275*fcf3ce44SJohn Forte 	for (i = 0; i < pathcnt; i++) {
276*fcf3ce44SJohn Forte 		/*
277*fcf3ce44SJohn Forte 		 * Just search for ONLINE and STANDBY paths as
278*fcf3ce44SJohn Forte 		 * those should be the only missing wwn entries.
279*fcf3ce44SJohn Forte 		 * There is a very small window for an offline
280*fcf3ce44SJohn Forte 		 * to have occurred between the time we retrieved
281*fcf3ce44SJohn Forte 		 * the device list and a call to this function.
282*fcf3ce44SJohn Forte 		 * If that happens, we just won't add it to
283*fcf3ce44SJohn Forte 		 * the list which is probably a good thing.
284*fcf3ce44SJohn Forte 		 */
285*fcf3ce44SJohn Forte 		if (pathlist.path_info[i].path_state ==
286*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE ||
287*fcf3ce44SJohn Forte 		    pathlist.path_info[i].path_state ==
288*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_STANDBY) {
289*fcf3ce44SJohn Forte 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
290*fcf3ce44SJohn Forte 				WWN_S_LEN - 1);
291*fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
292*fcf3ce44SJohn Forte 			/*
293*fcf3ce44SJohn Forte 			 * Now search through wwn list for matching
294*fcf3ce44SJohn Forte 			 * device path AND pwwn
295*fcf3ce44SJohn Forte 			 * If it's found, continue to next path.
296*fcf3ce44SJohn Forte 			 * If it's not found, add it the wwn list.
297*fcf3ce44SJohn Forte 			 */
298*fcf3ce44SJohn Forte 			match = 0;
299*fcf3ce44SJohn Forte 
300*fcf3ce44SJohn Forte 			for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL;
301*fcf3ce44SJohn Forte 			    wwn_list_s = wwn_list_s->wwn_next) {
302*fcf3ce44SJohn Forte 				if (strncmp(phys_path,
303*fcf3ce44SJohn Forte 					    wwn_list_s->physical_path,
304*fcf3ce44SJohn Forte 					    strlen(phys_path)) == 0) {
305*fcf3ce44SJohn Forte 					wwn_list_found = wwn_list_s;
306*fcf3ce44SJohn Forte 					if (strncmp(pwwn1,
307*fcf3ce44SJohn Forte 						    wwn_list_s->port_wwn_s,
308*fcf3ce44SJohn Forte 						    WWN_S_LEN) == 0) {
309*fcf3ce44SJohn Forte 						match++;
310*fcf3ce44SJohn Forte 						break;
311*fcf3ce44SJohn Forte 					}
312*fcf3ce44SJohn Forte 				}
313*fcf3ce44SJohn Forte 			}
314*fcf3ce44SJohn Forte 			if (match) {
315*fcf3ce44SJohn Forte 				continue;
316*fcf3ce44SJohn Forte 			} else {
317*fcf3ce44SJohn Forte 				/*
318*fcf3ce44SJohn Forte 				 * didn't find a match but the mpxio
319*fcf3ce44SJohn Forte 				 * device is in the list. Retrieve
320*fcf3ce44SJohn Forte 				 * the info from the wwn_list_found
321*fcf3ce44SJohn Forte 				 * and add it to the list.
322*fcf3ce44SJohn Forte 				 */
323*fcf3ce44SJohn Forte 				if ((new_wwn = (struct  wwn_list_struct *)
324*fcf3ce44SJohn Forte 					calloc(1,
325*fcf3ce44SJohn Forte 					sizeof (struct  wwn_list_struct)))
326*fcf3ce44SJohn Forte 					== NULL) {
327*fcf3ce44SJohn Forte 				    S_FREE(pathlist.path_info);
328*fcf3ce44SJohn Forte 				    return (L_MALLOC_FAILED);
329*fcf3ce44SJohn Forte 				}
330*fcf3ce44SJohn Forte 				if ((new_wwn->physical_path = (char *)
331*fcf3ce44SJohn Forte 					calloc(1,
332*fcf3ce44SJohn Forte 					strlen(wwn_list_found->physical_path)
333*fcf3ce44SJohn Forte 					+1)) == NULL) {
334*fcf3ce44SJohn Forte 				    S_FREE(pathlist.path_info);
335*fcf3ce44SJohn Forte 				    return (L_MALLOC_FAILED);
336*fcf3ce44SJohn Forte 				}
337*fcf3ce44SJohn Forte 				if ((new_wwn->logical_path = (char *)
338*fcf3ce44SJohn Forte 					calloc(1,
339*fcf3ce44SJohn Forte 					strlen(wwn_list_found->logical_path)
340*fcf3ce44SJohn Forte 					+ 1)) == NULL) {
341*fcf3ce44SJohn Forte 				    S_FREE(pathlist.path_info);
342*fcf3ce44SJohn Forte 				    return (L_MALLOC_FAILED);
343*fcf3ce44SJohn Forte 				}
344*fcf3ce44SJohn Forte 
345*fcf3ce44SJohn Forte 				/*
346*fcf3ce44SJohn Forte 				 * Insert new_wwn at the beginning of the list.
347*fcf3ce44SJohn Forte 				 */
348*fcf3ce44SJohn Forte 				new_wwn->wwn_next = *wwn_list_ptr;
349*fcf3ce44SJohn Forte 				(*wwn_list_ptr)->wwn_prev = new_wwn;
350*fcf3ce44SJohn Forte 
351*fcf3ce44SJohn Forte 				/* set new starting ptr */
352*fcf3ce44SJohn Forte 				*wwn_list_ptr = new_wwn;
353*fcf3ce44SJohn Forte 
354*fcf3ce44SJohn Forte 				memcpy(new_wwn->physical_path,
355*fcf3ce44SJohn Forte 				    wwn_list_found->physical_path,
356*fcf3ce44SJohn Forte 					strlen(wwn_list_found->physical_path));
357*fcf3ce44SJohn Forte 				memcpy(new_wwn->logical_path,
358*fcf3ce44SJohn Forte 				    wwn_list_found->logical_path,
359*fcf3ce44SJohn Forte 					strlen(wwn_list_found->logical_path));
360*fcf3ce44SJohn Forte 				/*
361*fcf3ce44SJohn Forte 				 * Copy found node wwn data to this new entry
362*fcf3ce44SJohn Forte 				 * Node wwn is required for the wwn_list
363*fcf3ce44SJohn Forte 				 * however for mpxio devices it is not
364*fcf3ce44SJohn Forte 				 * relevant as it may apply to multiple
365*fcf3ce44SJohn Forte 				 * target controllers, so just use what
366*fcf3ce44SJohn Forte 				 * we already have in wwn_list_found.
367*fcf3ce44SJohn Forte 				 */
368*fcf3ce44SJohn Forte 				memcpy(new_wwn->node_wwn_s,
369*fcf3ce44SJohn Forte 				    wwn_list_found->node_wwn_s, WWN_S_LEN);
370*fcf3ce44SJohn Forte 				memcpy(new_wwn->w_node_wwn,
371*fcf3ce44SJohn Forte 				    wwn_list_found->w_node_wwn, WWN_SIZE);
372*fcf3ce44SJohn Forte 				new_wwn->device_type =
373*fcf3ce44SJohn Forte 				    wwn_list_found->device_type;
374*fcf3ce44SJohn Forte 				memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN);
375*fcf3ce44SJohn Forte 			}
376*fcf3ce44SJohn Forte 		}
377*fcf3ce44SJohn Forte 	}
378*fcf3ce44SJohn Forte 	S_FREE(pathlist.path_info);
379*fcf3ce44SJohn Forte 	return (0);
380*fcf3ce44SJohn Forte }
381*fcf3ce44SJohn Forte 
382*fcf3ce44SJohn Forte /*
383*fcf3ce44SJohn Forte  * gets the port wwn for a scsi_vhci device using ONLINE path priority
384*fcf3ce44SJohn Forte  */
385*fcf3ce44SJohn Forte static int
386*fcf3ce44SJohn Forte get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn)
387*fcf3ce44SJohn Forte {
388*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
389*fcf3ce44SJohn Forte int	i, pathcnt, found;
390*fcf3ce44SJohn Forte char	pwwn1[WWN_S_LEN];
391*fcf3ce44SJohn Forte 
392*fcf3ce44SJohn Forte 	if (g_get_pathlist(phys_path, &pathlist)) {
393*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
394*fcf3ce44SJohn Forte 	}
395*fcf3ce44SJohn Forte 
396*fcf3ce44SJohn Forte 	found = 0;
397*fcf3ce44SJohn Forte 	pathcnt = pathlist.path_count;
398*fcf3ce44SJohn Forte 	/*
399*fcf3ce44SJohn Forte 	 * Look for an ONLINE path first.
400*fcf3ce44SJohn Forte 	 * If that fails, get the STANDBY path port WWN
401*fcf3ce44SJohn Forte 	 * If that fails, give up
402*fcf3ce44SJohn Forte 	 */
403*fcf3ce44SJohn Forte 	for (i = 0; found == 0 && i < pathcnt; i++) {
404*fcf3ce44SJohn Forte 		if (pathlist.path_info[i].path_state ==
405*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
406*fcf3ce44SJohn Forte 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
407*fcf3ce44SJohn Forte 				WWN_S_LEN - 1);
408*fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
409*fcf3ce44SJohn Forte 			found++;
410*fcf3ce44SJohn Forte 		}
411*fcf3ce44SJohn Forte 	}
412*fcf3ce44SJohn Forte 
413*fcf3ce44SJohn Forte 	for (i = 0; found == 0 && i < pathcnt; i++) {
414*fcf3ce44SJohn Forte 		if (pathlist.path_info[i].path_state ==
415*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_STANDBY) {
416*fcf3ce44SJohn Forte 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
417*fcf3ce44SJohn Forte 				WWN_S_LEN - 1);
418*fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
419*fcf3ce44SJohn Forte 			found++;
420*fcf3ce44SJohn Forte 		}
421*fcf3ce44SJohn Forte 	}
422*fcf3ce44SJohn Forte 
423*fcf3ce44SJohn Forte 	S_FREE(pathlist.path_info);
424*fcf3ce44SJohn Forte 	if (found) {
425*fcf3ce44SJohn Forte 		return (string_to_wwn((uchar_t *)pwwn1, port_wwn));
426*fcf3ce44SJohn Forte 	} else {
427*fcf3ce44SJohn Forte 		return (-1);
428*fcf3ce44SJohn Forte 	}
429*fcf3ce44SJohn Forte }
430*fcf3ce44SJohn Forte 
431*fcf3ce44SJohn Forte /*
432*fcf3ce44SJohn Forte  * searches wwn_list_found for the pwwn passed in
433*fcf3ce44SJohn Forte  * and sets the corresponding nwwn on return.
434*fcf3ce44SJohn Forte  * If no match is found, -1 is returned and nwwn is not set.
435*fcf3ce44SJohn Forte  */
436*fcf3ce44SJohn Forte static int
437*fcf3ce44SJohn Forte search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn,
438*fcf3ce44SJohn Forte 		uchar_t *nwwn)
439*fcf3ce44SJohn Forte {
440*fcf3ce44SJohn Forte struct	wwn_list_found_struct *wwn_list_s;
441*fcf3ce44SJohn Forte 
442*fcf3ce44SJohn Forte 	for (wwn_list_s = wwn_list_found; wwn_list_s != NULL;
443*fcf3ce44SJohn Forte 	    wwn_list_s = wwn_list_s->wwn_next) {
444*fcf3ce44SJohn Forte 		if (memcmp(pwwn,
445*fcf3ce44SJohn Forte 			    wwn_list_s->port_wwn, WWN_SIZE) == 0) {
446*fcf3ce44SJohn Forte 			memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE);
447*fcf3ce44SJohn Forte 			return (0);
448*fcf3ce44SJohn Forte 		}
449*fcf3ce44SJohn Forte 	}
450*fcf3ce44SJohn Forte 	return (-1);
451*fcf3ce44SJohn Forte }
452*fcf3ce44SJohn Forte 
453*fcf3ce44SJohn Forte /*
454*fcf3ce44SJohn Forte  * adds a nwwn, pwwn entry to the next entry in wwn_list_found list
455*fcf3ce44SJohn Forte  */
456*fcf3ce44SJohn Forte static int
457*fcf3ce44SJohn Forte add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn,
458*fcf3ce44SJohn Forte 		uchar_t *nwwn)
459*fcf3ce44SJohn Forte {
460*fcf3ce44SJohn Forte struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL;
461*fcf3ce44SJohn Forte 
462*fcf3ce44SJohn Forte 	/* Got wwns, load data in list */
463*fcf3ce44SJohn Forte 	if ((new_wwn = (struct  wwn_list_found_struct *)
464*fcf3ce44SJohn Forte 		calloc(1, sizeof (struct  wwn_list_found_struct)))
465*fcf3ce44SJohn Forte 			== NULL) {
466*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
467*fcf3ce44SJohn Forte 	}
468*fcf3ce44SJohn Forte 
469*fcf3ce44SJohn Forte 	memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE);
470*fcf3ce44SJohn Forte 	memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE);
471*fcf3ce44SJohn Forte 
472*fcf3ce44SJohn Forte 	/*
473*fcf3ce44SJohn Forte 	 * Insert new_wwn in the list
474*fcf3ce44SJohn Forte 	 */
475*fcf3ce44SJohn Forte 	if (*wwn_list_found != NULL) {
476*fcf3ce44SJohn Forte 		temp_wwn_list_found = (*wwn_list_found)->wwn_next;
477*fcf3ce44SJohn Forte 		(*wwn_list_found)->wwn_next = new_wwn;
478*fcf3ce44SJohn Forte 	} else {
479*fcf3ce44SJohn Forte 		*wwn_list_found = new_wwn;
480*fcf3ce44SJohn Forte 	}
481*fcf3ce44SJohn Forte 	new_wwn->wwn_next = temp_wwn_list_found;
482*fcf3ce44SJohn Forte 
483*fcf3ce44SJohn Forte 	return (0);
484*fcf3ce44SJohn Forte }
485*fcf3ce44SJohn Forte 
486*fcf3ce44SJohn Forte 
487*fcf3ce44SJohn Forte /*
488*fcf3ce44SJohn Forte  * Create a linked list of all the WWN's for all FC_AL disks and
489*fcf3ce44SJohn Forte  * tapes that are attached to this host.
490*fcf3ce44SJohn Forte  *
491*fcf3ce44SJohn Forte  * RETURN VALUES: 0 O.K.
492*fcf3ce44SJohn Forte  *
493*fcf3ce44SJohn Forte  * wwn_list pointer:
494*fcf3ce44SJohn Forte  *			NULL: No devices found.
495*fcf3ce44SJohn Forte  *			!NULL: Devices found
496*fcf3ce44SJohn Forte  *                      wwn_list points to a linked list of wwn's.
497*fcf3ce44SJohn Forte  */
498*fcf3ce44SJohn Forte int
499*fcf3ce44SJohn Forte g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose)
500*fcf3ce44SJohn Forte {
501*fcf3ce44SJohn Forte struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL;
502*fcf3ce44SJohn Forte struct wwn_list_found_struct *wwn_list_found = NULL;
503*fcf3ce44SJohn Forte int err;
504*fcf3ce44SJohn Forte int al_pa;
505*fcf3ce44SJohn Forte uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
506*fcf3ce44SJohn Forte hrtime_t	start_time, end_time;
507*fcf3ce44SJohn Forte char *env = NULL;
508*fcf3ce44SJohn Forte 
509*fcf3ce44SJohn Forte 	/* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */
510*fcf3ce44SJohn Forte 	if (wwn_list_ptr == NULL) {
511*fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
512*fcf3ce44SJohn Forte 	}
513*fcf3ce44SJohn Forte 
514*fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
515*fcf3ce44SJohn Forte 		start_time = gethrtime();
516*fcf3ce44SJohn Forte 	}
517*fcf3ce44SJohn Forte 
518*fcf3ce44SJohn Forte 	if ((err = g_devices_get_all(wwn_list_ptr))
519*fcf3ce44SJohn Forte 		!= 0) {
520*fcf3ce44SJohn Forte 		return (err);
521*fcf3ce44SJohn Forte 	}
522*fcf3ce44SJohn Forte 
523*fcf3ce44SJohn Forte 	/*
524*fcf3ce44SJohn Forte 	 * retain backward compatibility with g_get_wwn_list
525*fcf3ce44SJohn Forte 	 * and retrieve the WWN for scsi_vhci devices in the
526*fcf3ce44SJohn Forte 	 * same fashion
527*fcf3ce44SJohn Forte 	 * Note that for scsi_vhci devices, the wwn fields are
528*fcf3ce44SJohn Forte 	 * not relevant but in the previous versions
529*fcf3ce44SJohn Forte 	 * we loaded the wwns so...
530*fcf3ce44SJohn Forte 	 */
531*fcf3ce44SJohn Forte 	wwn_list_p = *wwn_list_ptr;
532*fcf3ce44SJohn Forte 	while (wwn_list_p != NULL) {
533*fcf3ce44SJohn Forte 	    if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
534*fcf3ce44SJohn Forte 		/* get port wwn of first ONLINE, STANDBY */
535*fcf3ce44SJohn Forte 		if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path,
536*fcf3ce44SJohn Forte 			port_wwn)) == 0) {
537*fcf3ce44SJohn Forte 		    if ((search_wwn_entry(wwn_list_found, port_wwn,
538*fcf3ce44SJohn Forte 			node_wwn)) != 0) {
539*fcf3ce44SJohn Forte 			if ((err = get_wwns(wwn_list_p->physical_path, port_wwn,
540*fcf3ce44SJohn Forte 				node_wwn, &al_pa, &wwn_list_found)) != 0) {
541*fcf3ce44SJohn Forte 				g_free_wwn_list_found(&wwn_list_found);
542*fcf3ce44SJohn Forte 				return (err);
543*fcf3ce44SJohn Forte 			}
544*fcf3ce44SJohn Forte 		    }
545*fcf3ce44SJohn Forte 		} else {
546*fcf3ce44SJohn Forte 		    /* Use g_get_wwn as a last resort */
547*fcf3ce44SJohn Forte 		    if ((err = g_get_wwn(wwn_list_p->physical_path, port_wwn,
548*fcf3ce44SJohn Forte 			node_wwn, &al_pa, 0)) != 0) {
549*fcf3ce44SJohn Forte 			/*
550*fcf3ce44SJohn Forte 			 * this is a bad WWN.  remove it from the
551*fcf3ce44SJohn Forte 			 * wwn_list.
552*fcf3ce44SJohn Forte 			 *
553*fcf3ce44SJohn Forte 			 * After removing the bad WWN, wwn_list_p
554*fcf3ce44SJohn Forte 			 * should point to the next node in the list
555*fcf3ce44SJohn Forte 			 */
556*fcf3ce44SJohn Forte 			if ((wwn_list_p->wwn_prev == NULL) &&
557*fcf3ce44SJohn Forte 			    (wwn_list_p->wwn_next == NULL)) {
558*fcf3ce44SJohn Forte 			    *wwn_list_ptr = NULL;
559*fcf3ce44SJohn Forte 			    free(wwn_list_p);
560*fcf3ce44SJohn Forte 			    g_free_wwn_list_found(&wwn_list_found);
561*fcf3ce44SJohn Forte 			    return (L_NO_DEVICES_FOUND);
562*fcf3ce44SJohn Forte 			} else if (wwn_list_p->wwn_prev == NULL) {
563*fcf3ce44SJohn Forte 			    *wwn_list_ptr = wwn_list_p->wwn_next;
564*fcf3ce44SJohn Forte 			    free(wwn_list_p);
565*fcf3ce44SJohn Forte 			    wwn_list_p = *wwn_list_ptr;
566*fcf3ce44SJohn Forte 			    wwn_list_p->wwn_prev = NULL;
567*fcf3ce44SJohn Forte 			} else if (wwn_list_p->wwn_next == NULL) {
568*fcf3ce44SJohn Forte 			    wwn_list_p->wwn_prev->wwn_next = NULL;
569*fcf3ce44SJohn Forte 			    free(wwn_list_p);
570*fcf3ce44SJohn Forte 			    wwn_list_p = NULL;
571*fcf3ce44SJohn Forte 			} else {
572*fcf3ce44SJohn Forte 			    wwn_list_tmp_p = wwn_list_p->wwn_next;
573*fcf3ce44SJohn Forte 			    wwn_list_p->wwn_prev->wwn_next =
574*fcf3ce44SJohn Forte 				wwn_list_p->wwn_next;
575*fcf3ce44SJohn Forte 			    wwn_list_p->wwn_next->wwn_prev =
576*fcf3ce44SJohn Forte 				wwn_list_p->wwn_prev;
577*fcf3ce44SJohn Forte 			    free(wwn_list_p);
578*fcf3ce44SJohn Forte 			    wwn_list_p = wwn_list_tmp_p;
579*fcf3ce44SJohn Forte 			}
580*fcf3ce44SJohn Forte 			continue;
581*fcf3ce44SJohn Forte 		    }
582*fcf3ce44SJohn Forte 		}
583*fcf3ce44SJohn Forte 		copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn);
584*fcf3ce44SJohn Forte 		copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn);
585*fcf3ce44SJohn Forte 		memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE);
586*fcf3ce44SJohn Forte 	    }
587*fcf3ce44SJohn Forte 	    wwn_list_p = wwn_list_p->wwn_next;
588*fcf3ce44SJohn Forte 	}
589*fcf3ce44SJohn Forte 	g_free_wwn_list_found(&wwn_list_found);
590*fcf3ce44SJohn Forte 
591*fcf3ce44SJohn Forte 	/*
592*fcf3ce44SJohn Forte 	 * Now go through the list one more time to add entries for
593*fcf3ce44SJohn Forte 	 * any missing port wwns.
594*fcf3ce44SJohn Forte 	 * This allows a search on port wwn for any paths which are
595*fcf3ce44SJohn Forte 	 * ONLINE or STANDBY. We don't care about OFFLINE as those won't
596*fcf3ce44SJohn Forte 	 * and should not show up in the list
597*fcf3ce44SJohn Forte 	 */
598*fcf3ce44SJohn Forte 	for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL;
599*fcf3ce44SJohn Forte 	    wwn_list_p = wwn_list_p->wwn_next) {
600*fcf3ce44SJohn Forte 	    if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
601*fcf3ce44SJohn Forte 		if ((err = insert_missing_pwwn(wwn_list_p->physical_path,
602*fcf3ce44SJohn Forte 				    wwn_list_ptr)) != 0)
603*fcf3ce44SJohn Forte 			return (err);
604*fcf3ce44SJohn Forte 	    }
605*fcf3ce44SJohn Forte 	}
606*fcf3ce44SJohn Forte 
607*fcf3ce44SJohn Forte 	if (env != NULL) {
608*fcf3ce44SJohn Forte 		end_time = gethrtime();
609*fcf3ce44SJohn Forte 		fprintf(stdout, "      g_get_wwn_list: "
610*fcf3ce44SJohn Forte 		"\t\tTime = %lld millisec\n",
611*fcf3ce44SJohn Forte 		(end_time - start_time)/1000000);
612*fcf3ce44SJohn Forte 	}
613*fcf3ce44SJohn Forte 	return (0);
614*fcf3ce44SJohn Forte 
615*fcf3ce44SJohn Forte }
616*fcf3ce44SJohn Forte 
617*fcf3ce44SJohn Forte int
618*fcf3ce44SJohn Forte g_devices_get_all(struct wwn_list_struct **wwn_list_ptr)
619*fcf3ce44SJohn Forte {
620*fcf3ce44SJohn Forte struct wwn_list_struct *tape_ptr = NULL;
621*fcf3ce44SJohn Forte struct wwn_list_struct *tmp;
622*fcf3ce44SJohn Forte int err;
623*fcf3ce44SJohn Forte di_node_t root;
624*fcf3ce44SJohn Forte hrtime_t	start_time, end_time;
625*fcf3ce44SJohn Forte char *env = NULL;
626*fcf3ce44SJohn Forte 
627*fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
628*fcf3ce44SJohn Forte 		start_time = gethrtime();
629*fcf3ce44SJohn Forte 	}
630*fcf3ce44SJohn Forte 
631*fcf3ce44SJohn Forte 	/*
632*fcf3ce44SJohn Forte 	 * Try to prime di_drv_first_node()
633*fcf3ce44SJohn Forte 	 * If there are no nodes bound, di_drv_first_node()
634*fcf3ce44SJohn Forte 	 * will return nothing.
635*fcf3ce44SJohn Forte 	 */
636*fcf3ce44SJohn Forte 	init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST);
637*fcf3ce44SJohn Forte 	init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD);
638*fcf3ce44SJohn Forte 
639*fcf3ce44SJohn Forte 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
640*fcf3ce44SJohn Forte 		return (L_DEV_SNAPSHOT_FAILED);
641*fcf3ce44SJohn Forte 	}
642*fcf3ce44SJohn Forte 
643*fcf3ce44SJohn Forte 	if (env != NULL) {
644*fcf3ce44SJohn Forte 		end_time = gethrtime();
645*fcf3ce44SJohn Forte 		fprintf(stdout, "      di_init - /:  "
646*fcf3ce44SJohn Forte 		"\t\tTime = %lld millisec\n",
647*fcf3ce44SJohn Forte 		(end_time - start_time)/1000000);
648*fcf3ce44SJohn Forte 	}
649*fcf3ce44SJohn Forte 
650*fcf3ce44SJohn Forte 	if (env != NULL) {
651*fcf3ce44SJohn Forte 		start_time = gethrtime();
652*fcf3ce44SJohn Forte 	}
653*fcf3ce44SJohn Forte 
654*fcf3ce44SJohn Forte 	if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME,
655*fcf3ce44SJohn Forte 			wwn_list_ptr)) != 0) {
656*fcf3ce44SJohn Forte 		if (err != L_NO_DEVICES_FOUND) {
657*fcf3ce44SJohn Forte 			di_fini(root);
658*fcf3ce44SJohn Forte 			g_free_wwn_list(&tape_ptr);
659*fcf3ce44SJohn Forte 			g_free_wwn_list(wwn_list_ptr);
660*fcf3ce44SJohn Forte 			return (err);
661*fcf3ce44SJohn Forte 		}
662*fcf3ce44SJohn Forte 	}
663*fcf3ce44SJohn Forte 
664*fcf3ce44SJohn Forte 	if (env != NULL) {
665*fcf3ce44SJohn Forte 		end_time = gethrtime();
666*fcf3ce44SJohn Forte 		fprintf(stdout, "      devices_get_all - ssd:  "
667*fcf3ce44SJohn Forte 		"\t\tTime = %lld millisec\n",
668*fcf3ce44SJohn Forte 		(end_time - start_time)/1000000);
669*fcf3ce44SJohn Forte 	}
670*fcf3ce44SJohn Forte 
671*fcf3ce44SJohn Forte 	if (env != NULL) {
672*fcf3ce44SJohn Forte 		start_time = gethrtime();
673*fcf3ce44SJohn Forte 	}
674*fcf3ce44SJohn Forte 
675*fcf3ce44SJohn Forte 	if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME,
676*fcf3ce44SJohn Forte 			&tape_ptr)) != 0) {
677*fcf3ce44SJohn Forte 		di_fini(root);
678*fcf3ce44SJohn Forte 		if (err != L_NO_DEVICES_FOUND) {
679*fcf3ce44SJohn Forte 			g_free_wwn_list(&tape_ptr);
680*fcf3ce44SJohn Forte 			g_free_wwn_list(wwn_list_ptr);
681*fcf3ce44SJohn Forte 			return (err);
682*fcf3ce44SJohn Forte 		} else {
683*fcf3ce44SJohn Forte 			/*
684*fcf3ce44SJohn Forte 			 * if *wwn_list_ptr == NULL
685*fcf3ce44SJohn Forte 			 * we have disks but no tapes
686*fcf3ce44SJohn Forte 			 * Just return
687*fcf3ce44SJohn Forte 			 */
688*fcf3ce44SJohn Forte 			if (*wwn_list_ptr != NULL) {
689*fcf3ce44SJohn Forte 				return (0);
690*fcf3ce44SJohn Forte 			} else {
691*fcf3ce44SJohn Forte 				/*
692*fcf3ce44SJohn Forte 				 * No disks or tapes
693*fcf3ce44SJohn Forte 				 */
694*fcf3ce44SJohn Forte 				g_free_wwn_list(&tape_ptr);
695*fcf3ce44SJohn Forte 				g_free_wwn_list(wwn_list_ptr);
696*fcf3ce44SJohn Forte 				return (err);
697*fcf3ce44SJohn Forte 			}
698*fcf3ce44SJohn Forte 		}
699*fcf3ce44SJohn Forte 	}
700*fcf3ce44SJohn Forte 
701*fcf3ce44SJohn Forte 	if (env != NULL) {
702*fcf3ce44SJohn Forte 		end_time = gethrtime();
703*fcf3ce44SJohn Forte 		fprintf(stdout, "      devices_get_all - st: "
704*fcf3ce44SJohn Forte 		"\t\tTime = %lld millisec\n",
705*fcf3ce44SJohn Forte 		(end_time - start_time)/1000000);
706*fcf3ce44SJohn Forte 	}
707*fcf3ce44SJohn Forte 
708*fcf3ce44SJohn Forte 	/* Now link the two together */
709*fcf3ce44SJohn Forte 	if (*wwn_list_ptr != NULL) { /* We have both disks and tapes */
710*fcf3ce44SJohn Forte 		/* Walk to the end of it */
711*fcf3ce44SJohn Forte 		for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL;
712*fcf3ce44SJohn Forte 			tmp = tmp->wwn_next);
713*fcf3ce44SJohn Forte 		tmp->wwn_next = tape_ptr;
714*fcf3ce44SJohn Forte 		tape_ptr->wwn_prev = tmp;
715*fcf3ce44SJohn Forte 		di_fini(root);
716*fcf3ce44SJohn Forte 		return (0);
717*fcf3ce44SJohn Forte 	}
718*fcf3ce44SJohn Forte 
719*fcf3ce44SJohn Forte 	/* else we have no disks */
720*fcf3ce44SJohn Forte 	*wwn_list_ptr = tape_ptr;
721*fcf3ce44SJohn Forte 	di_fini(root);
722*fcf3ce44SJohn Forte 	return (0);
723*fcf3ce44SJohn Forte }
724*fcf3ce44SJohn Forte 
725*fcf3ce44SJohn Forte void
726*fcf3ce44SJohn Forte g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found) {
727*fcf3ce44SJohn Forte 	WWN_list_found	    *next = NULL;
728*fcf3ce44SJohn Forte 
729*fcf3ce44SJohn Forte 	/* return if wwn_list_found is NULL */
730*fcf3ce44SJohn Forte 	if (wwn_list_found == NULL) {
731*fcf3ce44SJohn Forte 		return;
732*fcf3ce44SJohn Forte 	}
733*fcf3ce44SJohn Forte 	for (; *wwn_list_found != NULL; *wwn_list_found = next) {
734*fcf3ce44SJohn Forte 		next = (*wwn_list_found)->wwn_next;
735*fcf3ce44SJohn Forte 		g_destroy_data(*wwn_list_found);
736*fcf3ce44SJohn Forte 		*wwn_list_found = NULL;
737*fcf3ce44SJohn Forte 	}
738*fcf3ce44SJohn Forte }
739*fcf3ce44SJohn Forte 
740*fcf3ce44SJohn Forte void
741*fcf3ce44SJohn Forte g_free_wwn_list(struct wwn_list_struct **wwn_list)
742*fcf3ce44SJohn Forte {
743*fcf3ce44SJohn Forte WWN_list	*next = NULL;
744*fcf3ce44SJohn Forte 
745*fcf3ce44SJohn Forte 	/* return if wwn_list is NULL */
746*fcf3ce44SJohn Forte 	if (wwn_list == NULL) {
747*fcf3ce44SJohn Forte 		return;
748*fcf3ce44SJohn Forte 	}
749*fcf3ce44SJohn Forte 
750*fcf3ce44SJohn Forte 	for (; *wwn_list != NULL; *wwn_list = next) {
751*fcf3ce44SJohn Forte 		next = (*wwn_list)->wwn_next;
752*fcf3ce44SJohn Forte 		if ((*wwn_list)->physical_path != NULL)
753*fcf3ce44SJohn Forte 			(void) g_destroy_data((*wwn_list)->physical_path);
754*fcf3ce44SJohn Forte 		if ((*wwn_list)->logical_path != NULL)
755*fcf3ce44SJohn Forte 			(void) g_destroy_data((*wwn_list)->logical_path);
756*fcf3ce44SJohn Forte 		(void) g_destroy_data(*wwn_list);
757*fcf3ce44SJohn Forte 	}
758*fcf3ce44SJohn Forte 	wwn_list = NULL;
759*fcf3ce44SJohn Forte }
760*fcf3ce44SJohn Forte 
761*fcf3ce44SJohn Forte 
762*fcf3ce44SJohn Forte 
763*fcf3ce44SJohn Forte 
764*fcf3ce44SJohn Forte void
765*fcf3ce44SJohn Forte g_sort_wwn_list(struct wwn_list_struct **wwn_list)
766*fcf3ce44SJohn Forte {
767*fcf3ce44SJohn Forte 	int			i, n;
768*fcf3ce44SJohn Forte 	struct wwn_list_struct	**wwn_list_array;
769*fcf3ce44SJohn Forte 	struct wwn_list_struct	*wwn_list_ptr;
770*fcf3ce44SJohn Forte 	struct wwn_list_struct	**wwn_list_array_ptr1;
771*fcf3ce44SJohn Forte 	struct wwn_list_struct	**wwn_list_array_ptr2;
772*fcf3ce44SJohn Forte 
773*fcf3ce44SJohn Forte 	/*
774*fcf3ce44SJohn Forte 	 * Count the number of wwn_list in the list
775*fcf3ce44SJohn Forte 	 */
776*fcf3ce44SJohn Forte 	for (n = 0,  wwn_list_ptr = *wwn_list;
777*fcf3ce44SJohn Forte 	    wwn_list_ptr != NULL;
778*fcf3ce44SJohn Forte 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
779*fcf3ce44SJohn Forte 		n++;
780*fcf3ce44SJohn Forte 	}
781*fcf3ce44SJohn Forte 	if (n <= 1) {
782*fcf3ce44SJohn Forte 		return;
783*fcf3ce44SJohn Forte 	}
784*fcf3ce44SJohn Forte 
785*fcf3ce44SJohn Forte 	/*
786*fcf3ce44SJohn Forte 	 * Allocate a simple wwn_list array and fill it in
787*fcf3ce44SJohn Forte 	 */
788*fcf3ce44SJohn Forte 	wwn_list_array = (struct wwn_list_struct **)
789*fcf3ce44SJohn Forte 	    g_zalloc((n+1) * sizeof (struct wwn_list_struct *));
790*fcf3ce44SJohn Forte 
791*fcf3ce44SJohn Forte 	wwn_list_array_ptr1 = wwn_list_array;
792*fcf3ce44SJohn Forte 	for (wwn_list_ptr = *wwn_list;
793*fcf3ce44SJohn Forte 	    wwn_list_ptr != NULL;
794*fcf3ce44SJohn Forte 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
795*fcf3ce44SJohn Forte 		*wwn_list_array_ptr1++ = wwn_list_ptr;
796*fcf3ce44SJohn Forte 	}
797*fcf3ce44SJohn Forte 	*wwn_list_array_ptr1 = NULL;
798*fcf3ce44SJohn Forte 
799*fcf3ce44SJohn Forte 	/*
800*fcf3ce44SJohn Forte 	 * Sort the wwn_list array
801*fcf3ce44SJohn Forte 	 */
802*fcf3ce44SJohn Forte 	qsort((void *) wwn_list_array, n,
803*fcf3ce44SJohn Forte 	    sizeof (struct wwn_list_struct *), wwn_list_name_compare);
804*fcf3ce44SJohn Forte 
805*fcf3ce44SJohn Forte 	/*
806*fcf3ce44SJohn Forte 	 * Rebuild the linked list wwn_list structure
807*fcf3ce44SJohn Forte 	 */
808*fcf3ce44SJohn Forte 	wwn_list_array_ptr1 = wwn_list_array;
809*fcf3ce44SJohn Forte 	*wwn_list = *wwn_list_array_ptr1;
810*fcf3ce44SJohn Forte 	wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1;
811*fcf3ce44SJohn Forte 	(*wwn_list_array_ptr1)->wwn_prev = NULL;
812*fcf3ce44SJohn Forte 	for (i = 0; i < n - 1; i++) {
813*fcf3ce44SJohn Forte 	    (*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1;
814*fcf3ce44SJohn Forte 	    (*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++;
815*fcf3ce44SJohn Forte 	}
816*fcf3ce44SJohn Forte 	(*wwn_list_array_ptr1)->wwn_next = NULL;
817*fcf3ce44SJohn Forte 
818*fcf3ce44SJohn Forte 	/*
819*fcf3ce44SJohn Forte 	 * Clean up
820*fcf3ce44SJohn Forte 	 */
821*fcf3ce44SJohn Forte 	(void) g_destroy_data((void *)wwn_list_array);
822*fcf3ce44SJohn Forte }
823*fcf3ce44SJohn Forte 
824*fcf3ce44SJohn Forte int
825*fcf3ce44SJohn Forte wwn_list_name_compare(const void *arg1, const void *arg2)
826*fcf3ce44SJohn Forte {
827*fcf3ce44SJohn Forte 	char	*s1, *s2;
828*fcf3ce44SJohn Forte 	int	n1, n2;
829*fcf3ce44SJohn Forte 	char	*p1, *p2;
830*fcf3ce44SJohn Forte 
831*fcf3ce44SJohn Forte 	s1 = (*((struct wwn_list_struct **)arg1))->logical_path;
832*fcf3ce44SJohn Forte 	s2 = (*((struct wwn_list_struct **)arg2))->logical_path;
833*fcf3ce44SJohn Forte 	for (;;) {
834*fcf3ce44SJohn Forte 		if (*s1 == 0 || *s2 == 0)
835*fcf3ce44SJohn Forte 			break;
836*fcf3ce44SJohn Forte 		if ((isdigit(*s1) && isdigit(*s2))) {
837*fcf3ce44SJohn Forte 			n1 = strtol(s1, &p1, 10);
838*fcf3ce44SJohn Forte 			n2 = strtol(s2, &p2, 10);
839*fcf3ce44SJohn Forte 			if (n1 != n2) {
840*fcf3ce44SJohn Forte 				return (n1 - n2);
841*fcf3ce44SJohn Forte 			}
842*fcf3ce44SJohn Forte 			s1 = p1;
843*fcf3ce44SJohn Forte 			s2 = p2;
844*fcf3ce44SJohn Forte 		} else if (*s1 != *s2) {
845*fcf3ce44SJohn Forte 			break;
846*fcf3ce44SJohn Forte 		} else {
847*fcf3ce44SJohn Forte 			s1++;
848*fcf3ce44SJohn Forte 			s2++;
849*fcf3ce44SJohn Forte 		}
850*fcf3ce44SJohn Forte 	}
851*fcf3ce44SJohn Forte 	return (*s1 - *s2);
852*fcf3ce44SJohn Forte }
853*fcf3ce44SJohn Forte 
854*fcf3ce44SJohn Forte /*
855*fcf3ce44SJohn Forte  * Get the limited map for FC4 devices.
856*fcf3ce44SJohn Forte  * This function is specific to FC4
857*fcf3ce44SJohn Forte  * devices and doesn't work for FC (leadville) devices.
858*fcf3ce44SJohn Forte  *
859*fcf3ce44SJohn Forte  * RETURN VALUES:
860*fcf3ce44SJohn Forte  *	0	 O.K.
861*fcf3ce44SJohn Forte  *	non-zero otherwise
862*fcf3ce44SJohn Forte  *
863*fcf3ce44SJohn Forte  * lilpmap *map_ptr:
864*fcf3ce44SJohn Forte  *		NULL: No devices found
865*fcf3ce44SJohn Forte  *		!NULL: if devices found
866*fcf3ce44SJohn Forte  */
867*fcf3ce44SJohn Forte int
868*fcf3ce44SJohn Forte g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose)
869*fcf3ce44SJohn Forte {
870*fcf3ce44SJohn Forte int	fd, i;
871*fcf3ce44SJohn Forte char	drvr_path[MAXPATHLEN];
872*fcf3ce44SJohn Forte struct	stat	stbuf;
873*fcf3ce44SJohn Forte 
874*fcf3ce44SJohn Forte 
875*fcf3ce44SJohn Forte 	/* initialize map */
876*fcf3ce44SJohn Forte 	(void) memset(map_ptr, 0, sizeof (struct lilpmap));
877*fcf3ce44SJohn Forte 
878*fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
879*fcf3ce44SJohn Forte 	/*
880*fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
881*fcf3ce44SJohn Forte 	 *
882*fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
883*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0:1
884*fcf3ce44SJohn Forte 	 * or
885*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0
886*fcf3ce44SJohn Forte 	 * or
887*fcf3ce44SJohn Forte 	 * a 1 level PCI type driver
888*fcf3ce44SJohn Forte 	 */
889*fcf3ce44SJohn Forte 	if (stat(drvr_path, &stbuf) < 0) {
890*fcf3ce44SJohn Forte 		return (L_LSTAT_ERROR);
891*fcf3ce44SJohn Forte 	}
892*fcf3ce44SJohn Forte 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
893*fcf3ce44SJohn Forte 		/* append a port. Just try 0 since they did not give us one */
894*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, ":0");
895*fcf3ce44SJohn Forte 	}
896*fcf3ce44SJohn Forte 
897*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_limited_map: Geting drive map from:"
898*fcf3ce44SJohn Forte 		" %s\n", drvr_path);
899*fcf3ce44SJohn Forte 
900*fcf3ce44SJohn Forte 	/* open controller */
901*fcf3ce44SJohn Forte 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
902*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
903*fcf3ce44SJohn Forte 
904*fcf3ce44SJohn Forte 	if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) {
905*fcf3ce44SJohn Forte 		I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
906*fcf3ce44SJohn Forte 		(void) close(fd);
907*fcf3ce44SJohn Forte 		return (L_FCIO_GETMAP_IOCTL_FAIL);
908*fcf3ce44SJohn Forte 	}
909*fcf3ce44SJohn Forte 	(void) close(fd);
910*fcf3ce44SJohn Forte 
911*fcf3ce44SJohn Forte 	/*
912*fcf3ce44SJohn Forte 	 * Check for reasonableness.
913*fcf3ce44SJohn Forte 	 */
914*fcf3ce44SJohn Forte 	if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) {
915*fcf3ce44SJohn Forte 		return (L_INVALID_LOOP_MAP);
916*fcf3ce44SJohn Forte 	}
917*fcf3ce44SJohn Forte 	for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) {
918*fcf3ce44SJohn Forte 		if (map_ptr->lilp_list[i] > 0xef) {
919*fcf3ce44SJohn Forte 			return (L_INVALID_LOOP_MAP);
920*fcf3ce44SJohn Forte 		}
921*fcf3ce44SJohn Forte 	}
922*fcf3ce44SJohn Forte 
923*fcf3ce44SJohn Forte 	return (0);
924*fcf3ce44SJohn Forte }
925*fcf3ce44SJohn Forte 
926*fcf3ce44SJohn Forte 
927*fcf3ce44SJohn Forte /*
928*fcf3ce44SJohn Forte  * For leadville specific HBA's ONLY.
929*fcf3ce44SJohn Forte  * Get the host specific parameters,
930*fcf3ce44SJohn Forte  * al_pa, hard address, node/port WWN etc.
931*fcf3ce44SJohn Forte  *
932*fcf3ce44SJohn Forte  * OUTPUT:
933*fcf3ce44SJohn Forte  *	fc_port_dev_t structure.
934*fcf3ce44SJohn Forte  *
935*fcf3ce44SJohn Forte  * RETURNS:
936*fcf3ce44SJohn Forte  *	0	if  OK
937*fcf3ce44SJohn Forte  *	non-zero in case of error.
938*fcf3ce44SJohn Forte  */
939*fcf3ce44SJohn Forte int
940*fcf3ce44SJohn Forte g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose)
941*fcf3ce44SJohn Forte {
942*fcf3ce44SJohn Forte int		err;
943*fcf3ce44SJohn Forte int		fd;
944*fcf3ce44SJohn Forte int		dev_type;
945*fcf3ce44SJohn Forte fcio_t		fcio;
946*fcf3ce44SJohn Forte 
947*fcf3ce44SJohn Forte 	/* return invalid path if host_path is NULL */
948*fcf3ce44SJohn Forte 	if (host_path == NULL) {
949*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
950*fcf3ce44SJohn Forte 	}
951*fcf3ce44SJohn Forte 	/* return invalid arg if host_val is NULL */
952*fcf3ce44SJohn Forte 	if (host_val == NULL) {
953*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
954*fcf3ce44SJohn Forte 	}
955*fcf3ce44SJohn Forte 
956*fcf3ce44SJohn Forte 	dev_type = g_get_path_type(host_path);
957*fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
958*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
959*fcf3ce44SJohn Forte 	}
960*fcf3ce44SJohn Forte 	if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) {
961*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
962*fcf3ce44SJohn Forte 	}
963*fcf3ce44SJohn Forte 
964*fcf3ce44SJohn Forte 	/* initialize structure */
965*fcf3ce44SJohn Forte 	(void) memset(host_val, 0, sizeof (struct fc_port_dev));
966*fcf3ce44SJohn Forte 
967*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
968*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
969*fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)host_val;
970*fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (fc_port_dev_t);
971*fcf3ce44SJohn Forte 
972*fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
973*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
974*fcf3ce44SJohn Forte 		(void) close(fd);
975*fcf3ce44SJohn Forte 		return (L_FCIO_GET_HOST_PARAMS_FAIL);
976*fcf3ce44SJohn Forte 	}
977*fcf3ce44SJohn Forte 	(void) close(fd);
978*fcf3ce44SJohn Forte 
979*fcf3ce44SJohn Forte 	/* get the inquiry information for the leadville HBA. */
980*fcf3ce44SJohn Forte 	if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn,
981*fcf3ce44SJohn Forte 				&host_val->dev_dtype)) != 0) {
982*fcf3ce44SJohn Forte 		return (err);
983*fcf3ce44SJohn Forte 	}
984*fcf3ce44SJohn Forte 	return (0);
985*fcf3ce44SJohn Forte }
986*fcf3ce44SJohn Forte 
987*fcf3ce44SJohn Forte 
988*fcf3ce44SJohn Forte 
989*fcf3ce44SJohn Forte /*
990*fcf3ce44SJohn Forte  * Issue FCIO ioctls to the port(fp) driver.
991*fcf3ce44SJohn Forte  * FCIO ioctl needs to be retried when it
992*fcf3ce44SJohn Forte  * is returned with an EINVAL error, wait
993*fcf3ce44SJohn Forte  * time between retries should be atleast
994*fcf3ce44SJohn Forte  * WAIT_FCIO_IOCTL (too much of a time to wait!!)
995*fcf3ce44SJohn Forte  *
996*fcf3ce44SJohn Forte  * OUTPUT:
997*fcf3ce44SJohn Forte  *	fcio_t structure
998*fcf3ce44SJohn Forte  *
999*fcf3ce44SJohn Forte  * RETURNS:
1000*fcf3ce44SJohn Forte  *	0	 if O.K.
1001*fcf3ce44SJohn Forte  *	non-zero otherwise.
1002*fcf3ce44SJohn Forte  */
1003*fcf3ce44SJohn Forte int
1004*fcf3ce44SJohn Forte g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose)
1005*fcf3ce44SJohn Forte {
1006*fcf3ce44SJohn Forte int	ntries;
1007*fcf3ce44SJohn Forte 
1008*fcf3ce44SJohn Forte 	for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
1009*fcf3ce44SJohn Forte 		if (ioctl(fd, FCIO_CMD, fcio) != 0) {
1010*fcf3ce44SJohn Forte 			if ((errno == EAGAIN) &&
1011*fcf3ce44SJohn Forte 				(ntries+1 < RETRY_FCIO_IOCTL)) {
1012*fcf3ce44SJohn Forte 				/* wait WAIT_FCIO_IOCTL */
1013*fcf3ce44SJohn Forte 				(void) usleep(WAIT_FCIO_IOCTL);
1014*fcf3ce44SJohn Forte 				continue;
1015*fcf3ce44SJohn Forte 			}
1016*fcf3ce44SJohn Forte 			I_DPRINTF("FCIO ioctl failed.\n"
1017*fcf3ce44SJohn Forte 				"Error: %s. fc_error = %d (0x%x)\n",
1018*fcf3ce44SJohn Forte 			strerror(errno), fcio->fcio_errno, fcio->fcio_errno);
1019*fcf3ce44SJohn Forte 			if (errno == EINVAL) {
1020*fcf3ce44SJohn Forte 				if (fcio->fcio_errno == FC_TOOMANY) {
1021*fcf3ce44SJohn Forte 					return (L_INVALID_DEVICE_COUNT);
1022*fcf3ce44SJohn Forte 				} else {
1023*fcf3ce44SJohn Forte 					return (errno);
1024*fcf3ce44SJohn Forte 				}
1025*fcf3ce44SJohn Forte 			}
1026*fcf3ce44SJohn Forte 			/*
1027*fcf3ce44SJohn Forte 			 * When port is offlined, qlc
1028*fcf3ce44SJohn Forte 			 * returns the FC_OFFLINE error and errno
1029*fcf3ce44SJohn Forte 			 * is set to EIO.
1030*fcf3ce44SJohn Forte 			 * We do want to ignore this error,
1031*fcf3ce44SJohn Forte 			 * especially when an enclosure is
1032*fcf3ce44SJohn Forte 			 * removed from the loop.
1033*fcf3ce44SJohn Forte 			 */
1034*fcf3ce44SJohn Forte 			if (fcio->fcio_errno == FC_OFFLINE)
1035*fcf3ce44SJohn Forte 				break;
1036*fcf3ce44SJohn Forte 			return (-1);
1037*fcf3ce44SJohn Forte 		}
1038*fcf3ce44SJohn Forte 		break;
1039*fcf3ce44SJohn Forte 	}
1040*fcf3ce44SJohn Forte 
1041*fcf3ce44SJohn Forte 	return (0);
1042*fcf3ce44SJohn Forte }
1043*fcf3ce44SJohn Forte 
1044*fcf3ce44SJohn Forte /*
1045*fcf3ce44SJohn Forte  * This function issues the FCP_TGT_INQUIRY ioctl to
1046*fcf3ce44SJohn Forte  * the fcp module
1047*fcf3ce44SJohn Forte  *
1048*fcf3ce44SJohn Forte  * OUTPUT:
1049*fcf3ce44SJohn Forte  *	fcp_ioctl structure in fcp_data is filled in by fcp
1050*fcf3ce44SJohn Forte  *
1051*fcf3ce44SJohn Forte  * RETURN VALUES :
1052*fcf3ce44SJohn Forte  *	0 on Success
1053*fcf3ce44SJohn Forte  *	Non-zero otherwise
1054*fcf3ce44SJohn Forte  */
1055*fcf3ce44SJohn Forte static int
1056*fcf3ce44SJohn Forte g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose)
1057*fcf3ce44SJohn Forte {
1058*fcf3ce44SJohn Forte 	int 			num_tries = 0;
1059*fcf3ce44SJohn Forte 	struct device_data	*dev_data = NULL;
1060*fcf3ce44SJohn Forte 
1061*fcf3ce44SJohn Forte 	/*
1062*fcf3ce44SJohn Forte 	 * Issue the ioctl to FCP
1063*fcf3ce44SJohn Forte 	 * The retries are required because the driver may
1064*fcf3ce44SJohn Forte 	 * need some time to respond at times.
1065*fcf3ce44SJohn Forte 	 */
1066*fcf3ce44SJohn Forte 	while (num_tries++ < RETRY_FCP_IOCTL) {
1067*fcf3ce44SJohn Forte 		/* if ioctl fails it is an error from Solaris operation. */
1068*fcf3ce44SJohn Forte 		if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) {
1069*fcf3ce44SJohn Forte 			if (errno == EAGAIN) {
1070*fcf3ce44SJohn Forte 				(void) usleep(WAIT_FCP_IOCTL);
1071*fcf3ce44SJohn Forte 				continue;
1072*fcf3ce44SJohn Forte 			} else {
1073*fcf3ce44SJohn Forte 				break;
1074*fcf3ce44SJohn Forte 			}
1075*fcf3ce44SJohn Forte 		}
1076*fcf3ce44SJohn Forte 		dev_data = (struct device_data *)((void *)(fcp_data->list));
1077*fcf3ce44SJohn Forte 		if (dev_data->dev_status == 0) {
1078*fcf3ce44SJohn Forte 			return (0);
1079*fcf3ce44SJohn Forte 		}
1080*fcf3ce44SJohn Forte 
1081*fcf3ce44SJohn Forte 		if (dev_data->dev_status == EAGAIN) {
1082*fcf3ce44SJohn Forte 			(void) usleep(WAIT_FCP_IOCTL);
1083*fcf3ce44SJohn Forte 			continue;
1084*fcf3ce44SJohn Forte 		} else {
1085*fcf3ce44SJohn Forte 			dev_data->dev0_type = DTYPE_UNKNOWN;
1086*fcf3ce44SJohn Forte 			return (0);
1087*fcf3ce44SJohn Forte 		}
1088*fcf3ce44SJohn Forte 	}
1089*fcf3ce44SJohn Forte 
1090*fcf3ce44SJohn Forte 	return (L_FCP_TGT_INQUIRY_FAIL);
1091*fcf3ce44SJohn Forte }
1092*fcf3ce44SJohn Forte 
1093*fcf3ce44SJohn Forte /*
1094*fcf3ce44SJohn Forte  * Get the number of devices and also
1095*fcf3ce44SJohn Forte  * a list of devices accessible through
1096*fcf3ce44SJohn Forte  * the device's port as specified by path.
1097*fcf3ce44SJohn Forte  * The calling function * is responsible for freeing the dev_list.
1098*fcf3ce44SJohn Forte  *
1099*fcf3ce44SJohn Forte  * Acquires inq_dtype from g_get_inq_dtype() and
1100*fcf3ce44SJohn Forte  * stores into dev_dtype field of fc_port_dev.
1101*fcf3ce44SJohn Forte  *
1102*fcf3ce44SJohn Forte  * For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login
1103*fcf3ce44SJohn Forte  * and get inq dtype.
1104*fcf3ce44SJohn Forte  *
1105*fcf3ce44SJohn Forte  * dev_list:
1106*fcf3ce44SJohn Forte  *	NULL:	  No devices found, in case of an error
1107*fcf3ce44SJohn Forte  *	Non-NULL: Devices found.
1108*fcf3ce44SJohn Forte  * ndevs:
1109*fcf3ce44SJohn Forte  *	set to the number of devices
1110*fcf3ce44SJohn Forte  *	accessible through the port.
1111*fcf3ce44SJohn Forte  *
1112*fcf3ce44SJohn Forte  * RETURNS:
1113*fcf3ce44SJohn Forte  *	0	 if O.K.
1114*fcf3ce44SJohn Forte  *	non-zero otherwise
1115*fcf3ce44SJohn Forte  */
1116*fcf3ce44SJohn Forte int
1117*fcf3ce44SJohn Forte g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs)
1118*fcf3ce44SJohn Forte {
1119*fcf3ce44SJohn Forte int		num_devices = 0;
1120*fcf3ce44SJohn Forte int		i, err, ulp_failure = 0, new_count = 0;
1121*fcf3ce44SJohn Forte int		dev_type;
1122*fcf3ce44SJohn Forte int		fd;
1123*fcf3ce44SJohn Forte char		fcapath[MAXPATHLEN];
1124*fcf3ce44SJohn Forte char		*char_ptr;
1125*fcf3ce44SJohn Forte struct	stat	stbuf;
1126*fcf3ce44SJohn Forte fcio_t		fcio;
1127*fcf3ce44SJohn Forte uint32_t	port_top;
1128*fcf3ce44SJohn Forte fc_port_dev_t	*dlist;
1129*fcf3ce44SJohn Forte 
1130*fcf3ce44SJohn Forte 	*dev_list = dlist = NULL;
1131*fcf3ce44SJohn Forte 	(void) strcpy(fcapath, path);
1132*fcf3ce44SJohn Forte 	/*
1133*fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
1134*fcf3ce44SJohn Forte 	 *
1135*fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
1136*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1137*fcf3ce44SJohn Forte 	 * or
1138*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1139*fcf3ce44SJohn Forte 	 * or
1140*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1141*fcf3ce44SJohn Forte 	 * or
1142*fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
1143*fcf3ce44SJohn Forte 	 */
1144*fcf3ce44SJohn Forte 	if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) {
1145*fcf3ce44SJohn Forte 		if ((char_ptr = strrchr(fcapath, '/')) == NULL) {
1146*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
1147*fcf3ce44SJohn Forte 		}
1148*fcf3ce44SJohn Forte 		*char_ptr = '\0';   /* Terminate sting  */
1149*fcf3ce44SJohn Forte 		/* append controller */
1150*fcf3ce44SJohn Forte 		(void) strcat(fcapath, FC_CTLR);
1151*fcf3ce44SJohn Forte 	} else {
1152*fcf3ce44SJohn Forte 		if (stat(fcapath, &stbuf) < 0) {
1153*fcf3ce44SJohn Forte 			return (L_LSTAT_ERROR);
1154*fcf3ce44SJohn Forte 		}
1155*fcf3ce44SJohn Forte 		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1156*fcf3ce44SJohn Forte 			/* append controller */
1157*fcf3ce44SJohn Forte 			(void) strcat(fcapath, FC_CTLR);
1158*fcf3ce44SJohn Forte 		}
1159*fcf3ce44SJohn Forte 	}
1160*fcf3ce44SJohn Forte 	dev_type = g_get_path_type(fcapath);
1161*fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1162*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1163*fcf3ce44SJohn Forte 	}
1164*fcf3ce44SJohn Forte 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1165*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1166*fcf3ce44SJohn Forte 	}
1167*fcf3ce44SJohn Forte 
1168*fcf3ce44SJohn Forte 	/*
1169*fcf3ce44SJohn Forte 	 * Get the device list from port driver
1170*fcf3ce44SJohn Forte 	 */
1171*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
1172*fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (num_devices);
1173*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
1174*fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)&num_devices;
1175*fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
1176*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
1177*fcf3ce44SJohn Forte 		(void) close(fd);
1178*fcf3ce44SJohn Forte 		return (L_FCIO_GET_NUM_DEVS_FAIL);
1179*fcf3ce44SJohn Forte 	}
1180*fcf3ce44SJohn Forte 	if (num_devices == 0) {
1181*fcf3ce44SJohn Forte 		*ndevs = 0;
1182*fcf3ce44SJohn Forte 		(void) close(fd);
1183*fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
1184*fcf3ce44SJohn Forte 	}
1185*fcf3ce44SJohn Forte 
1186*fcf3ce44SJohn Forte 	if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1187*fcf3ce44SJohn Forte 				sizeof (fc_port_dev_t))) == NULL) {
1188*fcf3ce44SJohn Forte 		(void) close(fd);
1189*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1190*fcf3ce44SJohn Forte 	}
1191*fcf3ce44SJohn Forte 	bzero((caddr_t)&fcio, sizeof (fcio));
1192*fcf3ce44SJohn Forte 	/* Get the device list */
1193*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1194*fcf3ce44SJohn Forte 	/* Information read operation */
1195*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
1196*fcf3ce44SJohn Forte 	fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1197*fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)dlist;
1198*fcf3ce44SJohn Forte 	/* new device count */
1199*fcf3ce44SJohn Forte 	fcio.fcio_alen = sizeof (new_count);
1200*fcf3ce44SJohn Forte 	fcio.fcio_abuf = (caddr_t)&new_count;
1201*fcf3ce44SJohn Forte 	if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1202*fcf3ce44SJohn Forte 	    if (err == L_INVALID_DEVICE_COUNT) {
1203*fcf3ce44SJohn Forte 		/*
1204*fcf3ce44SJohn Forte 		 * original buffer was small so allocate buffer
1205*fcf3ce44SJohn Forte 		 * with a new count and retry.
1206*fcf3ce44SJohn Forte 		 */
1207*fcf3ce44SJohn Forte 		free(dlist);
1208*fcf3ce44SJohn Forte 		num_devices = new_count;
1209*fcf3ce44SJohn Forte 		new_count = 0;
1210*fcf3ce44SJohn Forte 		if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1211*fcf3ce44SJohn Forte 				sizeof (fc_port_dev_t))) == NULL) {
1212*fcf3ce44SJohn Forte 			(void) close(fd);
1213*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
1214*fcf3ce44SJohn Forte 		}
1215*fcf3ce44SJohn Forte 		fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1216*fcf3ce44SJohn Forte 		/* Information read operation */
1217*fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_READ;
1218*fcf3ce44SJohn Forte 		fcio.fcio_obuf = (caddr_t)dlist;
1219*fcf3ce44SJohn Forte 		fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1220*fcf3ce44SJohn Forte 		/* new device count */
1221*fcf3ce44SJohn Forte 		fcio.fcio_alen = sizeof (new_count);
1222*fcf3ce44SJohn Forte 		fcio.fcio_abuf = (caddr_t)&new_count;
1223*fcf3ce44SJohn Forte 		if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1224*fcf3ce44SJohn Forte 		    if (err == L_INVALID_DEVICE_COUNT) {
1225*fcf3ce44SJohn Forte 			/*
1226*fcf3ce44SJohn Forte 			 * No more retry. There may be severe hardware
1227*fcf3ce44SJohn Forte 			 * problem so return error here.
1228*fcf3ce44SJohn Forte 			 */
1229*fcf3ce44SJohn Forte 			I_DPRINTF(" Device count was %d"
1230*fcf3ce44SJohn Forte 			" should have been %d\n",
1231*fcf3ce44SJohn Forte 			num_devices, new_count);
1232*fcf3ce44SJohn Forte 		    } else {
1233*fcf3ce44SJohn Forte 			I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
1234*fcf3ce44SJohn Forte 			err = L_FCIO_GET_DEV_LIST_FAIL;
1235*fcf3ce44SJohn Forte 		    }
1236*fcf3ce44SJohn Forte 		    free(dlist);
1237*fcf3ce44SJohn Forte 		    (void) close(fd);
1238*fcf3ce44SJohn Forte 		    return (err);
1239*fcf3ce44SJohn Forte 		}
1240*fcf3ce44SJohn Forte 	    } else {
1241*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
1242*fcf3ce44SJohn Forte 		free(dlist);
1243*fcf3ce44SJohn Forte 		(void) close(fd);
1244*fcf3ce44SJohn Forte 		return (L_FCIO_GET_DEV_LIST_FAIL);
1245*fcf3ce44SJohn Forte 	    }
1246*fcf3ce44SJohn Forte 	}
1247*fcf3ce44SJohn Forte 
1248*fcf3ce44SJohn Forte 	/*
1249*fcf3ce44SJohn Forte 	 * if new count is smaller than the original number from
1250*fcf3ce44SJohn Forte 	 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
1251*fcf3ce44SJohn Forte 	 * and continue.
1252*fcf3ce44SJohn Forte 	 */
1253*fcf3ce44SJohn Forte 	if (new_count < num_devices) {
1254*fcf3ce44SJohn Forte 		if (new_count == 0) {
1255*fcf3ce44SJohn Forte 			*ndevs = 0;
1256*fcf3ce44SJohn Forte 			(void) close(fd);
1257*fcf3ce44SJohn Forte 			S_FREE(dlist);
1258*fcf3ce44SJohn Forte 			return (L_NO_DEVICES_FOUND);
1259*fcf3ce44SJohn Forte 		}
1260*fcf3ce44SJohn Forte 		num_devices = new_count;
1261*fcf3ce44SJohn Forte 		if ((dlist = (fc_port_dev_t *)realloc(dlist,
1262*fcf3ce44SJohn Forte 				(new_count * sizeof (fc_port_dev_t))))
1263*fcf3ce44SJohn Forte 				== NULL) {
1264*fcf3ce44SJohn Forte 			S_FREE(dlist);
1265*fcf3ce44SJohn Forte 			(void) close(fd);
1266*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
1267*fcf3ce44SJohn Forte 		}
1268*fcf3ce44SJohn Forte 	}
1269*fcf3ce44SJohn Forte 
1270*fcf3ce44SJohn Forte 	*dev_list = dlist;
1271*fcf3ce44SJohn Forte 	*ndevs = num_devices;
1272*fcf3ce44SJohn Forte 
1273*fcf3ce44SJohn Forte 	/* close here since fcapath will be passed to other routines. */
1274*fcf3ce44SJohn Forte 	(void) close(fd);
1275*fcf3ce44SJohn Forte 
1276*fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1277*fcf3ce44SJohn Forte 		free(*dev_list);
1278*fcf3ce44SJohn Forte 		*dev_list = NULL;
1279*fcf3ce44SJohn Forte 		return (err);
1280*fcf3ce44SJohn Forte 	}
1281*fcf3ce44SJohn Forte 
1282*fcf3ce44SJohn Forte 	/* Get the inq_dtype for each device on dev list. */
1283*fcf3ce44SJohn Forte 	for (i = 0; i < num_devices; i++, dlist++) {
1284*fcf3ce44SJohn Forte 		/* Get the inq_dtype for each device. */
1285*fcf3ce44SJohn Forte 		if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn,
1286*fcf3ce44SJohn Forte 				&dlist->dev_dtype)) != 0) {
1287*fcf3ce44SJohn Forte 			/*
1288*fcf3ce44SJohn Forte 			 * if g_get_inq_dtype failed on g_dev_login
1289*fcf3ce44SJohn Forte 			 * or g_issue_fcp_ioctl, continue to the next
1290*fcf3ce44SJohn Forte 			 * dev on dlist.
1291*fcf3ce44SJohn Forte 			 * L_GET_DEV_LIST_ULP_FAILURE is returned
1292*fcf3ce44SJohn Forte 			 * after processing the whole dlist.
1293*fcf3ce44SJohn Forte 			 */
1294*fcf3ce44SJohn Forte 			if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
1295*fcf3ce44SJohn Forte 				(err == L_FCP_TGT_INQUIRY_FAIL)) {
1296*fcf3ce44SJohn Forte 				ulp_failure = 1;
1297*fcf3ce44SJohn Forte 				dlist->dev_dtype = GFC_ERR_INQ_DTYPE;
1298*fcf3ce44SJohn Forte 			} else {
1299*fcf3ce44SJohn Forte 				(void) free(*dev_list);
1300*fcf3ce44SJohn Forte 				*dev_list = NULL;
1301*fcf3ce44SJohn Forte 				return (err);
1302*fcf3ce44SJohn Forte 			}
1303*fcf3ce44SJohn Forte 		}
1304*fcf3ce44SJohn Forte 	}
1305*fcf3ce44SJohn Forte 
1306*fcf3ce44SJohn Forte 	if (ulp_failure) {
1307*fcf3ce44SJohn Forte 		return (L_GET_DEV_LIST_ULP_FAILURE);
1308*fcf3ce44SJohn Forte 	} else {
1309*fcf3ce44SJohn Forte 		return (0);
1310*fcf3ce44SJohn Forte 	}
1311*fcf3ce44SJohn Forte }
1312*fcf3ce44SJohn Forte 
1313*fcf3ce44SJohn Forte 
1314*fcf3ce44SJohn Forte /* Constant used by g_get_inq_dtype() */
1315*fcf3ce44SJohn Forte #define	FCP_PATH	"/devices/pseudo/fcp@0:fcp"
1316*fcf3ce44SJohn Forte 
1317*fcf3ce44SJohn Forte /*
1318*fcf3ce44SJohn Forte  * Gets the inq_dtype for devices on the fabric FC driver
1319*fcf3ce44SJohn Forte  * through an ioctl to the FCP module.
1320*fcf3ce44SJohn Forte  *
1321*fcf3ce44SJohn Forte  * OUTPUT:
1322*fcf3ce44SJohn Forte  *	inq_dtype is set to the dtype on success
1323*fcf3ce44SJohn Forte  *
1324*fcf3ce44SJohn Forte  * RETURN VALUES:
1325*fcf3ce44SJohn Forte  *	0 on Success
1326*fcf3ce44SJohn Forte  *	Non-zero on error
1327*fcf3ce44SJohn Forte  */
1328*fcf3ce44SJohn Forte int
1329*fcf3ce44SJohn Forte g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1330*fcf3ce44SJohn Forte {
1331*fcf3ce44SJohn Forte 	int			dev_type, fd;
1332*fcf3ce44SJohn Forte 	int			err, fcp_fd;
1333*fcf3ce44SJohn Forte 	uint32_t		state;
1334*fcf3ce44SJohn Forte 	uint32_t		port_top = 0;
1335*fcf3ce44SJohn Forte 	struct fcp_ioctl	fcp_data;
1336*fcf3ce44SJohn Forte 	struct device_data	inq_data;
1337*fcf3ce44SJohn Forte 	struct stat		sbuf;
1338*fcf3ce44SJohn Forte 
1339*fcf3ce44SJohn Forte 	dev_type = g_get_path_type(fcapath);
1340*fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1341*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1342*fcf3ce44SJohn Forte 	}
1343*fcf3ce44SJohn Forte 
1344*fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1345*fcf3ce44SJohn Forte 		return (err);
1346*fcf3ce44SJohn Forte 	}
1347*fcf3ce44SJohn Forte 
1348*fcf3ce44SJohn Forte 	if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) {
1349*fcf3ce44SJohn Forte 		/*
1350*fcf3ce44SJohn Forte 		 * if there is an error on getting port state we will
1351*fcf3ce44SJohn Forte 		 * continue to login.
1352*fcf3ce44SJohn Forte 		 * state can be either of
1353*fcf3ce44SJohn Forte 		 * PORT_DEVICE_INVALID, PORT_DEVICE_VALID,
1354*fcf3ce44SJohn Forte 		 * PORT_DEVICE_LOGGED_IN.  Trying port login
1355*fcf3ce44SJohn Forte 		 * unless already logged in.
1356*fcf3ce44SJohn Forte 		 * It will be examined if there is an adverse
1357*fcf3ce44SJohn Forte 		 * effect on invalid state device.
1358*fcf3ce44SJohn Forte 		 */
1359*fcf3ce44SJohn Forte 		if (((err = g_get_dev_port_state(fcapath, pwwn, &state))
1360*fcf3ce44SJohn Forte 				!= 0) || (state != PORT_DEVICE_LOGGED_IN)) {
1361*fcf3ce44SJohn Forte 			/* do port login to fabric device.  */
1362*fcf3ce44SJohn Forte 			if ((err = g_dev_login(fcapath, pwwn)) != 0) {
1363*fcf3ce44SJohn Forte 				return (err);
1364*fcf3ce44SJohn Forte 			}
1365*fcf3ce44SJohn Forte 		}
1366*fcf3ce44SJohn Forte 	}
1367*fcf3ce44SJohn Forte 
1368*fcf3ce44SJohn Forte 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1)
1369*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1370*fcf3ce44SJohn Forte 
1371*fcf3ce44SJohn Forte 	if (fstat(fd, &sbuf) == -1) {
1372*fcf3ce44SJohn Forte 		(void) close(fd);
1373*fcf3ce44SJohn Forte 		return (L_FSTAT_ERROR);
1374*fcf3ce44SJohn Forte 	}
1375*fcf3ce44SJohn Forte 
1376*fcf3ce44SJohn Forte 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1377*fcf3ce44SJohn Forte 		(void) close(fd);
1378*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1379*fcf3ce44SJohn Forte 	}
1380*fcf3ce44SJohn Forte 
1381*fcf3ce44SJohn Forte 	/* Get the minor number for an fp instance */
1382*fcf3ce44SJohn Forte 	fcp_data.fp_minor = minor(sbuf.st_rdev);
1383*fcf3ce44SJohn Forte 
1384*fcf3ce44SJohn Forte 	fcp_data.listlen = 1;
1385*fcf3ce44SJohn Forte 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
1386*fcf3ce44SJohn Forte 	fcp_data.list = (caddr_t)&inq_data;
1387*fcf3ce44SJohn Forte 
1388*fcf3ce44SJohn Forte 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1389*fcf3ce44SJohn Forte 		close(fd);
1390*fcf3ce44SJohn Forte 		close(fcp_fd);
1391*fcf3ce44SJohn Forte 		return (err);
1392*fcf3ce44SJohn Forte 	}
1393*fcf3ce44SJohn Forte 	*inq_dtype = inq_data.dev0_type;
1394*fcf3ce44SJohn Forte 
1395*fcf3ce44SJohn Forte 	close(fd);
1396*fcf3ce44SJohn Forte 	close(fcp_fd);
1397*fcf3ce44SJohn Forte 
1398*fcf3ce44SJohn Forte 	return (err);
1399*fcf3ce44SJohn Forte }
1400*fcf3ce44SJohn Forte 
1401*fcf3ce44SJohn Forte /*
1402*fcf3ce44SJohn Forte  * Gets the inq_dtype for devices on the fabric FC driver
1403*fcf3ce44SJohn Forte  * through an ioctl to the FCP module.
1404*fcf3ce44SJohn Forte  *
1405*fcf3ce44SJohn Forte  * This is exactly same as g_get_inq_dtype except that it does not do
1406*fcf3ce44SJohn Forte  * g_dev_login(). That is for the case when the FCA tries to get its own
1407*fcf3ce44SJohn Forte  * inq_dtype and in such a case, it cannot PLOGI into itself.
1408*fcf3ce44SJohn Forte  *
1409*fcf3ce44SJohn Forte  * OUTPUT:
1410*fcf3ce44SJohn Forte  *	inq_dtype is set to the dtype on success
1411*fcf3ce44SJohn Forte  *
1412*fcf3ce44SJohn Forte  * RETURN VALUES:
1413*fcf3ce44SJohn Forte  *	0 on Success
1414*fcf3ce44SJohn Forte  *	Non-zero on error
1415*fcf3ce44SJohn Forte  */
1416*fcf3ce44SJohn Forte static int
1417*fcf3ce44SJohn Forte get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1418*fcf3ce44SJohn Forte {
1419*fcf3ce44SJohn Forte 	int			dev_type, fd;
1420*fcf3ce44SJohn Forte 	int			err, fcp_fd;
1421*fcf3ce44SJohn Forte 	struct fcp_ioctl	fcp_data;
1422*fcf3ce44SJohn Forte 	struct device_data	inq_data;
1423*fcf3ce44SJohn Forte 	struct stat		sbuf;
1424*fcf3ce44SJohn Forte 
1425*fcf3ce44SJohn Forte 	dev_type = g_get_path_type(fcapath);
1426*fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1427*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1428*fcf3ce44SJohn Forte 	}
1429*fcf3ce44SJohn Forte 
1430*fcf3ce44SJohn Forte 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1431*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1432*fcf3ce44SJohn Forte 	}
1433*fcf3ce44SJohn Forte 
1434*fcf3ce44SJohn Forte 	if (fstat(fd, &sbuf) == -1) {
1435*fcf3ce44SJohn Forte 		(void) close(fd);
1436*fcf3ce44SJohn Forte 		return (L_FSTAT_ERROR);
1437*fcf3ce44SJohn Forte 	}
1438*fcf3ce44SJohn Forte 
1439*fcf3ce44SJohn Forte 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1440*fcf3ce44SJohn Forte 		(void) close(fd);
1441*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1442*fcf3ce44SJohn Forte 	}
1443*fcf3ce44SJohn Forte 
1444*fcf3ce44SJohn Forte 	/* Get the minor number for an fp instance */
1445*fcf3ce44SJohn Forte 	fcp_data.fp_minor = minor(sbuf.st_rdev);
1446*fcf3ce44SJohn Forte 
1447*fcf3ce44SJohn Forte 	fcp_data.listlen = 1;
1448*fcf3ce44SJohn Forte 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
1449*fcf3ce44SJohn Forte 	fcp_data.list = (caddr_t)&inq_data;
1450*fcf3ce44SJohn Forte 
1451*fcf3ce44SJohn Forte 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1452*fcf3ce44SJohn Forte 		close(fd);
1453*fcf3ce44SJohn Forte 		close(fcp_fd);
1454*fcf3ce44SJohn Forte 		return (err);
1455*fcf3ce44SJohn Forte 	}
1456*fcf3ce44SJohn Forte 	*inq_dtype = inq_data.dev0_type;
1457*fcf3ce44SJohn Forte 
1458*fcf3ce44SJohn Forte 	close(fd);
1459*fcf3ce44SJohn Forte 	close(fcp_fd);
1460*fcf3ce44SJohn Forte 
1461*fcf3ce44SJohn Forte 	return (0);
1462*fcf3ce44SJohn Forte }
1463*fcf3ce44SJohn Forte 
1464*fcf3ce44SJohn Forte /*
1465*fcf3ce44SJohn Forte  * This function returns the traditional g_get_dev_map. Device list
1466*fcf3ce44SJohn Forte  * and local hba seperate.
1467*fcf3ce44SJohn Forte  */
1468*fcf3ce44SJohn Forte int
1469*fcf3ce44SJohn Forte g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose)
1470*fcf3ce44SJohn Forte {
1471*fcf3ce44SJohn Forte 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD));
1472*fcf3ce44SJohn Forte }
1473*fcf3ce44SJohn Forte 
1474*fcf3ce44SJohn Forte /*
1475*fcf3ce44SJohn Forte  * This function returns the device map with local hba in physical
1476*fcf3ce44SJohn Forte  * order.  Note: Physical order is only returned properly for
1477*fcf3ce44SJohn Forte  * private loop. local hba is also included seperate
1478*fcf3ce44SJohn Forte  */
1479*fcf3ce44SJohn Forte int
1480*fcf3ce44SJohn Forte g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose)
1481*fcf3ce44SJohn Forte {
1482*fcf3ce44SJohn Forte 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP));
1483*fcf3ce44SJohn Forte }
1484*fcf3ce44SJohn Forte 
1485*fcf3ce44SJohn Forte /*
1486*fcf3ce44SJohn Forte  * Gets device map from nexus driver
1487*fcf3ce44SJohn Forte  *
1488*fcf3ce44SJohn Forte  * PARAMS:
1489*fcf3ce44SJohn Forte  *	path -	must be the physical path to a device
1490*fcf3ce44SJohn Forte  *	map  -	loop map returned from fc port.
1491*fcf3ce44SJohn Forte  *	verbose - options.
1492*fcf3ce44SJohn Forte  *
1493*fcf3ce44SJohn Forte  * LOGIC:
1494*fcf3ce44SJohn Forte  *	1. check the validity of path via g_get_path_type.
1495*fcf3ce44SJohn Forte  *	2. If FC path, get the topology of the path via
1496*fcf3ce44SJohn Forte  *		g_get_fca_port_topology.
1497*fcf3ce44SJohn Forte  *
1498*fcf3ce44SJohn Forte  *	3. If FC type(Leadville statck)
1499*fcf3ce44SJohn Forte  *		g_get_dev_list to get the device node list of fc_port_dev_t.
1500*fcf3ce44SJohn Forte  *		g_get_host_params to get the fca port node of fc_port_dev_t.
1501*fcf3ce44SJohn Forte  *
1502*fcf3ce44SJohn Forte  *		Case of fabric or public loop topology
1503*fcf3ce44SJohn Forte  *			Check if the port id > 0xffff.
1504*fcf3ce44SJohn Forte  *			Move device node and fca port node to
1505*fcf3ce44SJohn Forte  *			gfc_map structure via gfc_port_dev_info_t
1506*fcf3ce44SJohn Forte  *			pub_port union.
1507*fcf3ce44SJohn Forte  *			Issue g_get_inq_dtype to get FCP inquiry data
1508*fcf3ce44SJohn Forte  *			and store it into gfc_port_dev_info_t.
1509*fcf3ce44SJohn Forte  *
1510*fcf3ce44SJohn Forte  *		Case of private loop topology
1511*fcf3ce44SJohn Forte  *			Check if the port id < 0xff.
1512*fcf3ce44SJohn Forte  *			Move device node and fca port node to
1513*fcf3ce44SJohn Forte  *			gfc_map structure via gfc_port_dev_info_t
1514*fcf3ce44SJohn Forte  *			priv_port union.
1515*fcf3ce44SJohn Forte  *			Issue g_get_inq_dtype to get FCP inquiry data
1516*fcf3ce44SJohn Forte  *			and store it into gfc_port_dev_info_t.
1517*fcf3ce44SJohn Forte  *
1518*fcf3ce44SJohn Forte  *	   else FC4 type(socal/sf or ifp stack)
1519*fcf3ce44SJohn Forte  *		SFIOCGMAP ioctl to get the device and hba nodes of
1520*fcf3ce44SJohn Forte  *			sf_addr_pair_t.
1521*fcf3ce44SJohn Forte  *
1522*fcf3ce44SJohn Forte  *
1523*fcf3ce44SJohn Forte  * RETURNS:
1524*fcf3ce44SJohn Forte  *	0	: if OK
1525*fcf3ce44SJohn Forte  *	non-zero: otherwise
1526*fcf3ce44SJohn Forte  */
1527*fcf3ce44SJohn Forte int
1528*fcf3ce44SJohn Forte create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type)
1529*fcf3ce44SJohn Forte {
1530*fcf3ce44SJohn Forte int		fd, i, j, num_devices = 0, err, pathcnt = 1;
1531*fcf3ce44SJohn Forte char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
1532*fcf3ce44SJohn Forte char		*char_ptr;
1533*fcf3ce44SJohn Forte struct stat	stbuf;
1534*fcf3ce44SJohn Forte fc_port_dev_t	*dev_list, *dlistptr;
1535*fcf3ce44SJohn Forte uint32_t	hba_port_top = 0;
1536*fcf3ce44SJohn Forte uint_t		dev_type;
1537*fcf3ce44SJohn Forte sf_al_map_t	sf_map;
1538*fcf3ce44SJohn Forte gfc_port_dev_info_t	*dev_ptr;
1539*fcf3ce44SJohn Forte fc_port_dev_t	fp_hba_port;
1540*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
1541*fcf3ce44SJohn Forte int		p_on = 0, p_st = 0;
1542*fcf3ce44SJohn Forte 
1543*fcf3ce44SJohn Forte 	/* return invalid path if path is NULL */
1544*fcf3ce44SJohn Forte 	if (path == NULL) {
1545*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
1546*fcf3ce44SJohn Forte 	}
1547*fcf3ce44SJohn Forte 	/* return invalid arg if map_ptr is NULL */
1548*fcf3ce44SJohn Forte 	if (map_ptr == NULL) {
1549*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
1550*fcf3ce44SJohn Forte 	}
1551*fcf3ce44SJohn Forte 
1552*fcf3ce44SJohn Forte 	map_ptr->dev_addr = NULL;
1553*fcf3ce44SJohn Forte 	map_ptr->count = 0;
1554*fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
1555*fcf3ce44SJohn Forte 	/*
1556*fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
1557*fcf3ce44SJohn Forte 	 *
1558*fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
1559*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1560*fcf3ce44SJohn Forte 	 * or
1561*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1562*fcf3ce44SJohn Forte 	 * or
1563*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1564*fcf3ce44SJohn Forte 	 * or
1565*fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
1566*fcf3ce44SJohn Forte 	 */
1567*fcf3ce44SJohn Forte 	if (strstr(path, SCSI_VHCI)) {
1568*fcf3ce44SJohn Forte 		(void) strcpy(drvr_path0, path);
1569*fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path0, &pathlist)) {
1570*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
1571*fcf3ce44SJohn Forte 		}
1572*fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
1573*fcf3ce44SJohn Forte 		p_on = p_st = 0;
1574*fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
1575*fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
1576*fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
1577*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_ONLINE) {
1578*fcf3ce44SJohn Forte 					p_on = i;
1579*fcf3ce44SJohn Forte 					break;
1580*fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
1581*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_STANDBY) {
1582*fcf3ce44SJohn Forte 					p_st = i;
1583*fcf3ce44SJohn Forte 				}
1584*fcf3ce44SJohn Forte 			}
1585*fcf3ce44SJohn Forte 		}
1586*fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
1587*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
1588*fcf3ce44SJohn Forte 			/* on_line path */
1589*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
1590*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_hba);
1591*fcf3ce44SJohn Forte 		} else {
1592*fcf3ce44SJohn Forte 			/* standby or path0 */
1593*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
1594*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_hba);
1595*fcf3ce44SJohn Forte 		}
1596*fcf3ce44SJohn Forte 		free(pathlist.path_info);
1597*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
1598*fcf3ce44SJohn Forte 	} else {
1599*fcf3ce44SJohn Forte 		(void) strcpy(drvr_path, path);
1600*fcf3ce44SJohn Forte 		if (strstr(drvr_path, DRV_NAME_SSD) ||
1601*fcf3ce44SJohn Forte 			strstr(drvr_path, SES_NAME) ||
1602*fcf3ce44SJohn Forte 			strstr(drvr_path, DRV_NAME_ST)) {
1603*fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
1604*fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
1605*fcf3ce44SJohn Forte 			}
1606*fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate sting  */
1607*fcf3ce44SJohn Forte 			/* append controller */
1608*fcf3ce44SJohn Forte 			(void) strcat(drvr_path, FC_CTLR);
1609*fcf3ce44SJohn Forte 		} else {
1610*fcf3ce44SJohn Forte 			if (stat(drvr_path, &stbuf) < 0) {
1611*fcf3ce44SJohn Forte 				return (L_LSTAT_ERROR);
1612*fcf3ce44SJohn Forte 			}
1613*fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1614*fcf3ce44SJohn Forte 				/* append controller */
1615*fcf3ce44SJohn Forte 				(void) strcat(drvr_path, FC_CTLR);
1616*fcf3ce44SJohn Forte 			}
1617*fcf3ce44SJohn Forte 		}
1618*fcf3ce44SJohn Forte 	}
1619*fcf3ce44SJohn Forte 
1620*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_dev_map: Geting drive map from:"
1621*fcf3ce44SJohn Forte 		" %s\n", drvr_path);
1622*fcf3ce44SJohn Forte 
1623*fcf3ce44SJohn Forte 	dev_type = g_get_path_type(drvr_path);
1624*fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & XPORT_MASK)) {
1625*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1626*fcf3ce44SJohn Forte 	}
1627*fcf3ce44SJohn Forte 
1628*fcf3ce44SJohn Forte 	/* get fiber topology */
1629*fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(drvr_path,
1630*fcf3ce44SJohn Forte 			&hba_port_top, verbose)) != 0) {
1631*fcf3ce44SJohn Forte 		return (err);
1632*fcf3ce44SJohn Forte 	}
1633*fcf3ce44SJohn Forte 
1634*fcf3ce44SJohn Forte 	/* for FC devices. */
1635*fcf3ce44SJohn Forte 	if (dev_type & FC_FCA_MASK) {
1636*fcf3ce44SJohn Forte 		/*
1637*fcf3ce44SJohn Forte 		 * if g_get_dev_list fails with L_NO_DEVICES_FOUND
1638*fcf3ce44SJohn Forte 		 * we still want to call g_get_host_params to try to find the
1639*fcf3ce44SJohn Forte 		 * HBA.  If we do not see any HBAs on the loop, the
1640*fcf3ce44SJohn Forte 		 * g_get_host_params will fail when it trys to issue the target
1641*fcf3ce44SJohn Forte 		 * inquiry ioctl.  In this case, we would still like to return
1642*fcf3ce44SJohn Forte 		 * L_NO_DEVICES_FOUND.
1643*fcf3ce44SJohn Forte 		 *
1644*fcf3ce44SJohn Forte 		 * If g_get_dev_list fails with L_NO_DEVICES_FOUND and
1645*fcf3ce44SJohn Forte 		 * g_get_host_params fails, the function returns
1646*fcf3ce44SJohn Forte 		 * L_NO_DEVICES_FOUND
1647*fcf3ce44SJohn Forte 		 */
1648*fcf3ce44SJohn Forte 		if ((err = g_get_dev_list(drvr_path, &dev_list,
1649*fcf3ce44SJohn Forte 				&num_devices)) != 0) {
1650*fcf3ce44SJohn Forte 			/*
1651*fcf3ce44SJohn Forte 			 * g_get_dev_map doesn't allow ulp failure
1652*fcf3ce44SJohn Forte 			 * to continue thus we need to free dev_list
1653*fcf3ce44SJohn Forte 			 * here.
1654*fcf3ce44SJohn Forte 			 */
1655*fcf3ce44SJohn Forte 			if (err == L_GET_DEV_LIST_ULP_FAILURE) {
1656*fcf3ce44SJohn Forte 				(void) free(dev_list);
1657*fcf3ce44SJohn Forte 			}
1658*fcf3ce44SJohn Forte 			if (err != L_NO_DEVICES_FOUND) {
1659*fcf3ce44SJohn Forte 				return (err);
1660*fcf3ce44SJohn Forte 			}
1661*fcf3ce44SJohn Forte 		}
1662*fcf3ce44SJohn Forte 
1663*fcf3ce44SJohn Forte 		/* Get local HBA information */
1664*fcf3ce44SJohn Forte 		if ((err = g_get_host_params(drvr_path, &fp_hba_port,
1665*fcf3ce44SJohn Forte 				verbose)) != 0) {
1666*fcf3ce44SJohn Forte 			(void) free(dev_list);
1667*fcf3ce44SJohn Forte 			if (num_devices == 0)
1668*fcf3ce44SJohn Forte 				return (L_NO_DEVICES_FOUND);
1669*fcf3ce44SJohn Forte 			else
1670*fcf3ce44SJohn Forte 				return (err);
1671*fcf3ce44SJohn Forte 		}
1672*fcf3ce44SJohn Forte 
1673*fcf3ce44SJohn Forte 		/* If devices, other than local HBA are found	*/
1674*fcf3ce44SJohn Forte 		/* allocate space for them in the gfc_map.	*/
1675*fcf3ce44SJohn Forte 		if (num_devices > 0) {
1676*fcf3ce44SJohn Forte 
1677*fcf3ce44SJohn Forte 			/* If map type is on MAP_FORMAT_LILP we need	*/
1678*fcf3ce44SJohn Forte 			/* to add space for the local HBA		*/
1679*fcf3ce44SJohn Forte 			if (map_type == MAP_FORMAT_LILP) {
1680*fcf3ce44SJohn Forte 				map_ptr->count = ++num_devices;
1681*fcf3ce44SJohn Forte 			} else {
1682*fcf3ce44SJohn Forte 				map_ptr->count = num_devices;
1683*fcf3ce44SJohn Forte 			}
1684*fcf3ce44SJohn Forte 
1685*fcf3ce44SJohn Forte 			if ((map_ptr->dev_addr = (gfc_port_dev_info_t *)
1686*fcf3ce44SJohn Forte 			    calloc(map_ptr->count,
1687*fcf3ce44SJohn Forte 				sizeof (gfc_port_dev_info_t))) == NULL) {
1688*fcf3ce44SJohn Forte 			    (void) free(dev_list);
1689*fcf3ce44SJohn Forte 			    return (L_MALLOC_FAILED);
1690*fcf3ce44SJohn Forte 			}
1691*fcf3ce44SJohn Forte 		}
1692*fcf3ce44SJohn Forte 
1693*fcf3ce44SJohn Forte 		/* If we want the lilp map then we need to do a little	*/
1694*fcf3ce44SJohn Forte 		/* work here.  The lilp map contains the local hba in	*/
1695*fcf3ce44SJohn Forte 		/* the dev_addr.  Once this has been added qsort the	*/
1696*fcf3ce44SJohn Forte 		/* dev_addr array so it's in physical order.		*/
1697*fcf3ce44SJohn Forte 		/* The lilp map will contain the local hba in the	*/
1698*fcf3ce44SJohn Forte 		/* dev_addr array only when num_devices > 0		*/
1699*fcf3ce44SJohn Forte 		if (map_type == MAP_FORMAT_LILP && num_devices > 0) {
1700*fcf3ce44SJohn Forte 
1701*fcf3ce44SJohn Forte 			/* First we need to allocate one additional	*/
1702*fcf3ce44SJohn Forte 			/* device to the dev_addr structure, for the 	*/
1703*fcf3ce44SJohn Forte 			/* local hba					*/
1704*fcf3ce44SJohn Forte 			if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
1705*fcf3ce44SJohn Forte 				(num_devices * sizeof (fc_port_dev_t))))
1706*fcf3ce44SJohn Forte 				== NULL) {
1707*fcf3ce44SJohn Forte 				S_FREE(dev_list);
1708*fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1709*fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1710*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
1711*fcf3ce44SJohn Forte 			}
1712*fcf3ce44SJohn Forte 
1713*fcf3ce44SJohn Forte 			/* Next, copy the local hba into this new loc.	*/
1714*fcf3ce44SJohn Forte 			if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
1715*fcf3ce44SJohn Forte 					sizeof (fc_port_dev_t)) == NULL) {
1716*fcf3ce44SJohn Forte 				(void) free(dev_list);
1717*fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1718*fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1719*fcf3ce44SJohn Forte 				return (L_MEMCPY_FAILED);
1720*fcf3ce44SJohn Forte 			}
1721*fcf3ce44SJohn Forte 
1722*fcf3ce44SJohn Forte 			/* Now sort by physical location		*/
1723*fcf3ce44SJohn Forte 			qsort((void*)dev_list, num_devices,
1724*fcf3ce44SJohn Forte 				sizeof (fc_port_dev_t), lilp_map_cmp);
1725*fcf3ce44SJohn Forte 		}
1726*fcf3ce44SJohn Forte 
1727*fcf3ce44SJohn Forte 		dlistptr = dev_list;
1728*fcf3ce44SJohn Forte 		dev_ptr = map_ptr->dev_addr;
1729*fcf3ce44SJohn Forte 
1730*fcf3ce44SJohn Forte 		switch (hba_port_top) {
1731*fcf3ce44SJohn Forte 		case FC_TOP_FABRIC:
1732*fcf3ce44SJohn Forte 		case FC_TOP_PUBLIC_LOOP:
1733*fcf3ce44SJohn Forte 			if (fp_hba_port.dev_did.port_id <= 0xffff) {
1734*fcf3ce44SJohn Forte 				(void) free(dlistptr);
1735*fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1736*fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1737*fcf3ce44SJohn Forte 				return (L_INVALID_FABRIC_ADDRESS);
1738*fcf3ce44SJohn Forte 			} else {
1739*fcf3ce44SJohn Forte 				map_ptr->hba_addr.port_topology = hba_port_top;
1740*fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.pub_port =
1741*fcf3ce44SJohn Forte 					fp_hba_port;
1742*fcf3ce44SJohn Forte 			}
1743*fcf3ce44SJohn Forte 			for (i = 0; i < num_devices; i++, dev_ptr++,
1744*fcf3ce44SJohn Forte 					dev_list++) {
1745*fcf3ce44SJohn Forte 				if (dev_list->dev_did.port_id <= 0xffff) {
1746*fcf3ce44SJohn Forte 					(void) free(dlistptr);
1747*fcf3ce44SJohn Forte 					(void) free(map_ptr->dev_addr);
1748*fcf3ce44SJohn Forte 					map_ptr->dev_addr = NULL;
1749*fcf3ce44SJohn Forte 					return (L_INVALID_FABRIC_ADDRESS);
1750*fcf3ce44SJohn Forte 				} else {
1751*fcf3ce44SJohn Forte 					dev_ptr->port_topology = hba_port_top;
1752*fcf3ce44SJohn Forte 					dev_ptr->gfc_port_dev.pub_port =
1753*fcf3ce44SJohn Forte 						*dev_list;
1754*fcf3ce44SJohn Forte 				}
1755*fcf3ce44SJohn Forte 			}
1756*fcf3ce44SJohn Forte 			break;
1757*fcf3ce44SJohn Forte 		case FC_TOP_PRIVATE_LOOP:
1758*fcf3ce44SJohn Forte 			/*
1759*fcf3ce44SJohn Forte 			 * Map the (new->old) structures here.
1760*fcf3ce44SJohn Forte 			 * Checking (i < SF_NUM_ENTRIES_IN_MAP) just to
1761*fcf3ce44SJohn Forte 			 * make sure that we don't overrun the map structure
1762*fcf3ce44SJohn Forte 			 * since it can hold data for upto 126 devices.
1763*fcf3ce44SJohn Forte 			 */
1764*fcf3ce44SJohn Forte 			if (fp_hba_port.dev_did.port_id > 0xff) {
1765*fcf3ce44SJohn Forte 				(void) free(dlistptr);
1766*fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1767*fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1768*fcf3ce44SJohn Forte 				return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1769*fcf3ce44SJohn Forte 			} else {
1770*fcf3ce44SJohn Forte 				map_ptr->hba_addr.port_topology = hba_port_top;
1771*fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.
1772*fcf3ce44SJohn Forte 					priv_port.sf_al_pa =
1773*fcf3ce44SJohn Forte 					(uchar_t)fp_hba_port.dev_did.port_id;
1774*fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.
1775*fcf3ce44SJohn Forte 					priv_port.sf_hard_address = (uchar_t)
1776*fcf3ce44SJohn Forte 					fp_hba_port.dev_hard_addr.hard_addr;
1777*fcf3ce44SJohn Forte 				for (j = 0; j < FC_WWN_SIZE; j++) {
1778*fcf3ce44SJohn Forte 					map_ptr->hba_addr.gfc_port_dev.
1779*fcf3ce44SJohn Forte 						priv_port.sf_node_wwn[j] =
1780*fcf3ce44SJohn Forte 					fp_hba_port.dev_nwwn.raw_wwn[j];
1781*fcf3ce44SJohn Forte 					map_ptr->hba_addr.gfc_port_dev.
1782*fcf3ce44SJohn Forte 						priv_port.sf_port_wwn[j] =
1783*fcf3ce44SJohn Forte 					fp_hba_port.dev_pwwn.raw_wwn[j];
1784*fcf3ce44SJohn Forte 				}
1785*fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.
1786*fcf3ce44SJohn Forte 					priv_port.sf_inq_dtype =
1787*fcf3ce44SJohn Forte 					fp_hba_port.dev_dtype;
1788*fcf3ce44SJohn Forte 			}
1789*fcf3ce44SJohn Forte 
1790*fcf3ce44SJohn Forte 			for (i = 0; (i < num_devices &&
1791*fcf3ce44SJohn Forte 					i < SF_NUM_ENTRIES_IN_MAP);
1792*fcf3ce44SJohn Forte 					i++, dev_ptr++, dev_list++) {
1793*fcf3ce44SJohn Forte 				/*
1794*fcf3ce44SJohn Forte 				 * Out of 24 bits of port_id, copy only
1795*fcf3ce44SJohn Forte 				 * 8 bits to al_pa. This works okay for
1796*fcf3ce44SJohn Forte 				 * devices that're on a private loop.
1797*fcf3ce44SJohn Forte 				 */
1798*fcf3ce44SJohn Forte 				if (dev_list->dev_did.port_id > 0xff) {
1799*fcf3ce44SJohn Forte 					(void) free(dlistptr);
1800*fcf3ce44SJohn Forte 					(void) free(map_ptr->dev_addr);
1801*fcf3ce44SJohn Forte 					map_ptr->dev_addr = NULL;
1802*fcf3ce44SJohn Forte 					return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1803*fcf3ce44SJohn Forte 				}
1804*fcf3ce44SJohn Forte 				dev_ptr->port_topology = hba_port_top;
1805*fcf3ce44SJohn Forte 				dev_ptr->gfc_port_dev.priv_port.sf_al_pa
1806*fcf3ce44SJohn Forte 					= (uchar_t)dev_list->dev_did.port_id;
1807*fcf3ce44SJohn Forte 				dev_ptr->gfc_port_dev.priv_port.sf_hard_address
1808*fcf3ce44SJohn Forte 					= (uchar_t)dev_list->dev_hard_addr.
1809*fcf3ce44SJohn Forte 						hard_addr;
1810*fcf3ce44SJohn Forte 				for (j = 0; j < FC_WWN_SIZE; j++) {
1811*fcf3ce44SJohn Forte 					dev_ptr->
1812*fcf3ce44SJohn Forte 					gfc_port_dev.priv_port.sf_node_wwn[j] =
1813*fcf3ce44SJohn Forte 						dev_list->dev_nwwn.raw_wwn[j];
1814*fcf3ce44SJohn Forte 					dev_ptr->
1815*fcf3ce44SJohn Forte 					gfc_port_dev.priv_port.sf_port_wwn[j] =
1816*fcf3ce44SJohn Forte 						dev_list->dev_pwwn.raw_wwn[j];
1817*fcf3ce44SJohn Forte 				}
1818*fcf3ce44SJohn Forte 				dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype =
1819*fcf3ce44SJohn Forte 					dev_list->dev_dtype;
1820*fcf3ce44SJohn Forte 			}
1821*fcf3ce44SJohn Forte 			break;
1822*fcf3ce44SJohn Forte 		case FC_TOP_PT_PT:
1823*fcf3ce44SJohn Forte 			(void) free(dlistptr);
1824*fcf3ce44SJohn Forte 			(void) free(map_ptr->dev_addr);
1825*fcf3ce44SJohn Forte 			map_ptr->dev_addr = NULL;
1826*fcf3ce44SJohn Forte 			return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
1827*fcf3ce44SJohn Forte 		default:
1828*fcf3ce44SJohn Forte 			(void) free(dlistptr);
1829*fcf3ce44SJohn Forte 			(void) free(map_ptr->dev_addr);
1830*fcf3ce44SJohn Forte 			map_ptr->dev_addr = NULL;
1831*fcf3ce44SJohn Forte 			return (L_UNEXPECTED_FC_TOPOLOGY);
1832*fcf3ce44SJohn Forte 		}	/* End of switch on port_topology */
1833*fcf3ce44SJohn Forte 		(void) free(dlistptr);
1834*fcf3ce44SJohn Forte 
1835*fcf3ce44SJohn Forte 	} else {	/* sf and fc4/pci devices */
1836*fcf3ce44SJohn Forte 		if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
1837*fcf3ce44SJohn Forte 			return (errno);
1838*fcf3ce44SJohn Forte 		/* initialize map */
1839*fcf3ce44SJohn Forte 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
1840*fcf3ce44SJohn Forte 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
1841*fcf3ce44SJohn Forte 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
1842*fcf3ce44SJohn Forte 			(void) close(fd);
1843*fcf3ce44SJohn Forte 			return (L_SFIOCGMAP_IOCTL_FAIL);
1844*fcf3ce44SJohn Forte 		}
1845*fcf3ce44SJohn Forte 		/* Check for reasonableness. */
1846*fcf3ce44SJohn Forte 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
1847*fcf3ce44SJohn Forte 			(void) close(fd);
1848*fcf3ce44SJohn Forte 			return (L_INVALID_LOOP_MAP);
1849*fcf3ce44SJohn Forte 		}
1850*fcf3ce44SJohn Forte 		if (sf_map.sf_count == 0) {
1851*fcf3ce44SJohn Forte 			(void) close(fd);
1852*fcf3ce44SJohn Forte 			return (L_NO_DEVICES_FOUND);
1853*fcf3ce44SJohn Forte 		}
1854*fcf3ce44SJohn Forte 
1855*fcf3ce44SJohn Forte 		map_ptr->count = sf_map.sf_count;
1856*fcf3ce44SJohn Forte 		if ((map_ptr->dev_addr =
1857*fcf3ce44SJohn Forte 			(gfc_port_dev_info_t *)calloc(map_ptr->count,
1858*fcf3ce44SJohn Forte 			sizeof (gfc_port_dev_info_t))) == NULL) {
1859*fcf3ce44SJohn Forte 			(void) close(fd);
1860*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
1861*fcf3ce44SJohn Forte 		}
1862*fcf3ce44SJohn Forte 		dev_ptr = map_ptr->dev_addr;
1863*fcf3ce44SJohn Forte 		for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) {
1864*fcf3ce44SJohn Forte 			if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) {
1865*fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1866*fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1867*fcf3ce44SJohn Forte 				(void) close(fd);
1868*fcf3ce44SJohn Forte 				return (L_INVALID_LOOP_MAP);
1869*fcf3ce44SJohn Forte 			}
1870*fcf3ce44SJohn Forte 			dev_ptr->port_topology = hba_port_top;
1871*fcf3ce44SJohn Forte 			dev_ptr->gfc_port_dev.priv_port =
1872*fcf3ce44SJohn Forte 				sf_map.sf_addr_pair[i];
1873*fcf3ce44SJohn Forte 		}
1874*fcf3ce44SJohn Forte 		map_ptr->hba_addr.port_topology = hba_port_top;
1875*fcf3ce44SJohn Forte 		map_ptr->hba_addr.gfc_port_dev.priv_port =
1876*fcf3ce44SJohn Forte 				sf_map.sf_hba_addr;
1877*fcf3ce44SJohn Forte 		(void) close(fd);
1878*fcf3ce44SJohn Forte 	}
1879*fcf3ce44SJohn Forte 
1880*fcf3ce44SJohn Forte 	return (0);
1881*fcf3ce44SJohn Forte }
1882*fcf3ce44SJohn Forte 
1883*fcf3ce44SJohn Forte /*
1884*fcf3ce44SJohn Forte  * This function consturct FC proerty list using map_dev_fc_prop_list.
1885*fcf3ce44SJohn Forte  *
1886*fcf3ce44SJohn Forte  * port WWN, node WWN, port addr and hard addr properties is constructed.
1887*fcf3ce44SJohn Forte  *
1888*fcf3ce44SJohn Forte  * return 0 if OK.
1889*fcf3ce44SJohn Forte  * otherwise returns error code.
1890*fcf3ce44SJohn Forte  */
1891*fcf3ce44SJohn Forte static int
1892*fcf3ce44SJohn Forte update_map_dev_fc_prop(
1893*fcf3ce44SJohn Forte 	impl_map_dev_prop_t **prop_list, uint32_t map_topo,
1894*fcf3ce44SJohn Forte 	uchar_t *port_wwn, uchar_t *node_wwn, int port_addr,
1895*fcf3ce44SJohn Forte 	int hard_addr)
1896*fcf3ce44SJohn Forte {
1897*fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*prop_ptr, *pl_start = NULL, *pl_end = NULL;
1898*fcf3ce44SJohn Forte 	uchar_t *port_wwn_data, *node_wwn_data;
1899*fcf3ce44SJohn Forte 	int *port_addr_data, *hard_addr_data;
1900*fcf3ce44SJohn Forte 
1901*fcf3ce44SJohn Forte 	/* consrtruct port addr property. */
1902*fcf3ce44SJohn Forte 	if ((map_topo == FC_TOP_FABRIC) ||
1903*fcf3ce44SJohn Forte 		(map_topo == FC_TOP_PUBLIC_LOOP)) {
1904*fcf3ce44SJohn Forte 		if (port_addr <= 0xffff) {
1905*fcf3ce44SJohn Forte 		    return (L_INVALID_FABRIC_ADDRESS);
1906*fcf3ce44SJohn Forte 		}
1907*fcf3ce44SJohn Forte 	} else if (map_topo == FC_TOP_PRIVATE_LOOP) {
1908*fcf3ce44SJohn Forte 		if (port_addr > 0xff) {
1909*fcf3ce44SJohn Forte 		    return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1910*fcf3ce44SJohn Forte 		}
1911*fcf3ce44SJohn Forte 	}
1912*fcf3ce44SJohn Forte 
1913*fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1914*fcf3ce44SJohn Forte 		1, sizeof (impl_map_dev_prop_t))) == NULL) {
1915*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1916*fcf3ce44SJohn Forte 	}
1917*fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP,
1918*fcf3ce44SJohn Forte 			strlen(PORT_ADDR_PROP));
1919*fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1920*fcf3ce44SJohn Forte 
1921*fcf3ce44SJohn Forte 	if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1922*fcf3ce44SJohn Forte 		free(prop_ptr);
1923*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1924*fcf3ce44SJohn Forte 	}
1925*fcf3ce44SJohn Forte 	*port_addr_data = port_addr;
1926*fcf3ce44SJohn Forte 	prop_ptr->prop_data = port_addr_data;
1927*fcf3ce44SJohn Forte 
1928*fcf3ce44SJohn Forte 	pl_start = pl_end = prop_ptr;
1929*fcf3ce44SJohn Forte 
1930*fcf3ce44SJohn Forte 	/* consrtruct port WWN property. */
1931*fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1932*fcf3ce44SJohn Forte 		1, sizeof (impl_map_dev_prop_t))) == NULL) {
1933*fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1934*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1935*fcf3ce44SJohn Forte 	}
1936*fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP,
1937*fcf3ce44SJohn Forte 			strlen(PORT_WWN_PROP));
1938*fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1939*fcf3ce44SJohn Forte 
1940*fcf3ce44SJohn Forte 	if ((port_wwn_data = (uchar_t *)calloc(
1941*fcf3ce44SJohn Forte 		1, FC_WWN_SIZE)) == NULL) {
1942*fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1943*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1944*fcf3ce44SJohn Forte 	}
1945*fcf3ce44SJohn Forte 	memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE);
1946*fcf3ce44SJohn Forte 	prop_ptr->prop_data = port_wwn_data;
1947*fcf3ce44SJohn Forte 	prop_ptr->prop_size = FC_WWN_SIZE;
1948*fcf3ce44SJohn Forte 	pl_end->next = prop_ptr;
1949*fcf3ce44SJohn Forte 	pl_end = prop_ptr;
1950*fcf3ce44SJohn Forte 
1951*fcf3ce44SJohn Forte 	/* consrtruct node WWN property. */
1952*fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1953*fcf3ce44SJohn Forte 		1, sizeof (impl_map_dev_prop_t))) == NULL) {
1954*fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1955*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1956*fcf3ce44SJohn Forte 	}
1957*fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP,
1958*fcf3ce44SJohn Forte 			strlen(NODE_WWN_PROP));
1959*fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1960*fcf3ce44SJohn Forte 
1961*fcf3ce44SJohn Forte 	if ((node_wwn_data = (uchar_t *)calloc(
1962*fcf3ce44SJohn Forte 		1, FC_WWN_SIZE)) == NULL) {
1963*fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1964*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1965*fcf3ce44SJohn Forte 	}
1966*fcf3ce44SJohn Forte 	memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE);
1967*fcf3ce44SJohn Forte 	prop_ptr->prop_data = node_wwn_data;
1968*fcf3ce44SJohn Forte 	prop_ptr->prop_size = FC_WWN_SIZE;
1969*fcf3ce44SJohn Forte 	pl_end->next = prop_ptr;
1970*fcf3ce44SJohn Forte 	pl_end = prop_ptr;
1971*fcf3ce44SJohn Forte 
1972*fcf3ce44SJohn Forte 	/* consrtruct hard addr property. */
1973*fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1974*fcf3ce44SJohn Forte 		1, sizeof (impl_map_dev_prop_t))) == NULL) {
1975*fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1976*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1977*fcf3ce44SJohn Forte 	}
1978*fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP,
1979*fcf3ce44SJohn Forte 			strlen(HARD_ADDR_PROP));
1980*fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1981*fcf3ce44SJohn Forte 
1982*fcf3ce44SJohn Forte 	if ((hard_addr_data = (int *)calloc(
1983*fcf3ce44SJohn Forte 		1, sizeof (int))) == NULL) {
1984*fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1985*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1986*fcf3ce44SJohn Forte 	}
1987*fcf3ce44SJohn Forte 	*hard_addr_data = hard_addr;
1988*fcf3ce44SJohn Forte 	prop_ptr->prop_data = hard_addr_data;
1989*fcf3ce44SJohn Forte 	pl_end->next = prop_ptr;
1990*fcf3ce44SJohn Forte 	pl_end = prop_ptr;
1991*fcf3ce44SJohn Forte 
1992*fcf3ce44SJohn Forte 	if (*prop_list == NULL) {
1993*fcf3ce44SJohn Forte 		*prop_list = pl_start;
1994*fcf3ce44SJohn Forte 	} else {
1995*fcf3ce44SJohn Forte 		pl_end->next = (*prop_list)->next;
1996*fcf3ce44SJohn Forte 		*prop_list = pl_start;
1997*fcf3ce44SJohn Forte 	}
1998*fcf3ce44SJohn Forte 
1999*fcf3ce44SJohn Forte 	return (0);
2000*fcf3ce44SJohn Forte }
2001*fcf3ce44SJohn Forte 
2002*fcf3ce44SJohn Forte /*
2003*fcf3ce44SJohn Forte  * This function consturct FCP inq dtype propery.
2004*fcf3ce44SJohn Forte  * if inq_dtype is null the property is constrcted with err info.
2005*fcf3ce44SJohn Forte  *
2006*fcf3ce44SJohn Forte  * L_MALLOC_FAILED is the only possible error.
2007*fcf3ce44SJohn Forte  */
2008*fcf3ce44SJohn Forte static int
2009*fcf3ce44SJohn Forte update_map_dev_FCP_prop(
2010*fcf3ce44SJohn Forte 	impl_map_dev_prop_t **prop_list,
2011*fcf3ce44SJohn Forte 	uchar_t *inq_dtype, int err, int exist)
2012*fcf3ce44SJohn Forte {
2013*fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*prop_ptr, *old_prop_ptr;
2014*fcf3ce44SJohn Forte 	uchar_t *inq_dtype_data;
2015*fcf3ce44SJohn Forte 
2016*fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
2017*fcf3ce44SJohn Forte 		1, sizeof (impl_map_dev_prop_t))) == NULL) {
2018*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
2019*fcf3ce44SJohn Forte 	}
2020*fcf3ce44SJohn Forte 
2021*fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP,
2022*fcf3ce44SJohn Forte 		strlen(INQ_DTYPE_PROP));
2023*fcf3ce44SJohn Forte 
2024*fcf3ce44SJohn Forte 	if (inq_dtype == NULL) {
2025*fcf3ce44SJohn Forte 		prop_ptr->prop_data = NULL;
2026*fcf3ce44SJohn Forte 		prop_ptr->prop_error = err;
2027*fcf3ce44SJohn Forte 	} else {
2028*fcf3ce44SJohn Forte 		if ((inq_dtype_data = (uchar_t *)calloc(
2029*fcf3ce44SJohn Forte 			1, sizeof (uchar_t))) == NULL) {
2030*fcf3ce44SJohn Forte 			free(prop_ptr);
2031*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
2032*fcf3ce44SJohn Forte 		}
2033*fcf3ce44SJohn Forte 		memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t));
2034*fcf3ce44SJohn Forte 		prop_ptr->prop_data = inq_dtype_data;
2035*fcf3ce44SJohn Forte 		prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
2036*fcf3ce44SJohn Forte 		prop_ptr->prop_size = sizeof (uchar_t);
2037*fcf3ce44SJohn Forte 	}
2038*fcf3ce44SJohn Forte 
2039*fcf3ce44SJohn Forte 	if (*prop_list == NULL) {
2040*fcf3ce44SJohn Forte 		*prop_list = prop_ptr;
2041*fcf3ce44SJohn Forte 	} else {
2042*fcf3ce44SJohn Forte 		if (exist == PROP_EXIST) {
2043*fcf3ce44SJohn Forte 			prop_ptr->next = (*prop_list)->next;
2044*fcf3ce44SJohn Forte 			old_prop_ptr = *prop_list;
2045*fcf3ce44SJohn Forte 			*prop_list = prop_ptr;
2046*fcf3ce44SJohn Forte 			free((uchar_t *)(old_prop_ptr->prop_data));
2047*fcf3ce44SJohn Forte 			old_prop_ptr->prop_data = NULL;
2048*fcf3ce44SJohn Forte 			S_FREE(old_prop_ptr);
2049*fcf3ce44SJohn Forte 		} else {
2050*fcf3ce44SJohn Forte 			prop_ptr->next = *prop_list;
2051*fcf3ce44SJohn Forte 			*prop_list = prop_ptr;
2052*fcf3ce44SJohn Forte 		}
2053*fcf3ce44SJohn Forte 	}
2054*fcf3ce44SJohn Forte 
2055*fcf3ce44SJohn Forte 	return (0);
2056*fcf3ce44SJohn Forte }
2057*fcf3ce44SJohn Forte 
2058*fcf3ce44SJohn Forte /*
2059*fcf3ce44SJohn Forte  * This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl()
2060*fcf3ce44SJohn Forte  * to get the inq_dtype of input device and calls update_map_dev_FCP_prop().
2061*fcf3ce44SJohn Forte  * inq_dtype is set to NULL and pass error code if inq_dtype data is not
2062*fcf3ce44SJohn Forte  * requried.
2063*fcf3ce44SJohn Forte  *
2064*fcf3ce44SJohn Forte  * return error from update_map_dev_FCP_prop().
2065*fcf3ce44SJohn Forte  */
2066*fcf3ce44SJohn Forte static int
2067*fcf3ce44SJohn Forte handle_map_dev_FCP_prop(
2068*fcf3ce44SJohn Forte 	minor_t fp_xport_minor,
2069*fcf3ce44SJohn Forte 	la_wwn_t port_wwn,
2070*fcf3ce44SJohn Forte 	impl_map_dev_prop_t **prop_list)
2071*fcf3ce44SJohn Forte {
2072*fcf3ce44SJohn Forte 	struct device_data	inq_data;
2073*fcf3ce44SJohn Forte 	int 			fcp_fd, err;
2074*fcf3ce44SJohn Forte 	struct fcp_ioctl	fcp_data;
2075*fcf3ce44SJohn Forte 	uchar_t			inq_dtype;
2076*fcf3ce44SJohn Forte 
2077*fcf3ce44SJohn Forte 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
2078*fcf3ce44SJohn Forte 		update_map_dev_FCP_prop(prop_list, NULL,
2079*fcf3ce44SJohn Forte 			L_OPEN_PATH_FAIL, PROP_NOEXIST);
2080*fcf3ce44SJohn Forte 	}
2081*fcf3ce44SJohn Forte 
2082*fcf3ce44SJohn Forte 	/* Get the minor number for an fp instance */
2083*fcf3ce44SJohn Forte 	fcp_data.fp_minor = fp_xport_minor;
2084*fcf3ce44SJohn Forte 
2085*fcf3ce44SJohn Forte 	/* Get FCP prop for the hba first. */
2086*fcf3ce44SJohn Forte 	fcp_data.listlen = 1;
2087*fcf3ce44SJohn Forte 	inq_data.dev_pwwn = port_wwn;
2088*fcf3ce44SJohn Forte 	fcp_data.list = (caddr_t)&inq_data;
2089*fcf3ce44SJohn Forte 
2090*fcf3ce44SJohn Forte 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
2091*fcf3ce44SJohn Forte 		/* if ioctl error then set the prop_error.	*/
2092*fcf3ce44SJohn Forte 	    if ((err = update_map_dev_FCP_prop(
2093*fcf3ce44SJohn Forte 		prop_list, NULL, err, PROP_NOEXIST)) != 0) {
2094*fcf3ce44SJohn Forte 		return (err);
2095*fcf3ce44SJohn Forte 	    }
2096*fcf3ce44SJohn Forte 	} else {
2097*fcf3ce44SJohn Forte 	    inq_dtype = inq_data.dev0_type;
2098*fcf3ce44SJohn Forte 	    if ((err = update_map_dev_FCP_prop(
2099*fcf3ce44SJohn Forte 		prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) {
2100*fcf3ce44SJohn Forte 		return (err);
2101*fcf3ce44SJohn Forte 	    }
2102*fcf3ce44SJohn Forte 	}
2103*fcf3ce44SJohn Forte 
2104*fcf3ce44SJohn Forte 	return (0);
2105*fcf3ce44SJohn Forte }
2106*fcf3ce44SJohn Forte 
2107*fcf3ce44SJohn Forte /*
2108*fcf3ce44SJohn Forte  * Construct device map tree from nexus driver
2109*fcf3ce44SJohn Forte  *
2110*fcf3ce44SJohn Forte  * PARAMS:
2111*fcf3ce44SJohn Forte  *	path -	must be the physical path to a device
2112*fcf3ce44SJohn Forte  *	l_err  - ptr to an error code.  Set when NULL is returned.
2113*fcf3ce44SJohn Forte  *	flag -  device map fomat and property type.
2114*fcf3ce44SJohn Forte  *
2115*fcf3ce44SJohn Forte  * LOGIC:
2116*fcf3ce44SJohn Forte  *	1. check the validity of path via g_get_path_type.
2117*fcf3ce44SJohn Forte  *	2. If FC path, get the topology of the path via
2118*fcf3ce44SJohn Forte  *		g_get_fca_port_topology.
2119*fcf3ce44SJohn Forte  *
2120*fcf3ce44SJohn Forte  *	3. If FC type(Leadville statck)
2121*fcf3ce44SJohn Forte  *		FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t.
2122*fcf3ce44SJohn Forte  *		FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t.
2123*fcf3ce44SJohn Forte  *
2124*fcf3ce44SJohn Forte  *		root of tree is set with host_params info
2125*fcf3ce44SJohn Forte  *			FC propery is set.
2126*fcf3ce44SJohn Forte  *			FCP property is set if reqyested through flag.
2127*fcf3ce44SJohn Forte  *				Issue g_issue_fcp_ioctl to get FCP inquiry data
2128*fcf3ce44SJohn Forte  *		consruruct list of children via dev_list.
2129*fcf3ce44SJohn Forte  *			FC property is set.
2130*fcf3ce44SJohn Forte  *			FCP property is set if reqyested through flag.
2131*fcf3ce44SJohn Forte  *				Issue FCIO_DEV_LOGIN if it is fabric device.
2132*fcf3ce44SJohn Forte  *				Issue g_issue_fcp_ioctl to get FCP inquiry data.
2133*fcf3ce44SJohn Forte  *
2134*fcf3ce44SJohn Forte  *	   else FC4 type(socal/sf or ifp stack)
2135*fcf3ce44SJohn Forte  *		SFIOCGMAP ioctl to get the device and hba nodes of
2136*fcf3ce44SJohn Forte  *			sf_addr_pair_t.
2137*fcf3ce44SJohn Forte  *		FCIO_GETMAP ioctl to get hba port info.
2138*fcf3ce44SJohn Forte  *		consturct map and child tree list and
2139*fcf3ce44SJohn Forte  *		set the properties as private loop devices.
2140*fcf3ce44SJohn Forte  *
2141*fcf3ce44SJohn Forte  * RETURNS:
2142*fcf3ce44SJohn Forte  *	ptr to map is returned if OK.
2143*fcf3ce44SJohn Forte  *	NULL and l_err is set otherwise.
2144*fcf3ce44SJohn Forte  */
2145*fcf3ce44SJohn Forte gfc_dev_t
2146*fcf3ce44SJohn Forte g_dev_map_init(char *path, int *l_err, int flag)
2147*fcf3ce44SJohn Forte {
2148*fcf3ce44SJohn Forte int		fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0;
2149*fcf3ce44SJohn Forte char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
2150*fcf3ce44SJohn Forte char		*char_ptr, *nexus_path;
2151*fcf3ce44SJohn Forte struct stat	stbuf;
2152*fcf3ce44SJohn Forte fc_port_dev_t	*dev_list = NULL, *dlist;
2153*fcf3ce44SJohn Forte uint32_t	hba_port_top, state;
2154*fcf3ce44SJohn Forte uint_t		path_type;
2155*fcf3ce44SJohn Forte sf_al_map_t	sf_map;
2156*fcf3ce44SJohn Forte fc_port_dev_t	fp_hba_port;
2157*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
2158*fcf3ce44SJohn Forte int		p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd;
2159*fcf3ce44SJohn Forte fcio_t		fcio;
2160*fcf3ce44SJohn Forte struct lilpmap	limited_map;
2161*fcf3ce44SJohn Forte impl_map_dev_t	*impl_map, *impl_dev, *mdl_start = NULL, *mdl_end = NULL;
2162*fcf3ce44SJohn Forte struct stat	sbuf;
2163*fcf3ce44SJohn Forte 
2164*fcf3ce44SJohn Forte 	if (l_err == NULL) {
2165*fcf3ce44SJohn Forte 		return (NULL);
2166*fcf3ce44SJohn Forte 	}
2167*fcf3ce44SJohn Forte 
2168*fcf3ce44SJohn Forte 	if (path == NULL) {
2169*fcf3ce44SJohn Forte 		*l_err = L_INVALID_PATH;
2170*fcf3ce44SJohn Forte 		return (NULL);
2171*fcf3ce44SJohn Forte 	}
2172*fcf3ce44SJohn Forte 
2173*fcf3ce44SJohn Forte 	*l_err = 0;
2174*fcf3ce44SJohn Forte 
2175*fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
2176*fcf3ce44SJohn Forte 	/*
2177*fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
2178*fcf3ce44SJohn Forte 	 *
2179*fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
2180*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
2181*fcf3ce44SJohn Forte 	 * or
2182*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
2183*fcf3ce44SJohn Forte 	 * or
2184*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
2185*fcf3ce44SJohn Forte 	 * or
2186*fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
2187*fcf3ce44SJohn Forte 	 */
2188*fcf3ce44SJohn Forte 	if (strstr(path, SCSI_VHCI)) {
2189*fcf3ce44SJohn Forte 		(void) strcpy(drvr_path0, path);
2190*fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path0, &pathlist)) {
2191*fcf3ce44SJohn Forte 			*l_err = L_INVALID_PATH;
2192*fcf3ce44SJohn Forte 			return (NULL);
2193*fcf3ce44SJohn Forte 		}
2194*fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
2195*fcf3ce44SJohn Forte 		p_on = p_st = 0;
2196*fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
2197*fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
2198*fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
2199*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_ONLINE) {
2200*fcf3ce44SJohn Forte 					p_on = i;
2201*fcf3ce44SJohn Forte 					break;
2202*fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
2203*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_STANDBY) {
2204*fcf3ce44SJohn Forte 					p_st = i;
2205*fcf3ce44SJohn Forte 				}
2206*fcf3ce44SJohn Forte 			}
2207*fcf3ce44SJohn Forte 		}
2208*fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
2209*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
2210*fcf3ce44SJohn Forte 			/* on_line path */
2211*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
2212*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_hba);
2213*fcf3ce44SJohn Forte 		} else {
2214*fcf3ce44SJohn Forte 			/* standby or path0 */
2215*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
2216*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_hba);
2217*fcf3ce44SJohn Forte 		}
2218*fcf3ce44SJohn Forte 		free(pathlist.path_info);
2219*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
2220*fcf3ce44SJohn Forte 	} else {
2221*fcf3ce44SJohn Forte 		(void) strcpy(drvr_path, path);
2222*fcf3ce44SJohn Forte 		if (strstr(drvr_path, DRV_NAME_SSD) ||
2223*fcf3ce44SJohn Forte 			strstr(drvr_path, SES_NAME) ||
2224*fcf3ce44SJohn Forte 			strstr(drvr_path, DRV_NAME_ST)) {
2225*fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
2226*fcf3ce44SJohn Forte 				*l_err = L_INVALID_PATH;
2227*fcf3ce44SJohn Forte 				return (NULL);
2228*fcf3ce44SJohn Forte 			}
2229*fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate sting  */
2230*fcf3ce44SJohn Forte 			/* append controller */
2231*fcf3ce44SJohn Forte 			(void) strcat(drvr_path, FC_CTLR);
2232*fcf3ce44SJohn Forte 		} else {
2233*fcf3ce44SJohn Forte 			if (stat(drvr_path, &stbuf) < 0) {
2234*fcf3ce44SJohn Forte 				*l_err = L_LSTAT_ERROR;
2235*fcf3ce44SJohn Forte 				return (NULL);
2236*fcf3ce44SJohn Forte 			}
2237*fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
2238*fcf3ce44SJohn Forte 				/* append controller */
2239*fcf3ce44SJohn Forte 				(void) strcat(drvr_path, FC_CTLR);
2240*fcf3ce44SJohn Forte 			}
2241*fcf3ce44SJohn Forte 		}
2242*fcf3ce44SJohn Forte 	}
2243*fcf3ce44SJohn Forte 
2244*fcf3ce44SJohn Forte 	P_DPRINTF("  g_dev_map_init: Geting drive map from:"
2245*fcf3ce44SJohn Forte 		" %s\n", drvr_path);
2246*fcf3ce44SJohn Forte 
2247*fcf3ce44SJohn Forte 	path_type = g_get_path_type(drvr_path);
2248*fcf3ce44SJohn Forte 	if ((path_type == 0) || !(path_type & XPORT_MASK)) {
2249*fcf3ce44SJohn Forte 		*l_err = L_INVALID_PATH_TYPE;
2250*fcf3ce44SJohn Forte 		return (NULL);
2251*fcf3ce44SJohn Forte 	}
2252*fcf3ce44SJohn Forte 
2253*fcf3ce44SJohn Forte 	/* get fiber topology */
2254*fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(drvr_path,
2255*fcf3ce44SJohn Forte 			&hba_port_top, 0)) != 0) {
2256*fcf3ce44SJohn Forte 		*l_err = err;
2257*fcf3ce44SJohn Forte 		return (NULL);
2258*fcf3ce44SJohn Forte 	}
2259*fcf3ce44SJohn Forte 
2260*fcf3ce44SJohn Forte 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) {
2261*fcf3ce44SJohn Forte 		*l_err = errno;
2262*fcf3ce44SJohn Forte 		return (NULL);
2263*fcf3ce44SJohn Forte 	}
2264*fcf3ce44SJohn Forte 
2265*fcf3ce44SJohn Forte 	/* for FC devices. */
2266*fcf3ce44SJohn Forte 	if (path_type & FC_FCA_MASK) {
2267*fcf3ce44SJohn Forte 		/* get the number of device first. */
2268*fcf3ce44SJohn Forte 	    fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
2269*fcf3ce44SJohn Forte 	    fcio.fcio_olen = sizeof (num_devices);
2270*fcf3ce44SJohn Forte 	    fcio.fcio_xfer = FCIO_XFER_READ;
2271*fcf3ce44SJohn Forte 	    fcio.fcio_obuf = (caddr_t)&num_devices;
2272*fcf3ce44SJohn Forte 	    if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2273*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
2274*fcf3ce44SJohn Forte 		(void) close(fd);
2275*fcf3ce44SJohn Forte 		*l_err = L_FCIO_GET_NUM_DEVS_FAIL;
2276*fcf3ce44SJohn Forte 		return (NULL);
2277*fcf3ce44SJohn Forte 	    }
2278*fcf3ce44SJohn Forte 	    if (num_devices != 0) {
2279*fcf3ce44SJohn Forte 		if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
2280*fcf3ce44SJohn Forte 			sizeof (fc_port_dev_t))) == NULL) {
2281*fcf3ce44SJohn Forte 		    (void) close(fd);
2282*fcf3ce44SJohn Forte 		    *l_err = L_MALLOC_FAILED;
2283*fcf3ce44SJohn Forte 		    return (NULL);
2284*fcf3ce44SJohn Forte 		}
2285*fcf3ce44SJohn Forte 
2286*fcf3ce44SJohn Forte 		bzero((caddr_t)&fcio, sizeof (fcio));
2287*fcf3ce44SJohn Forte 		/* Get the device list */
2288*fcf3ce44SJohn Forte 		fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2289*fcf3ce44SJohn Forte 		/* Information read operation */
2290*fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_READ;
2291*fcf3ce44SJohn Forte 		fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
2292*fcf3ce44SJohn Forte 		fcio.fcio_obuf = (caddr_t)dev_list;
2293*fcf3ce44SJohn Forte 		/* new device count */
2294*fcf3ce44SJohn Forte 		fcio.fcio_alen = sizeof (new_count);
2295*fcf3ce44SJohn Forte 		fcio.fcio_abuf = (caddr_t)&new_count;
2296*fcf3ce44SJohn Forte 		if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
2297*fcf3ce44SJohn Forte 		    if (err == L_INVALID_DEVICE_COUNT) {
2298*fcf3ce44SJohn Forte 			/*
2299*fcf3ce44SJohn Forte 			 * original buffer was small so allocate buffer
2300*fcf3ce44SJohn Forte 			 * with a new count and retry.
2301*fcf3ce44SJohn Forte 			 */
2302*fcf3ce44SJohn Forte 			free(dev_list);
2303*fcf3ce44SJohn Forte 			num_devices = new_count;
2304*fcf3ce44SJohn Forte 			new_count = 0;
2305*fcf3ce44SJohn Forte 			if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
2306*fcf3ce44SJohn Forte 				sizeof (fc_port_dev_t))) == NULL) {
2307*fcf3ce44SJohn Forte 			    (void) close(fd);
2308*fcf3ce44SJohn Forte 			    *l_err = L_MALLOC_FAILED;
2309*fcf3ce44SJohn Forte 			    return (NULL);
2310*fcf3ce44SJohn Forte 			}
2311*fcf3ce44SJohn Forte 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2312*fcf3ce44SJohn Forte 			/* Information read operation */
2313*fcf3ce44SJohn Forte 			fcio.fcio_xfer = FCIO_XFER_READ;
2314*fcf3ce44SJohn Forte 			fcio.fcio_obuf = (caddr_t)dev_list;
2315*fcf3ce44SJohn Forte 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
2316*fcf3ce44SJohn Forte 			/* new device count */
2317*fcf3ce44SJohn Forte 			fcio.fcio_alen = sizeof (new_count);
2318*fcf3ce44SJohn Forte 			fcio.fcio_abuf = (caddr_t)&new_count;
2319*fcf3ce44SJohn Forte 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
2320*fcf3ce44SJohn Forte 			    if (err == L_INVALID_DEVICE_COUNT) {
2321*fcf3ce44SJohn Forte 				/*
2322*fcf3ce44SJohn Forte 				 * No more retry. There may be severe hardware
2323*fcf3ce44SJohn Forte 				 * problem so return error here.
2324*fcf3ce44SJohn Forte 				 */
2325*fcf3ce44SJohn Forte 				I_DPRINTF(" Device count was %d"
2326*fcf3ce44SJohn Forte 				" should have been %d\n",
2327*fcf3ce44SJohn Forte 				num_devices, new_count);
2328*fcf3ce44SJohn Forte 				free(dev_list);
2329*fcf3ce44SJohn Forte 				(void) close(fd);
2330*fcf3ce44SJohn Forte 				*l_err = L_INVALID_DEVICE_COUNT;
2331*fcf3ce44SJohn Forte 				return (NULL);
2332*fcf3ce44SJohn Forte 			    } else {
2333*fcf3ce44SJohn Forte 				I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
2334*fcf3ce44SJohn Forte 				free(dev_list);
2335*fcf3ce44SJohn Forte 				(void) close(fd);
2336*fcf3ce44SJohn Forte 				*l_err = L_FCIO_GET_DEV_LIST_FAIL;
2337*fcf3ce44SJohn Forte 				return (NULL);
2338*fcf3ce44SJohn Forte 			    }
2339*fcf3ce44SJohn Forte 			}
2340*fcf3ce44SJohn Forte 		    }
2341*fcf3ce44SJohn Forte 		}
2342*fcf3ce44SJohn Forte 	    }
2343*fcf3ce44SJohn Forte 
2344*fcf3ce44SJohn Forte 		/*
2345*fcf3ce44SJohn Forte 		 * if new count is smaller than the original number from
2346*fcf3ce44SJohn Forte 		 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
2347*fcf3ce44SJohn Forte 		 * and continue.
2348*fcf3ce44SJohn Forte 		 */
2349*fcf3ce44SJohn Forte 	    if (new_count < num_devices) {
2350*fcf3ce44SJohn Forte 		num_devices = new_count;
2351*fcf3ce44SJohn Forte 		if (new_count > 0) {
2352*fcf3ce44SJohn Forte 		    if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
2353*fcf3ce44SJohn Forte 			(new_count * sizeof (fc_port_dev_t))))
2354*fcf3ce44SJohn Forte 				== NULL) {
2355*fcf3ce44SJohn Forte 			S_FREE(dev_list);
2356*fcf3ce44SJohn Forte 			(void) close(fd);
2357*fcf3ce44SJohn Forte 			*l_err = L_MALLOC_FAILED;
2358*fcf3ce44SJohn Forte 			return (NULL);
2359*fcf3ce44SJohn Forte 		    }
2360*fcf3ce44SJohn Forte 		}
2361*fcf3ce44SJohn Forte 	    }
2362*fcf3ce44SJohn Forte 
2363*fcf3ce44SJohn Forte 		/* get the host param info */
2364*fcf3ce44SJohn Forte 	    (void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev));
2365*fcf3ce44SJohn Forte 	    fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
2366*fcf3ce44SJohn Forte 	    fcio.fcio_xfer = FCIO_XFER_READ;
2367*fcf3ce44SJohn Forte 	    fcio.fcio_obuf = (caddr_t)&fp_hba_port;
2368*fcf3ce44SJohn Forte 	    fcio.fcio_olen = sizeof (fc_port_dev_t);
2369*fcf3ce44SJohn Forte 
2370*fcf3ce44SJohn Forte 	    if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2371*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
2372*fcf3ce44SJohn Forte 		(void) close(fd);
2373*fcf3ce44SJohn Forte 		if (num_devices == 0) {
2374*fcf3ce44SJohn Forte 			*l_err = L_NO_DEVICES_FOUND;
2375*fcf3ce44SJohn Forte 		} else {
2376*fcf3ce44SJohn Forte 			free(dev_list);
2377*fcf3ce44SJohn Forte 			*l_err = L_FCIO_GET_HOST_PARAMS_FAIL;
2378*fcf3ce44SJohn Forte 		}
2379*fcf3ce44SJohn Forte 		(void) close(fd);
2380*fcf3ce44SJohn Forte 		return (NULL);
2381*fcf3ce44SJohn Forte 	    }
2382*fcf3ce44SJohn Forte 
2383*fcf3ce44SJohn Forte 		/* If we want the lilp map then we need to do a little	*/
2384*fcf3ce44SJohn Forte 		/* work here.  The lilp map contains the local hba in	*/
2385*fcf3ce44SJohn Forte 		/* the dev_addr.  Once this has been added qsort the	*/
2386*fcf3ce44SJohn Forte 		/* dev_addr array so it's in physical order.		*/
2387*fcf3ce44SJohn Forte 	    if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) {
2388*fcf3ce44SJohn Forte 		/* First we need to allocate one additional	*/
2389*fcf3ce44SJohn Forte 		/* device to the dev_addr structure, for the 	*/
2390*fcf3ce44SJohn Forte 		/* local hba					*/
2391*fcf3ce44SJohn Forte 		if (num_devices > 0) {
2392*fcf3ce44SJohn Forte 		    if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
2393*fcf3ce44SJohn Forte 			(++num_devices * sizeof (fc_port_dev_t)))) == NULL) {
2394*fcf3ce44SJohn Forte 			(void) close(fd);
2395*fcf3ce44SJohn Forte 			/* in case dev_list is not null free it. */
2396*fcf3ce44SJohn Forte 			S_FREE(dev_list);
2397*fcf3ce44SJohn Forte 			*l_err =  L_MALLOC_FAILED;
2398*fcf3ce44SJohn Forte 			return (NULL);
2399*fcf3ce44SJohn Forte 		    }
2400*fcf3ce44SJohn Forte 
2401*fcf3ce44SJohn Forte 		    /* Next, copy the local hba into this new loc.	*/
2402*fcf3ce44SJohn Forte 		    if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
2403*fcf3ce44SJohn Forte 				sizeof (fc_port_dev_t)) == NULL) {
2404*fcf3ce44SJohn Forte 			(void) free(dev_list);
2405*fcf3ce44SJohn Forte 			(void) close(fd);
2406*fcf3ce44SJohn Forte 			*l_err =  L_MEMCPY_FAILED;
2407*fcf3ce44SJohn Forte 			return (NULL);
2408*fcf3ce44SJohn Forte 		    }
2409*fcf3ce44SJohn Forte 
2410*fcf3ce44SJohn Forte 			/* Now sort by physical location		*/
2411*fcf3ce44SJohn Forte 		    qsort((void*)dev_list, num_devices,
2412*fcf3ce44SJohn Forte 			sizeof (fc_port_dev_t), lilp_map_cmp);
2413*fcf3ce44SJohn Forte 		}
2414*fcf3ce44SJohn Forte 	    }
2415*fcf3ce44SJohn Forte 
2416*fcf3ce44SJohn Forte 
2417*fcf3ce44SJohn Forte 		/* We have dev list info and host param info.	*/
2418*fcf3ce44SJohn Forte 		/* Now constructs map tree with these info.	*/
2419*fcf3ce44SJohn Forte 		/* First consturct the root of the map tree	*/
2420*fcf3ce44SJohn Forte 		/* with host param.				*/
2421*fcf3ce44SJohn Forte 	    if ((impl_map = (impl_map_dev_t *)calloc(
2422*fcf3ce44SJohn Forte 			1, sizeof (impl_map_dev_t))) == NULL) {
2423*fcf3ce44SJohn Forte 		(void) free(dev_list);
2424*fcf3ce44SJohn Forte 		(void) close(fd);
2425*fcf3ce44SJohn Forte 		*l_err = L_MALLOC_FAILED;
2426*fcf3ce44SJohn Forte 		return (NULL);
2427*fcf3ce44SJohn Forte 	    }
2428*fcf3ce44SJohn Forte 	    impl_map->flag = flag;
2429*fcf3ce44SJohn Forte 	    impl_map->topo = hba_port_top;
2430*fcf3ce44SJohn Forte 
2431*fcf3ce44SJohn Forte 		/* consturct hba property list.	*/
2432*fcf3ce44SJohn Forte 	    if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2433*fcf3ce44SJohn Forte 		    hba_port_top, fp_hba_port.dev_pwwn.raw_wwn,
2434*fcf3ce44SJohn Forte 		    fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id,
2435*fcf3ce44SJohn Forte 		    fp_hba_port.dev_hard_addr.hard_addr)) != 0) {
2436*fcf3ce44SJohn Forte 		(void) free(dev_list);
2437*fcf3ce44SJohn Forte 		(void) close(fd);
2438*fcf3ce44SJohn Forte 		g_dev_map_fini(impl_map);
2439*fcf3ce44SJohn Forte 		*l_err = err;
2440*fcf3ce44SJohn Forte 		return (NULL);
2441*fcf3ce44SJohn Forte 	    }
2442*fcf3ce44SJohn Forte 
2443*fcf3ce44SJohn Forte 	    if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2444*fcf3ce44SJohn Forte 		if (fstat(fd, &sbuf) == -1) {
2445*fcf3ce44SJohn Forte 		    (void) free(dev_list);
2446*fcf3ce44SJohn Forte 		    (void) close(fd);
2447*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2448*fcf3ce44SJohn Forte 		    *l_err = L_FSTAT_ERROR;
2449*fcf3ce44SJohn Forte 		    return (NULL);
2450*fcf3ce44SJohn Forte 		}
2451*fcf3ce44SJohn Forte 		if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
2452*fcf3ce44SJohn Forte 			fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) {
2453*fcf3ce44SJohn Forte 		    (void) free(dev_list);
2454*fcf3ce44SJohn Forte 		    (void) close(fd);
2455*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2456*fcf3ce44SJohn Forte 		    *l_err = err;
2457*fcf3ce44SJohn Forte 		    return (NULL);
2458*fcf3ce44SJohn Forte 		}
2459*fcf3ce44SJohn Forte 	    }
2460*fcf3ce44SJohn Forte 
2461*fcf3ce44SJohn Forte 		/* consturct child for each device and	*/
2462*fcf3ce44SJohn Forte 		/* set device property list.		*/
2463*fcf3ce44SJohn Forte 	    dlist = dev_list;
2464*fcf3ce44SJohn Forte 	    for (i = 0; i < num_devices; i++, dlist++) {
2465*fcf3ce44SJohn Forte 		if ((impl_dev = (impl_map_dev_t *)calloc(
2466*fcf3ce44SJohn Forte 			1, sizeof (impl_map_dev_t))) == NULL) {
2467*fcf3ce44SJohn Forte 		    (void) free(dev_list);
2468*fcf3ce44SJohn Forte 		    (void) close(fd);
2469*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2470*fcf3ce44SJohn Forte 		    *l_err = L_MALLOC_FAILED;
2471*fcf3ce44SJohn Forte 		    return (NULL);
2472*fcf3ce44SJohn Forte 		}
2473*fcf3ce44SJohn Forte 		/* set the map as parent */
2474*fcf3ce44SJohn Forte 		impl_dev->parent = impl_map;
2475*fcf3ce44SJohn Forte 		if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2476*fcf3ce44SJohn Forte 		    hba_port_top, dlist->dev_pwwn.raw_wwn,
2477*fcf3ce44SJohn Forte 		    dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id,
2478*fcf3ce44SJohn Forte 		    dlist->dev_hard_addr.hard_addr)) != 0) {
2479*fcf3ce44SJohn Forte 		    (void) free(dev_list);
2480*fcf3ce44SJohn Forte 		    (void) close(fd);
2481*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2482*fcf3ce44SJohn Forte 		    *l_err = err;
2483*fcf3ce44SJohn Forte 		    return (NULL);
2484*fcf3ce44SJohn Forte 		}
2485*fcf3ce44SJohn Forte 		if (i == 0) {
2486*fcf3ce44SJohn Forte 		    mdl_start = mdl_end = impl_dev;
2487*fcf3ce44SJohn Forte 		} else {
2488*fcf3ce44SJohn Forte 		    mdl_end->next = impl_dev;
2489*fcf3ce44SJohn Forte 		    mdl_end = impl_dev;
2490*fcf3ce44SJohn Forte 		}
2491*fcf3ce44SJohn Forte 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2492*fcf3ce44SJohn Forte 		    if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
2493*fcf3ce44SJohn Forte 			(hba_port_top == FC_TOP_FABRIC)) &&
2494*fcf3ce44SJohn Forte 			(memcmp(fp_hba_port.dev_pwwn.raw_wwn,
2495*fcf3ce44SJohn Forte 			dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) {
2496*fcf3ce44SJohn Forte 			(void) memset(&fcio, 0, sizeof (fcio_t));
2497*fcf3ce44SJohn Forte 			fcio.fcio_cmd = FCIO_GET_STATE;
2498*fcf3ce44SJohn Forte 			fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
2499*fcf3ce44SJohn Forte 			fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
2500*fcf3ce44SJohn Forte 			fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE;
2501*fcf3ce44SJohn Forte 			fcio.fcio_olen = sizeof (uint32_t);
2502*fcf3ce44SJohn Forte 			fcio.fcio_obuf = (caddr_t)&state;
2503*fcf3ce44SJohn Forte 			fcio.fcio_alen = 0;
2504*fcf3ce44SJohn Forte 			fcio.fcio_abuf = NULL;
2505*fcf3ce44SJohn Forte 			if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2506*fcf3ce44SJohn Forte 			    I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
2507*fcf3ce44SJohn Forte 			    if ((err = update_map_dev_FCP_prop(
2508*fcf3ce44SJohn Forte 				&impl_dev->prop_list, NULL,
2509*fcf3ce44SJohn Forte 				L_FCIO_GET_STATE_FAIL, PROP_NOEXIST)) != 0) {
2510*fcf3ce44SJohn Forte 				(void) free(dev_list);
2511*fcf3ce44SJohn Forte 				(void) close(fd);
2512*fcf3ce44SJohn Forte 				g_dev_map_fini(impl_map);
2513*fcf3ce44SJohn Forte 				*l_err = err;
2514*fcf3ce44SJohn Forte 				return (NULL);
2515*fcf3ce44SJohn Forte 			    }
2516*fcf3ce44SJohn Forte 			}
2517*fcf3ce44SJohn Forte 			if (state != PORT_DEVICE_LOGGED_IN) {
2518*fcf3ce44SJohn Forte 			    (void) close(fd);
2519*fcf3ce44SJohn Forte 			    if ((fd = g_object_open(drvr_path,
2520*fcf3ce44SJohn Forte 				O_NDELAY | O_RDONLY | O_EXCL)) == -1) {
2521*fcf3ce44SJohn Forte 				(void) free(dev_list);
2522*fcf3ce44SJohn Forte 				g_dev_map_fini(impl_map);
2523*fcf3ce44SJohn Forte 				*l_err = L_OPEN_PATH_FAIL;
2524*fcf3ce44SJohn Forte 				return (NULL);
2525*fcf3ce44SJohn Forte 			    }
2526*fcf3ce44SJohn Forte 			    (void) memset(&fcio, 0, sizeof (fcio_t));
2527*fcf3ce44SJohn Forte 			    fcio.fcio_cmd = FCIO_DEV_LOGIN;
2528*fcf3ce44SJohn Forte 			    fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
2529*fcf3ce44SJohn Forte 			    fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
2530*fcf3ce44SJohn Forte 			    fcio.fcio_xfer = FCIO_XFER_WRITE;
2531*fcf3ce44SJohn Forte 			    fcio.fcio_olen = fcio.fcio_alen = 0;
2532*fcf3ce44SJohn Forte 			    fcio.fcio_obuf = fcio.fcio_abuf = NULL;
2533*fcf3ce44SJohn Forte 			    if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2534*fcf3ce44SJohn Forte 				I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
2535*fcf3ce44SJohn Forte 				if ((err = update_map_dev_FCP_prop(
2536*fcf3ce44SJohn Forte 				    &impl_dev->prop_list, NULL,
2537*fcf3ce44SJohn Forte 				    L_FCIO_DEV_LOGIN_FAIL,
2538*fcf3ce44SJohn Forte 				    PROP_NOEXIST)) != 0) {
2539*fcf3ce44SJohn Forte 				    (void) free(dev_list);
2540*fcf3ce44SJohn Forte 				    (void) close(fd);
2541*fcf3ce44SJohn Forte 				    g_dev_map_fini(impl_map);
2542*fcf3ce44SJohn Forte 				    *l_err = err;
2543*fcf3ce44SJohn Forte 				    return (NULL);
2544*fcf3ce44SJohn Forte 				}
2545*fcf3ce44SJohn Forte 				/* plogi failed continue to next dev */
2546*fcf3ce44SJohn Forte 				continue;
2547*fcf3ce44SJohn Forte 			    }
2548*fcf3ce44SJohn Forte 			}
2549*fcf3ce44SJohn Forte 		    }
2550*fcf3ce44SJohn Forte 			/* sbuf should be set from hba_port handling. */
2551*fcf3ce44SJohn Forte 		    if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
2552*fcf3ce44SJohn Forte 			dlist->dev_pwwn, &impl_dev->prop_list)) != 0) {
2553*fcf3ce44SJohn Forte 			(void) free(dev_list);
2554*fcf3ce44SJohn Forte 			(void) close(fd);
2555*fcf3ce44SJohn Forte 			g_dev_map_fini(impl_map);
2556*fcf3ce44SJohn Forte 			*l_err = err;
2557*fcf3ce44SJohn Forte 			return (NULL);
2558*fcf3ce44SJohn Forte 		    }
2559*fcf3ce44SJohn Forte 		}
2560*fcf3ce44SJohn Forte 	    }
2561*fcf3ce44SJohn Forte 		/* connect the children to to map.	*/
2562*fcf3ce44SJohn Forte 	    impl_map->child = mdl_start;
2563*fcf3ce44SJohn Forte 	    S_FREE(dev_list);
2564*fcf3ce44SJohn Forte 
2565*fcf3ce44SJohn Forte 	} else {	/* sf and fc4/pci devices */
2566*fcf3ce44SJohn Forte 	    /* initialize map */
2567*fcf3ce44SJohn Forte 	    (void) memset(&sf_map, 0, sizeof (struct sf_al_map));
2568*fcf3ce44SJohn Forte 	    if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
2569*fcf3ce44SJohn Forte 		I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
2570*fcf3ce44SJohn Forte 		(void) close(fd);
2571*fcf3ce44SJohn Forte 		*l_err = L_SFIOCGMAP_IOCTL_FAIL;
2572*fcf3ce44SJohn Forte 		return (NULL);
2573*fcf3ce44SJohn Forte 	    }
2574*fcf3ce44SJohn Forte 		/* Check for reasonableness. */
2575*fcf3ce44SJohn Forte 	    if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
2576*fcf3ce44SJohn Forte 		(void) close(fd);
2577*fcf3ce44SJohn Forte 		*l_err = L_INVALID_LOOP_MAP;
2578*fcf3ce44SJohn Forte 		return (NULL);
2579*fcf3ce44SJohn Forte 	    }
2580*fcf3ce44SJohn Forte 
2581*fcf3ce44SJohn Forte 	    if (sf_map.sf_count == 0) {
2582*fcf3ce44SJohn Forte 		(void) close(fd);
2583*fcf3ce44SJohn Forte 		*l_err = L_NO_DEVICES_FOUND;
2584*fcf3ce44SJohn Forte 		return (NULL);
2585*fcf3ce44SJohn Forte 	    }
2586*fcf3ce44SJohn Forte 
2587*fcf3ce44SJohn Forte 	    if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) {
2588*fcf3ce44SJohn Forte 		(void) close(fd);
2589*fcf3ce44SJohn Forte 		*l_err = err;
2590*fcf3ce44SJohn Forte 		return (NULL);
2591*fcf3ce44SJohn Forte 	    }
2592*fcf3ce44SJohn Forte 
2593*fcf3ce44SJohn Forte 	    if ((nexus_fd = g_object_open(nexus_path, O_NDELAY | O_RDONLY)) ==
2594*fcf3ce44SJohn Forte 			-1) {
2595*fcf3ce44SJohn Forte 		(void) close(fd);
2596*fcf3ce44SJohn Forte 		S_FREE(nexus_path);
2597*fcf3ce44SJohn Forte 		*l_err = errno;
2598*fcf3ce44SJohn Forte 		return (NULL);
2599*fcf3ce44SJohn Forte 	    }
2600*fcf3ce44SJohn Forte 
2601*fcf3ce44SJohn Forte 		/* get limited map to get hba param info */
2602*fcf3ce44SJohn Forte 	    if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) {
2603*fcf3ce44SJohn Forte 		I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
2604*fcf3ce44SJohn Forte 		(void) close(fd);
2605*fcf3ce44SJohn Forte 		(void) close(nexus_fd);
2606*fcf3ce44SJohn Forte 		S_FREE(nexus_path);
2607*fcf3ce44SJohn Forte 		*l_err = L_FCIO_GETMAP_IOCTL_FAIL;
2608*fcf3ce44SJohn Forte 		return (NULL);
2609*fcf3ce44SJohn Forte 	    }
2610*fcf3ce44SJohn Forte 	    (void) close(nexus_fd);
2611*fcf3ce44SJohn Forte 	    S_FREE(nexus_path);
2612*fcf3ce44SJohn Forte 
2613*fcf3ce44SJohn Forte 	    for (i = 0; i < sf_map.sf_count; i++) {
2614*fcf3ce44SJohn Forte 		if (sf_map.sf_addr_pair[i].sf_al_pa ==
2615*fcf3ce44SJohn Forte 			limited_map.lilp_myalpa) {
2616*fcf3ce44SJohn Forte 			sf_map.sf_hba_addr = sf_map.sf_addr_pair[i];
2617*fcf3ce44SJohn Forte 			hba_alpa_found = 1;
2618*fcf3ce44SJohn Forte 		}
2619*fcf3ce44SJohn Forte 	    }
2620*fcf3ce44SJohn Forte 
2621*fcf3ce44SJohn Forte 	    if (!(hba_alpa_found)) {
2622*fcf3ce44SJohn Forte 		(void) close(fd);
2623*fcf3ce44SJohn Forte 		*l_err = L_INVALID_LOOP_MAP;
2624*fcf3ce44SJohn Forte 		return (NULL);
2625*fcf3ce44SJohn Forte 	    }
2626*fcf3ce44SJohn Forte 
2627*fcf3ce44SJohn Forte 		/* We have dev list info and host param info.	*/
2628*fcf3ce44SJohn Forte 		/* Now constructs map tree with these info.	*/
2629*fcf3ce44SJohn Forte 		/* First consturct the root of the map tree	*/
2630*fcf3ce44SJohn Forte 		/* with host param.				*/
2631*fcf3ce44SJohn Forte 	    if ((impl_map = (impl_map_dev_t *)calloc(
2632*fcf3ce44SJohn Forte 			1, sizeof (impl_map_dev_t))) == NULL) {
2633*fcf3ce44SJohn Forte 		(void) close(fd);
2634*fcf3ce44SJohn Forte 		*l_err = L_MALLOC_FAILED;
2635*fcf3ce44SJohn Forte 		return (NULL);
2636*fcf3ce44SJohn Forte 	    }
2637*fcf3ce44SJohn Forte 	    impl_map->flag = flag;
2638*fcf3ce44SJohn Forte 	    impl_map->topo = hba_port_top;
2639*fcf3ce44SJohn Forte 
2640*fcf3ce44SJohn Forte 		/* consturct hba property list.	*/
2641*fcf3ce44SJohn Forte 	    if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2642*fcf3ce44SJohn Forte 		    hba_port_top, sf_map.sf_hba_addr.sf_port_wwn,
2643*fcf3ce44SJohn Forte 		    sf_map.sf_hba_addr.sf_node_wwn,
2644*fcf3ce44SJohn Forte 		    (int)sf_map.sf_hba_addr.sf_al_pa,
2645*fcf3ce44SJohn Forte 		    (int)sf_map.sf_hba_addr.sf_hard_address)) != 0) {
2646*fcf3ce44SJohn Forte 		(void) close(fd);
2647*fcf3ce44SJohn Forte 		g_dev_map_fini(impl_map);
2648*fcf3ce44SJohn Forte 		*l_err = err;
2649*fcf3ce44SJohn Forte 		return (NULL);
2650*fcf3ce44SJohn Forte 	    }
2651*fcf3ce44SJohn Forte 
2652*fcf3ce44SJohn Forte 	    if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2653*fcf3ce44SJohn Forte 		if ((err = update_map_dev_FCP_prop(&impl_map->prop_list,
2654*fcf3ce44SJohn Forte 		    &sf_map.sf_hba_addr.sf_inq_dtype, 0, PROP_NOEXIST)) != 0) {
2655*fcf3ce44SJohn Forte 		    (void) close(fd);
2656*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2657*fcf3ce44SJohn Forte 		    *l_err = err;
2658*fcf3ce44SJohn Forte 		    return (NULL);
2659*fcf3ce44SJohn Forte 		}
2660*fcf3ce44SJohn Forte 	    }
2661*fcf3ce44SJohn Forte 
2662*fcf3ce44SJohn Forte 	    for (i = 0; i < sf_map.sf_count; i++) {
2663*fcf3ce44SJohn Forte 		if ((impl_dev = (impl_map_dev_t *)calloc(
2664*fcf3ce44SJohn Forte 			1, sizeof (impl_map_dev_t))) == NULL) {
2665*fcf3ce44SJohn Forte 		    (void) close(fd);
2666*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2667*fcf3ce44SJohn Forte 		    *l_err = L_MALLOC_FAILED;
2668*fcf3ce44SJohn Forte 		    return (NULL);
2669*fcf3ce44SJohn Forte 		}
2670*fcf3ce44SJohn Forte 		/* set the map as parent */
2671*fcf3ce44SJohn Forte 		impl_dev->parent = impl_map;
2672*fcf3ce44SJohn Forte 		if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2673*fcf3ce44SJohn Forte 		    hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn,
2674*fcf3ce44SJohn Forte 		    sf_map.sf_addr_pair[i].sf_node_wwn,
2675*fcf3ce44SJohn Forte 		    (int)(sf_map.sf_addr_pair[i].sf_al_pa),
2676*fcf3ce44SJohn Forte 		    (int)(sf_map.sf_addr_pair[i].sf_hard_address))) != 0) {
2677*fcf3ce44SJohn Forte 		    (void) close(fd);
2678*fcf3ce44SJohn Forte 		    g_dev_map_fini(impl_map);
2679*fcf3ce44SJohn Forte 		    *l_err = err;
2680*fcf3ce44SJohn Forte 		    return (NULL);
2681*fcf3ce44SJohn Forte 		}
2682*fcf3ce44SJohn Forte 		if (i == 0) {
2683*fcf3ce44SJohn Forte 		    mdl_start = mdl_end = impl_dev;
2684*fcf3ce44SJohn Forte 		} else {
2685*fcf3ce44SJohn Forte 		    mdl_end->next = impl_dev;
2686*fcf3ce44SJohn Forte 		    mdl_end = impl_dev;
2687*fcf3ce44SJohn Forte 		}
2688*fcf3ce44SJohn Forte 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2689*fcf3ce44SJohn Forte 		    if ((err = update_map_dev_FCP_prop(&impl_dev->prop_list,
2690*fcf3ce44SJohn Forte 			&sf_map.sf_addr_pair[i].sf_inq_dtype, 0,
2691*fcf3ce44SJohn Forte 			PROP_NOEXIST)) != 0) {
2692*fcf3ce44SJohn Forte 			(void) close(fd);
2693*fcf3ce44SJohn Forte 			g_dev_map_fini(impl_map);
2694*fcf3ce44SJohn Forte 			*l_err = err;
2695*fcf3ce44SJohn Forte 			return (NULL);
2696*fcf3ce44SJohn Forte 		    }
2697*fcf3ce44SJohn Forte 		}
2698*fcf3ce44SJohn Forte 	    } /* end of for loop */
2699*fcf3ce44SJohn Forte 
2700*fcf3ce44SJohn Forte 	    impl_map->child = mdl_start;
2701*fcf3ce44SJohn Forte 	} /* end of else */
2702*fcf3ce44SJohn Forte 
2703*fcf3ce44SJohn Forte 	close(fd);
2704*fcf3ce44SJohn Forte 	return ((gfc_dev_t)(impl_map));
2705*fcf3ce44SJohn Forte }
2706*fcf3ce44SJohn Forte 
2707*fcf3ce44SJohn Forte /*
2708*fcf3ce44SJohn Forte  * This function deallocates memory for propery list.
2709*fcf3ce44SJohn Forte  */
2710*fcf3ce44SJohn Forte static void
2711*fcf3ce44SJohn Forte free_prop_list(impl_map_dev_prop_t **prop_list)
2712*fcf3ce44SJohn Forte {
2713*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *lp, *olp;
2714*fcf3ce44SJohn Forte 
2715*fcf3ce44SJohn Forte 	lp = *prop_list;
2716*fcf3ce44SJohn Forte 	while (lp != NULL) {
2717*fcf3ce44SJohn Forte 		switch (lp->prop_type) {
2718*fcf3ce44SJohn Forte 		case GFC_PROP_TYPE_BYTES:
2719*fcf3ce44SJohn Forte 			free((uchar_t *)(lp->prop_data));
2720*fcf3ce44SJohn Forte 			break;
2721*fcf3ce44SJohn Forte 		case GFC_PROP_TYPE_INT:
2722*fcf3ce44SJohn Forte 			free((int *)(lp->prop_data));
2723*fcf3ce44SJohn Forte 			break;
2724*fcf3ce44SJohn Forte 		case GFC_PROP_TYPE_STRING:
2725*fcf3ce44SJohn Forte 			free((char *)(lp->prop_data));
2726*fcf3ce44SJohn Forte 			break;
2727*fcf3ce44SJohn Forte 		default:
2728*fcf3ce44SJohn Forte 			break;
2729*fcf3ce44SJohn Forte 		}
2730*fcf3ce44SJohn Forte 		lp->prop_data = NULL;
2731*fcf3ce44SJohn Forte 		olp = lp;
2732*fcf3ce44SJohn Forte 		lp = olp->next;
2733*fcf3ce44SJohn Forte 		S_FREE(olp);
2734*fcf3ce44SJohn Forte 	}
2735*fcf3ce44SJohn Forte 
2736*fcf3ce44SJohn Forte 	*prop_list = NULL;
2737*fcf3ce44SJohn Forte }
2738*fcf3ce44SJohn Forte 
2739*fcf3ce44SJohn Forte /*
2740*fcf3ce44SJohn Forte  * This function deallocates memory for children list.
2741*fcf3ce44SJohn Forte  */
2742*fcf3ce44SJohn Forte static void
2743*fcf3ce44SJohn Forte free_child_list(impl_map_dev_t **dev_list)
2744*fcf3ce44SJohn Forte {
2745*fcf3ce44SJohn Forte 	impl_map_dev_t *lp, *olp;
2746*fcf3ce44SJohn Forte 
2747*fcf3ce44SJohn Forte 	lp = *dev_list;
2748*fcf3ce44SJohn Forte 	while (lp != NULL) {
2749*fcf3ce44SJohn Forte 		free_prop_list(&lp->prop_list);
2750*fcf3ce44SJohn Forte 		olp = lp;
2751*fcf3ce44SJohn Forte 		lp = olp->next;
2752*fcf3ce44SJohn Forte 		S_FREE(olp);
2753*fcf3ce44SJohn Forte 	}
2754*fcf3ce44SJohn Forte 
2755*fcf3ce44SJohn Forte 	*dev_list = NULL;
2756*fcf3ce44SJohn Forte }
2757*fcf3ce44SJohn Forte 
2758*fcf3ce44SJohn Forte /*
2759*fcf3ce44SJohn Forte  * This function deallocates memory for the whole map.
2760*fcf3ce44SJohn Forte  */
2761*fcf3ce44SJohn Forte void
2762*fcf3ce44SJohn Forte g_dev_map_fini(gfc_dev_t map)
2763*fcf3ce44SJohn Forte {
2764*fcf3ce44SJohn Forte 	impl_map_dev_t *impl_map;
2765*fcf3ce44SJohn Forte 
2766*fcf3ce44SJohn Forte 	impl_map = (impl_map_dev_t *)map;
2767*fcf3ce44SJohn Forte 
2768*fcf3ce44SJohn Forte 	if (impl_map != NULL) {
2769*fcf3ce44SJohn Forte 	    free_prop_list(&impl_map->prop_list);
2770*fcf3ce44SJohn Forte 	    free_child_list(&impl_map->child);
2771*fcf3ce44SJohn Forte 	    S_FREE(impl_map);
2772*fcf3ce44SJohn Forte 	}
2773*fcf3ce44SJohn Forte }
2774*fcf3ce44SJohn Forte 
2775*fcf3ce44SJohn Forte /*
2776*fcf3ce44SJohn Forte  * This function passes back topology of the input map.
2777*fcf3ce44SJohn Forte  * input should be a handle form g_dev_map_init().
2778*fcf3ce44SJohn Forte  *
2779*fcf3ce44SJohn Forte  * return 0 if OK.
2780*fcf3ce44SJohn Forte  * return error code otherwise.
2781*fcf3ce44SJohn Forte  */
2782*fcf3ce44SJohn Forte int
2783*fcf3ce44SJohn Forte g_get_map_topology(
2784*fcf3ce44SJohn Forte 	gfc_dev_t map,
2785*fcf3ce44SJohn Forte 	uint_t *topology)
2786*fcf3ce44SJohn Forte {
2787*fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_map;
2788*fcf3ce44SJohn Forte 
2789*fcf3ce44SJohn Forte 	if (map == NULL) {
2790*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2791*fcf3ce44SJohn Forte 	}
2792*fcf3ce44SJohn Forte 
2793*fcf3ce44SJohn Forte 	if (topology == NULL) {
2794*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
2795*fcf3ce44SJohn Forte 	}
2796*fcf3ce44SJohn Forte 
2797*fcf3ce44SJohn Forte 	impl_map = (impl_map_dev_t *)map;
2798*fcf3ce44SJohn Forte 
2799*fcf3ce44SJohn Forte 	*topology = impl_map->topo;
2800*fcf3ce44SJohn Forte 
2801*fcf3ce44SJohn Forte 	return (0);
2802*fcf3ce44SJohn Forte }
2803*fcf3ce44SJohn Forte 
2804*fcf3ce44SJohn Forte /*
2805*fcf3ce44SJohn Forte  * This function returns the first device handle of the input map.
2806*fcf3ce44SJohn Forte  * map input should be a handle form g_dev_map_init().
2807*fcf3ce44SJohn Forte  *
2808*fcf3ce44SJohn Forte  * l_err set to 0 if OK.
2809*fcf3ce44SJohn Forte  * l_err set to error code otherwise.
2810*fcf3ce44SJohn Forte  */
2811*fcf3ce44SJohn Forte gfc_dev_t
2812*fcf3ce44SJohn Forte g_get_first_dev(
2813*fcf3ce44SJohn Forte 	gfc_dev_t map,
2814*fcf3ce44SJohn Forte 	int *l_err)
2815*fcf3ce44SJohn Forte {
2816*fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_map;
2817*fcf3ce44SJohn Forte 
2818*fcf3ce44SJohn Forte 	if (l_err == NULL) {
2819*fcf3ce44SJohn Forte 		return (NULL);
2820*fcf3ce44SJohn Forte 	}
2821*fcf3ce44SJohn Forte 
2822*fcf3ce44SJohn Forte 	*l_err = 0;
2823*fcf3ce44SJohn Forte 
2824*fcf3ce44SJohn Forte 	if (map == NULL) {
2825*fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_ADDR;
2826*fcf3ce44SJohn Forte 		return (NULL);
2827*fcf3ce44SJohn Forte 	}
2828*fcf3ce44SJohn Forte 
2829*fcf3ce44SJohn Forte 	impl_map = (impl_map_dev_t *)map;
2830*fcf3ce44SJohn Forte 
2831*fcf3ce44SJohn Forte 	if (impl_map->child == NULL) {
2832*fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_DEV_FOUND;
2833*fcf3ce44SJohn Forte 	}
2834*fcf3ce44SJohn Forte 
2835*fcf3ce44SJohn Forte 	return ((gfc_dev_t)(impl_map->child));
2836*fcf3ce44SJohn Forte }
2837*fcf3ce44SJohn Forte 
2838*fcf3ce44SJohn Forte /*
2839*fcf3ce44SJohn Forte  * This function returns the next device handle of the input map.
2840*fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2841*fcf3ce44SJohn Forte  *
2842*fcf3ce44SJohn Forte  * l_err set to 0 if OK.
2843*fcf3ce44SJohn Forte  * l_err set to error code otherwise.
2844*fcf3ce44SJohn Forte  */
2845*fcf3ce44SJohn Forte gfc_dev_t
2846*fcf3ce44SJohn Forte g_get_next_dev(
2847*fcf3ce44SJohn Forte 	gfc_dev_t map_dev,
2848*fcf3ce44SJohn Forte 	int *l_err)
2849*fcf3ce44SJohn Forte {
2850*fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_dev;
2851*fcf3ce44SJohn Forte 
2852*fcf3ce44SJohn Forte 	if (l_err == NULL) {
2853*fcf3ce44SJohn Forte 		return (NULL);
2854*fcf3ce44SJohn Forte 	}
2855*fcf3ce44SJohn Forte 
2856*fcf3ce44SJohn Forte 	*l_err = 0;
2857*fcf3ce44SJohn Forte 
2858*fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2859*fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_ADDR;
2860*fcf3ce44SJohn Forte 		return (NULL);
2861*fcf3ce44SJohn Forte 	}
2862*fcf3ce44SJohn Forte 
2863*fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
2864*fcf3ce44SJohn Forte 
2865*fcf3ce44SJohn Forte 	if (impl_dev->next == NULL) {
2866*fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_DEV_FOUND;
2867*fcf3ce44SJohn Forte 	}
2868*fcf3ce44SJohn Forte 
2869*fcf3ce44SJohn Forte 	return ((gfc_dev_t)(impl_dev->next));
2870*fcf3ce44SJohn Forte }
2871*fcf3ce44SJohn Forte 
2872*fcf3ce44SJohn Forte /*
2873*fcf3ce44SJohn Forte  * This function passes back uchar_t type property and its count.
2874*fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2875*fcf3ce44SJohn Forte  *
2876*fcf3ce44SJohn Forte  * return 0 if OK.
2877*fcf3ce44SJohn Forte  * return error code otherwise.
2878*fcf3ce44SJohn Forte  */
2879*fcf3ce44SJohn Forte int
2880*fcf3ce44SJohn Forte g_dev_prop_lookup_bytes(
2881*fcf3ce44SJohn Forte 	gfc_dev_t map_dev,
2882*fcf3ce44SJohn Forte 	const char *prop_name,
2883*fcf3ce44SJohn Forte 	int *prop_data_count,
2884*fcf3ce44SJohn Forte 	uchar_t **prop_data)
2885*fcf3ce44SJohn Forte {
2886*fcf3ce44SJohn Forte 	impl_map_dev_t *impl_dev;
2887*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
2888*fcf3ce44SJohn Forte 	int err;
2889*fcf3ce44SJohn Forte 
2890*fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2891*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2892*fcf3ce44SJohn Forte 	}
2893*fcf3ce44SJohn Forte 
2894*fcf3ce44SJohn Forte 	if ((prop_name == NULL) || (prop_data == NULL) ||
2895*fcf3ce44SJohn Forte 		(prop_data_count == NULL)) {
2896*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
2897*fcf3ce44SJohn Forte 	}
2898*fcf3ce44SJohn Forte 
2899*fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
2900*fcf3ce44SJohn Forte 	impl_prop = impl_dev->prop_list;
2901*fcf3ce44SJohn Forte 
2902*fcf3ce44SJohn Forte 	err = L_INVALID_MAP_DEV_PROP_NAME;
2903*fcf3ce44SJohn Forte 
2904*fcf3ce44SJohn Forte 	while (impl_prop) {
2905*fcf3ce44SJohn Forte 	    if (strncmp(impl_prop->prop_name, prop_name,
2906*fcf3ce44SJohn Forte 		strlen(prop_name)) == 0) {
2907*fcf3ce44SJohn Forte 		if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
2908*fcf3ce44SJohn Forte 		    err = L_INVALID_MAP_DEV_PROP_TYPE;
2909*fcf3ce44SJohn Forte 		    break;
2910*fcf3ce44SJohn Forte 		}
2911*fcf3ce44SJohn Forte 		if (impl_prop->prop_data) {
2912*fcf3ce44SJohn Forte 		    *prop_data = (uchar_t *)(impl_prop->prop_data);
2913*fcf3ce44SJohn Forte 		    *prop_data_count = impl_prop->prop_size;
2914*fcf3ce44SJohn Forte 		    return (0);
2915*fcf3ce44SJohn Forte 		} else {
2916*fcf3ce44SJohn Forte 		    err = impl_prop->prop_error;
2917*fcf3ce44SJohn Forte 		}
2918*fcf3ce44SJohn Forte 		break;
2919*fcf3ce44SJohn Forte 	    }
2920*fcf3ce44SJohn Forte 	    impl_prop = impl_prop->next;
2921*fcf3ce44SJohn Forte 	}
2922*fcf3ce44SJohn Forte 
2923*fcf3ce44SJohn Forte 	return (err);
2924*fcf3ce44SJohn Forte }
2925*fcf3ce44SJohn Forte 
2926*fcf3ce44SJohn Forte /*
2927*fcf3ce44SJohn Forte  * This function passes back int type property.
2928*fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2929*fcf3ce44SJohn Forte  *
2930*fcf3ce44SJohn Forte  * return 0 if OK.
2931*fcf3ce44SJohn Forte  * return error code otherwise.
2932*fcf3ce44SJohn Forte  */
2933*fcf3ce44SJohn Forte int
2934*fcf3ce44SJohn Forte g_dev_prop_lookup_ints(
2935*fcf3ce44SJohn Forte 	gfc_dev_t map_dev,
2936*fcf3ce44SJohn Forte 	const char *prop_name,
2937*fcf3ce44SJohn Forte 	int **prop_data)
2938*fcf3ce44SJohn Forte {
2939*fcf3ce44SJohn Forte 	impl_map_dev_t *impl_dev;
2940*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
2941*fcf3ce44SJohn Forte 	int err;
2942*fcf3ce44SJohn Forte 
2943*fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2944*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2945*fcf3ce44SJohn Forte 	}
2946*fcf3ce44SJohn Forte 
2947*fcf3ce44SJohn Forte 	if ((prop_name == NULL) || (prop_data == NULL)) {
2948*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
2949*fcf3ce44SJohn Forte 	}
2950*fcf3ce44SJohn Forte 
2951*fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
2952*fcf3ce44SJohn Forte 	impl_prop = impl_dev->prop_list;
2953*fcf3ce44SJohn Forte 
2954*fcf3ce44SJohn Forte 	err = L_INVALID_MAP_DEV_PROP_NAME;
2955*fcf3ce44SJohn Forte 
2956*fcf3ce44SJohn Forte 	while (impl_prop) {
2957*fcf3ce44SJohn Forte 	    if (strncmp(impl_prop->prop_name, prop_name,
2958*fcf3ce44SJohn Forte 		strlen(prop_name)) == 0) {
2959*fcf3ce44SJohn Forte 		if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
2960*fcf3ce44SJohn Forte 		    err = L_INVALID_MAP_DEV_PROP_TYPE;
2961*fcf3ce44SJohn Forte 		    break;
2962*fcf3ce44SJohn Forte 		}
2963*fcf3ce44SJohn Forte 		if (impl_prop->prop_data) {
2964*fcf3ce44SJohn Forte 		    *prop_data = (int *)(impl_prop->prop_data);
2965*fcf3ce44SJohn Forte 		    return (0);
2966*fcf3ce44SJohn Forte 		} else {
2967*fcf3ce44SJohn Forte 		    err = impl_prop->prop_error;
2968*fcf3ce44SJohn Forte 		}
2969*fcf3ce44SJohn Forte 		break;
2970*fcf3ce44SJohn Forte 	    }
2971*fcf3ce44SJohn Forte 	    impl_prop = impl_prop->next;
2972*fcf3ce44SJohn Forte 	}
2973*fcf3ce44SJohn Forte 
2974*fcf3ce44SJohn Forte 	return (err);
2975*fcf3ce44SJohn Forte }
2976*fcf3ce44SJohn Forte 
2977*fcf3ce44SJohn Forte /*
2978*fcf3ce44SJohn Forte  * This function passes back int type property.
2979*fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2980*fcf3ce44SJohn Forte  *
2981*fcf3ce44SJohn Forte  * return 0 if OK.
2982*fcf3ce44SJohn Forte  * return error code otherwise.
2983*fcf3ce44SJohn Forte  */
2984*fcf3ce44SJohn Forte int
2985*fcf3ce44SJohn Forte g_dev_prop_lookup_strings(
2986*fcf3ce44SJohn Forte 	gfc_dev_t map_dev,
2987*fcf3ce44SJohn Forte 	const char *prop_name,
2988*fcf3ce44SJohn Forte 	char **prop_data)
2989*fcf3ce44SJohn Forte {
2990*fcf3ce44SJohn Forte 	impl_map_dev_t *impl_dev;
2991*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
2992*fcf3ce44SJohn Forte 	int err;
2993*fcf3ce44SJohn Forte 
2994*fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2995*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2996*fcf3ce44SJohn Forte 	}
2997*fcf3ce44SJohn Forte 
2998*fcf3ce44SJohn Forte 	if ((prop_name == NULL) || (prop_data == NULL)) {
2999*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3000*fcf3ce44SJohn Forte 	}
3001*fcf3ce44SJohn Forte 
3002*fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
3003*fcf3ce44SJohn Forte 	impl_prop = impl_dev->prop_list;
3004*fcf3ce44SJohn Forte 
3005*fcf3ce44SJohn Forte 	err = L_INVALID_MAP_DEV_PROP_NAME;
3006*fcf3ce44SJohn Forte 
3007*fcf3ce44SJohn Forte 	while (impl_prop) {
3008*fcf3ce44SJohn Forte 	    if (strncmp(impl_prop->prop_name, prop_name,
3009*fcf3ce44SJohn Forte 		strlen(prop_name)) == 0) {
3010*fcf3ce44SJohn Forte 		if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3011*fcf3ce44SJohn Forte 		    err = L_INVALID_MAP_DEV_PROP_TYPE;
3012*fcf3ce44SJohn Forte 		    break;
3013*fcf3ce44SJohn Forte 		}
3014*fcf3ce44SJohn Forte 		if (impl_prop->prop_data) {
3015*fcf3ce44SJohn Forte 		    *prop_data = (char *)(impl_prop->prop_data);
3016*fcf3ce44SJohn Forte 		    return (0);
3017*fcf3ce44SJohn Forte 		} else {
3018*fcf3ce44SJohn Forte 		    err = impl_prop->prop_error;
3019*fcf3ce44SJohn Forte 		}
3020*fcf3ce44SJohn Forte 		break;
3021*fcf3ce44SJohn Forte 	    }
3022*fcf3ce44SJohn Forte 	    impl_prop = impl_prop->next;
3023*fcf3ce44SJohn Forte 	}
3024*fcf3ce44SJohn Forte 
3025*fcf3ce44SJohn Forte 	return (err);
3026*fcf3ce44SJohn Forte }
3027*fcf3ce44SJohn Forte 
3028*fcf3ce44SJohn Forte /*
3029*fcf3ce44SJohn Forte  * This function returns the handle for the first property of the input device.
3030*fcf3ce44SJohn Forte  * map_dev input should be a handle form a device.
3031*fcf3ce44SJohn Forte  *
3032*fcf3ce44SJohn Forte  * l_err set to 0 if OK.
3033*fcf3ce44SJohn Forte  * l_err set to error code otherwise.
3034*fcf3ce44SJohn Forte  */
3035*fcf3ce44SJohn Forte gfc_prop_t
3036*fcf3ce44SJohn Forte g_get_first_dev_prop(
3037*fcf3ce44SJohn Forte 	gfc_dev_t map_dev,
3038*fcf3ce44SJohn Forte 	int *l_err)
3039*fcf3ce44SJohn Forte {
3040*fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_dev;
3041*fcf3ce44SJohn Forte 
3042*fcf3ce44SJohn Forte 	if (l_err == NULL) {
3043*fcf3ce44SJohn Forte 		return (NULL);
3044*fcf3ce44SJohn Forte 	}
3045*fcf3ce44SJohn Forte 
3046*fcf3ce44SJohn Forte 	*l_err = 0;
3047*fcf3ce44SJohn Forte 
3048*fcf3ce44SJohn Forte 	if (map_dev == NULL) {
3049*fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_ADDR;
3050*fcf3ce44SJohn Forte 		return (NULL);
3051*fcf3ce44SJohn Forte 	}
3052*fcf3ce44SJohn Forte 
3053*fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
3054*fcf3ce44SJohn Forte 
3055*fcf3ce44SJohn Forte 	if (impl_dev->prop_list == NULL) {
3056*fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_PROP_FOUND;
3057*fcf3ce44SJohn Forte 	}
3058*fcf3ce44SJohn Forte 
3059*fcf3ce44SJohn Forte 	return ((gfc_prop_t)(impl_dev->prop_list));
3060*fcf3ce44SJohn Forte }
3061*fcf3ce44SJohn Forte 
3062*fcf3ce44SJohn Forte /*
3063*fcf3ce44SJohn Forte  * This function returns the handle for next property handle of the input prop.
3064*fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3065*fcf3ce44SJohn Forte  *
3066*fcf3ce44SJohn Forte  * l_err set to 0 if OK.
3067*fcf3ce44SJohn Forte  * l_err set to error code otherwise.
3068*fcf3ce44SJohn Forte  */
3069*fcf3ce44SJohn Forte gfc_prop_t
3070*fcf3ce44SJohn Forte g_get_next_dev_prop(
3071*fcf3ce44SJohn Forte 	gfc_prop_t map_prop,
3072*fcf3ce44SJohn Forte 	int *l_err)
3073*fcf3ce44SJohn Forte {
3074*fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*impl_prop;
3075*fcf3ce44SJohn Forte 
3076*fcf3ce44SJohn Forte 	if (l_err == NULL) {
3077*fcf3ce44SJohn Forte 		return (NULL);
3078*fcf3ce44SJohn Forte 	}
3079*fcf3ce44SJohn Forte 
3080*fcf3ce44SJohn Forte 	*l_err = 0;
3081*fcf3ce44SJohn Forte 
3082*fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3083*fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_PROP;
3084*fcf3ce44SJohn Forte 		return (NULL);
3085*fcf3ce44SJohn Forte 	}
3086*fcf3ce44SJohn Forte 
3087*fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3088*fcf3ce44SJohn Forte 
3089*fcf3ce44SJohn Forte 	if (impl_prop->next == NULL) {
3090*fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_PROP_FOUND;
3091*fcf3ce44SJohn Forte 	}
3092*fcf3ce44SJohn Forte 
3093*fcf3ce44SJohn Forte 	return ((gfc_prop_t)(impl_prop->next));
3094*fcf3ce44SJohn Forte }
3095*fcf3ce44SJohn Forte 
3096*fcf3ce44SJohn Forte /*
3097*fcf3ce44SJohn Forte  * This function returns the name of the property of the input prop.
3098*fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3099*fcf3ce44SJohn Forte  *
3100*fcf3ce44SJohn Forte  * return name string if OK.
3101*fcf3ce44SJohn Forte  * returns NULL and l_err set to error code otherwise.
3102*fcf3ce44SJohn Forte  */
3103*fcf3ce44SJohn Forte char *
3104*fcf3ce44SJohn Forte g_get_dev_prop_name(
3105*fcf3ce44SJohn Forte 	gfc_prop_t map_prop,
3106*fcf3ce44SJohn Forte 	int *l_err)
3107*fcf3ce44SJohn Forte {
3108*fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*impl_prop;
3109*fcf3ce44SJohn Forte 
3110*fcf3ce44SJohn Forte 	if (l_err == NULL) {
3111*fcf3ce44SJohn Forte 		return (NULL);
3112*fcf3ce44SJohn Forte 	}
3113*fcf3ce44SJohn Forte 
3114*fcf3ce44SJohn Forte 	*l_err = 0;
3115*fcf3ce44SJohn Forte 
3116*fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3117*fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_PROP;
3118*fcf3ce44SJohn Forte 		return (NULL);
3119*fcf3ce44SJohn Forte 	}
3120*fcf3ce44SJohn Forte 
3121*fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3122*fcf3ce44SJohn Forte 
3123*fcf3ce44SJohn Forte 	return (impl_prop->prop_name);
3124*fcf3ce44SJohn Forte }
3125*fcf3ce44SJohn Forte 
3126*fcf3ce44SJohn Forte /*
3127*fcf3ce44SJohn Forte  * This function returns the type of the property of the input prop.
3128*fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3129*fcf3ce44SJohn Forte  *
3130*fcf3ce44SJohn Forte  * return type if OK.
3131*fcf3ce44SJohn Forte  * returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise.
3132*fcf3ce44SJohn Forte  */
3133*fcf3ce44SJohn Forte int
3134*fcf3ce44SJohn Forte g_get_dev_prop_type(
3135*fcf3ce44SJohn Forte 	gfc_prop_t map_prop,
3136*fcf3ce44SJohn Forte 	int *l_err)
3137*fcf3ce44SJohn Forte {
3138*fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*impl_prop;
3139*fcf3ce44SJohn Forte 
3140*fcf3ce44SJohn Forte 	if (l_err != NULL) {
3141*fcf3ce44SJohn Forte 		*l_err = 0;
3142*fcf3ce44SJohn Forte 	} else {
3143*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3144*fcf3ce44SJohn Forte 	}
3145*fcf3ce44SJohn Forte 
3146*fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3147*fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_PROP;
3148*fcf3ce44SJohn Forte 		return (GFC_PROP_TYPE_UNKNOWN);
3149*fcf3ce44SJohn Forte 	}
3150*fcf3ce44SJohn Forte 
3151*fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3152*fcf3ce44SJohn Forte 
3153*fcf3ce44SJohn Forte 	return (impl_prop->prop_type);
3154*fcf3ce44SJohn Forte }
3155*fcf3ce44SJohn Forte 
3156*fcf3ce44SJohn Forte /*
3157*fcf3ce44SJohn Forte  * This function passes back uchar_t type property and its count.
3158*fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3159*fcf3ce44SJohn Forte  *
3160*fcf3ce44SJohn Forte  * return 0 if OK.
3161*fcf3ce44SJohn Forte  * return error code otherwise.
3162*fcf3ce44SJohn Forte  */
3163*fcf3ce44SJohn Forte int
3164*fcf3ce44SJohn Forte g_get_dev_prop_bytes(
3165*fcf3ce44SJohn Forte 	gfc_prop_t map_prop,
3166*fcf3ce44SJohn Forte 	int *prop_data_count,
3167*fcf3ce44SJohn Forte 	uchar_t **prop_data)
3168*fcf3ce44SJohn Forte {
3169*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3170*fcf3ce44SJohn Forte 
3171*fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3172*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3173*fcf3ce44SJohn Forte 	}
3174*fcf3ce44SJohn Forte 
3175*fcf3ce44SJohn Forte 	if ((prop_data == NULL) || (prop_data_count == NULL)) {
3176*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3177*fcf3ce44SJohn Forte 	}
3178*fcf3ce44SJohn Forte 
3179*fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3180*fcf3ce44SJohn Forte 
3181*fcf3ce44SJohn Forte 	if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
3182*fcf3ce44SJohn Forte 		    return (L_INVALID_MAP_DEV_PROP_TYPE);
3183*fcf3ce44SJohn Forte 	}
3184*fcf3ce44SJohn Forte 	if (impl_prop->prop_data) {
3185*fcf3ce44SJohn Forte 	    *prop_data = (uchar_t *)(impl_prop->prop_data);
3186*fcf3ce44SJohn Forte 	    *prop_data_count = impl_prop->prop_size;
3187*fcf3ce44SJohn Forte 	} else {
3188*fcf3ce44SJohn Forte 	    return (impl_prop->prop_error);
3189*fcf3ce44SJohn Forte 	}
3190*fcf3ce44SJohn Forte 
3191*fcf3ce44SJohn Forte 	return (0);
3192*fcf3ce44SJohn Forte }
3193*fcf3ce44SJohn Forte 
3194*fcf3ce44SJohn Forte /*
3195*fcf3ce44SJohn Forte  * This function passes back int type property.
3196*fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3197*fcf3ce44SJohn Forte  *
3198*fcf3ce44SJohn Forte  * return 0 if OK.
3199*fcf3ce44SJohn Forte  * return error code otherwise.
3200*fcf3ce44SJohn Forte  */
3201*fcf3ce44SJohn Forte int
3202*fcf3ce44SJohn Forte g_get_dev_prop_ints(
3203*fcf3ce44SJohn Forte 	gfc_prop_t map_prop,
3204*fcf3ce44SJohn Forte 	int **prop_data)
3205*fcf3ce44SJohn Forte {
3206*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3207*fcf3ce44SJohn Forte 
3208*fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3209*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3210*fcf3ce44SJohn Forte 	}
3211*fcf3ce44SJohn Forte 
3212*fcf3ce44SJohn Forte 	if (prop_data == NULL) {
3213*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3214*fcf3ce44SJohn Forte 	}
3215*fcf3ce44SJohn Forte 
3216*fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3217*fcf3ce44SJohn Forte 
3218*fcf3ce44SJohn Forte 	if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3219*fcf3ce44SJohn Forte 		    return (L_INVALID_MAP_DEV_PROP_TYPE);
3220*fcf3ce44SJohn Forte 	}
3221*fcf3ce44SJohn Forte 	if (impl_prop->prop_data) {
3222*fcf3ce44SJohn Forte 	    *prop_data = (int *)(impl_prop->prop_data);
3223*fcf3ce44SJohn Forte 	} else {
3224*fcf3ce44SJohn Forte 	    return (impl_prop->prop_error);
3225*fcf3ce44SJohn Forte 	}
3226*fcf3ce44SJohn Forte 
3227*fcf3ce44SJohn Forte 	return (0);
3228*fcf3ce44SJohn Forte }
3229*fcf3ce44SJohn Forte 
3230*fcf3ce44SJohn Forte /*
3231*fcf3ce44SJohn Forte  * This function passes back string type property.
3232*fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3233*fcf3ce44SJohn Forte  *
3234*fcf3ce44SJohn Forte  * return 0 if OK.
3235*fcf3ce44SJohn Forte  * return error code otherwise.
3236*fcf3ce44SJohn Forte  */
3237*fcf3ce44SJohn Forte int
3238*fcf3ce44SJohn Forte g_get_dev_prop_strings(
3239*fcf3ce44SJohn Forte 	gfc_prop_t map_prop,
3240*fcf3ce44SJohn Forte 	char **prop_data)
3241*fcf3ce44SJohn Forte {
3242*fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3243*fcf3ce44SJohn Forte 
3244*fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3245*fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3246*fcf3ce44SJohn Forte 	}
3247*fcf3ce44SJohn Forte 
3248*fcf3ce44SJohn Forte 	if (prop_data == NULL) {
3249*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3250*fcf3ce44SJohn Forte 	}
3251*fcf3ce44SJohn Forte 
3252*fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3253*fcf3ce44SJohn Forte 
3254*fcf3ce44SJohn Forte 	if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3255*fcf3ce44SJohn Forte 		    return (L_INVALID_MAP_DEV_PROP_TYPE);
3256*fcf3ce44SJohn Forte 	}
3257*fcf3ce44SJohn Forte 	if (impl_prop->prop_data) {
3258*fcf3ce44SJohn Forte 	    *prop_data = (char *)(impl_prop->prop_data);
3259*fcf3ce44SJohn Forte 	} else {
3260*fcf3ce44SJohn Forte 	    return (impl_prop->prop_error);
3261*fcf3ce44SJohn Forte 	}
3262*fcf3ce44SJohn Forte 
3263*fcf3ce44SJohn Forte 	return (0);
3264*fcf3ce44SJohn Forte }
3265*fcf3ce44SJohn Forte 
3266*fcf3ce44SJohn Forte /*
3267*fcf3ce44SJohn Forte  * Free the linked list allocated by g_rdls()
3268*fcf3ce44SJohn Forte  */
3269*fcf3ce44SJohn Forte static void
3270*fcf3ce44SJohn Forte g_free_rls(AL_rls *rlsptr)
3271*fcf3ce44SJohn Forte {
3272*fcf3ce44SJohn Forte 	AL_rls *trlsptr;
3273*fcf3ce44SJohn Forte 
3274*fcf3ce44SJohn Forte 	while (rlsptr != NULL) {
3275*fcf3ce44SJohn Forte 		trlsptr = rlsptr->next;
3276*fcf3ce44SJohn Forte 		free(rlsptr);
3277*fcf3ce44SJohn Forte 		rlsptr = trlsptr;
3278*fcf3ce44SJohn Forte 	}
3279*fcf3ce44SJohn Forte }
3280*fcf3ce44SJohn Forte 
3281*fcf3ce44SJohn Forte /*
3282*fcf3ce44SJohn Forte  * Read the extended link error status block
3283*fcf3ce44SJohn Forte  * from the specified device and Host Adapter.
3284*fcf3ce44SJohn Forte  *
3285*fcf3ce44SJohn Forte  * PARAMS:
3286*fcf3ce44SJohn Forte  *	path_phys - physical path to an FC device
3287*fcf3ce44SJohn Forte  *	rls_ptr   - pointer to read link state structure
3288*fcf3ce44SJohn Forte  *
3289*fcf3ce44SJohn Forte  * RETURNS:
3290*fcf3ce44SJohn Forte  *	0	: if OK
3291*fcf3ce44SJohn Forte  *	non-zero: otherwise
3292*fcf3ce44SJohn Forte  */
3293*fcf3ce44SJohn Forte int
3294*fcf3ce44SJohn Forte g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose)
3295*fcf3ce44SJohn Forte {
3296*fcf3ce44SJohn Forte char		nexus_path[MAXPATHLEN], *nexus_path_ptr;
3297*fcf3ce44SJohn Forte int		fd, fp_fd, err, length, exp_map_flag = 0, *port_addr;
3298*fcf3ce44SJohn Forte struct lilpmap	map;
3299*fcf3ce44SJohn Forte AL_rls		*rls, *c1 = NULL, *c2 = NULL;
3300*fcf3ce44SJohn Forte uchar_t		i, *port_wwn_byte;
3301*fcf3ce44SJohn Forte la_wwn_t	port_wwn;
3302*fcf3ce44SJohn Forte sf_al_map_t	exp_map;
3303*fcf3ce44SJohn Forte char		*charPtr, fp_path[MAXPATHLEN];
3304*fcf3ce44SJohn Forte uint_t		dev_type;
3305*fcf3ce44SJohn Forte struct stat	stbuf;
3306*fcf3ce44SJohn Forte fcio_t		fcio;
3307*fcf3ce44SJohn Forte fc_portid_t	rls_req;
3308*fcf3ce44SJohn Forte fc_rls_acc_t	rls_payload;
3309*fcf3ce44SJohn Forte gfc_dev_t	map_root, map_dev;
3310*fcf3ce44SJohn Forte uint32_t	hba_port_top, state;
3311*fcf3ce44SJohn Forte int		pathcnt = 1, count;
3312*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
3313*fcf3ce44SJohn Forte int		p_on = 0, p_st = 0;
3314*fcf3ce44SJohn Forte 
3315*fcf3ce44SJohn Forte 	/* return invalid path if path_phys is NULL */
3316*fcf3ce44SJohn Forte 	if (path_phys == NULL) {
3317*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3318*fcf3ce44SJohn Forte 	}
3319*fcf3ce44SJohn Forte 	/* return invalid arg if rls_ptr is NULL */
3320*fcf3ce44SJohn Forte 	if (rls_ptr == NULL) {
3321*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3322*fcf3ce44SJohn Forte 	}
3323*fcf3ce44SJohn Forte 
3324*fcf3ce44SJohn Forte 	*rls_ptr = rls = NULL;
3325*fcf3ce44SJohn Forte 
3326*fcf3ce44SJohn Forte 	if (strstr(path_phys, SCSI_VHCI) != NULL) {
3327*fcf3ce44SJohn Forte 		(void) strcpy(fp_path, path_phys);
3328*fcf3ce44SJohn Forte 		if (g_get_pathlist(fp_path, &pathlist)) {
3329*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
3330*fcf3ce44SJohn Forte 		}
3331*fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
3332*fcf3ce44SJohn Forte 		p_on = p_st = 0;
3333*fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
3334*fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3335*fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
3336*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_ONLINE) {
3337*fcf3ce44SJohn Forte 					p_on = i;
3338*fcf3ce44SJohn Forte 					break;
3339*fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
3340*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_STANDBY) {
3341*fcf3ce44SJohn Forte 					p_st = i;
3342*fcf3ce44SJohn Forte 				}
3343*fcf3ce44SJohn Forte 			}
3344*fcf3ce44SJohn Forte 		}
3345*fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
3346*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
3347*fcf3ce44SJohn Forte 			/* on_line path */
3348*fcf3ce44SJohn Forte 			(void) strcpy(fp_path,
3349*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_hba);
3350*fcf3ce44SJohn Forte 		} else {
3351*fcf3ce44SJohn Forte 			/* standby or path0 */
3352*fcf3ce44SJohn Forte 			(void) strcpy(fp_path,
3353*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_hba);
3354*fcf3ce44SJohn Forte 		}
3355*fcf3ce44SJohn Forte 		free(pathlist.path_info);
3356*fcf3ce44SJohn Forte 	} else {
3357*fcf3ce44SJohn Forte 		(void) strcpy(fp_path, path_phys);
3358*fcf3ce44SJohn Forte 	}
3359*fcf3ce44SJohn Forte 
3360*fcf3ce44SJohn Forte 	/* Get map of devices on this loop. */
3361*fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(fp_path)) == 0) {
3362*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3363*fcf3ce44SJohn Forte 	}
3364*fcf3ce44SJohn Forte 	if (dev_type & FC_FCA_MASK) {
3365*fcf3ce44SJohn Forte 		if (strstr(path_phys, SCSI_VHCI) != NULL) {
3366*fcf3ce44SJohn Forte 			(void) strcat(fp_path, FC_CTLR);
3367*fcf3ce44SJohn Forte 		} else if (strstr(fp_path, DRV_NAME_SSD) ||
3368*fcf3ce44SJohn Forte 		    strstr(fp_path, DRV_NAME_ST) ||
3369*fcf3ce44SJohn Forte 				strstr(fp_path, SES_NAME)) {
3370*fcf3ce44SJohn Forte 			if ((charPtr = strrchr(fp_path, '/')) == NULL) {
3371*fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
3372*fcf3ce44SJohn Forte 			}
3373*fcf3ce44SJohn Forte 			*charPtr = '\0';
3374*fcf3ce44SJohn Forte 			/* append devctl to the path */
3375*fcf3ce44SJohn Forte 			(void) strcat(fp_path, FC_CTLR);
3376*fcf3ce44SJohn Forte 		} else {
3377*fcf3ce44SJohn Forte 			if (stat(fp_path, &stbuf) < 0) {
3378*fcf3ce44SJohn Forte 				return (L_LSTAT_ERROR);
3379*fcf3ce44SJohn Forte 			}
3380*fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
3381*fcf3ce44SJohn Forte 				/* append devctl to the path */
3382*fcf3ce44SJohn Forte 				(void) strcat(fp_path, FC_CTLR);
3383*fcf3ce44SJohn Forte 			}
3384*fcf3ce44SJohn Forte 		}
3385*fcf3ce44SJohn Forte 
3386*fcf3ce44SJohn Forte 		if ((map_root = g_dev_map_init(fp_path, &err,
3387*fcf3ce44SJohn Forte 			MAP_XPORT_PROP_ONLY)) == NULL) {
3388*fcf3ce44SJohn Forte 			return (err);
3389*fcf3ce44SJohn Forte 		}
3390*fcf3ce44SJohn Forte 
3391*fcf3ce44SJohn Forte 	} else { /* FC4_FCA_MASK type path */
3392*fcf3ce44SJohn Forte 	    (void) memset(&map, 0, sizeof (struct lilpmap));
3393*fcf3ce44SJohn Forte 
3394*fcf3ce44SJohn Forte 	    if ((err = g_get_nexus_path(path_phys,
3395*fcf3ce44SJohn Forte 		    &nexus_path_ptr)) != 0) {
3396*fcf3ce44SJohn Forte 		return (err);
3397*fcf3ce44SJohn Forte 	    }
3398*fcf3ce44SJohn Forte 	    (void) strcpy(nexus_path, nexus_path_ptr);
3399*fcf3ce44SJohn Forte 	    g_destroy_data(nexus_path_ptr);
3400*fcf3ce44SJohn Forte 
3401*fcf3ce44SJohn Forte 		/* open driver */
3402*fcf3ce44SJohn Forte 	    if ((fd = g_object_open(nexus_path,
3403*fcf3ce44SJohn Forte 			O_NDELAY | O_RDONLY)) == -1)
3404*fcf3ce44SJohn Forte 		return (errno);
3405*fcf3ce44SJohn Forte 
3406*fcf3ce44SJohn Forte 		/*
3407*fcf3ce44SJohn Forte 		 * First try using the socal version of the map.
3408*fcf3ce44SJohn Forte 		 * If that fails get the expanded vesion.
3409*fcf3ce44SJohn Forte 		 */
3410*fcf3ce44SJohn Forte 	    if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
3411*fcf3ce44SJohn Forte 		I_DPRINTF("  FCIO_GETMAP ioctl failed.\n");
3412*fcf3ce44SJohn Forte 		if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) {
3413*fcf3ce44SJohn Forte 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
3414*fcf3ce44SJohn Forte 			(void) close(fd);
3415*fcf3ce44SJohn Forte 			return (L_SFIOCGMAP_IOCTL_FAIL);
3416*fcf3ce44SJohn Forte 		}
3417*fcf3ce44SJohn Forte 		/* Check for reasonableness. */
3418*fcf3ce44SJohn Forte 		if ((exp_map.sf_count > 126) ||
3419*fcf3ce44SJohn Forte 				(exp_map.sf_count < 0)) {
3420*fcf3ce44SJohn Forte 			(void) close(fd);
3421*fcf3ce44SJohn Forte 			return (L_INVALID_LOOP_MAP);
3422*fcf3ce44SJohn Forte 		}
3423*fcf3ce44SJohn Forte 		for (i = 0; i < exp_map.sf_count; i++) {
3424*fcf3ce44SJohn Forte 			if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) {
3425*fcf3ce44SJohn Forte 				(void) close(fd);
3426*fcf3ce44SJohn Forte 				return (L_INVALID_LOOP_MAP);
3427*fcf3ce44SJohn Forte 			}
3428*fcf3ce44SJohn Forte 		}
3429*fcf3ce44SJohn Forte 		length = exp_map.sf_count;
3430*fcf3ce44SJohn Forte 		exp_map_flag++;
3431*fcf3ce44SJohn Forte 	    } else {
3432*fcf3ce44SJohn Forte 		I_DPRINTF("  g_rdls:"
3433*fcf3ce44SJohn Forte 			" FCIO_GETMAP ioctl returned %d entries.\n",
3434*fcf3ce44SJohn Forte 			map.lilp_length);
3435*fcf3ce44SJohn Forte 		/* Check for reasonableness. */
3436*fcf3ce44SJohn Forte 		if (map.lilp_length > sizeof (map.lilp_list)) {
3437*fcf3ce44SJohn Forte 			(void) close(fd);
3438*fcf3ce44SJohn Forte 			return (L_FCIOGETMAP_INVLD_LEN);
3439*fcf3ce44SJohn Forte 		}
3440*fcf3ce44SJohn Forte 		length = map.lilp_length;
3441*fcf3ce44SJohn Forte 	    }
3442*fcf3ce44SJohn Forte 	    for (i = 0; i < length; i++) {
3443*fcf3ce44SJohn Forte 		if ((c2 = (struct al_rls *)
3444*fcf3ce44SJohn Forte 			g_zalloc(sizeof (struct al_rls))) == NULL) {
3445*fcf3ce44SJohn Forte 			close(fd);
3446*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
3447*fcf3ce44SJohn Forte 		}
3448*fcf3ce44SJohn Forte 		if (rls == NULL) {
3449*fcf3ce44SJohn Forte 			c1 = rls = c2;
3450*fcf3ce44SJohn Forte 		} else {
3451*fcf3ce44SJohn Forte 			for (c1 = rls; c1->next; c1 =  c1->next) {};
3452*fcf3ce44SJohn Forte 			c1 = c1->next = c2;
3453*fcf3ce44SJohn Forte 		}
3454*fcf3ce44SJohn Forte 		(void) strcpy(c1->driver_path, nexus_path);
3455*fcf3ce44SJohn Forte 		if (exp_map_flag) {
3456*fcf3ce44SJohn Forte 			c1->payload.rls_portno = c1->al_ha =
3457*fcf3ce44SJohn Forte 				exp_map.sf_addr_pair[i].sf_al_pa;
3458*fcf3ce44SJohn Forte 		} else {
3459*fcf3ce44SJohn Forte 			c1->payload.rls_portno = c1->al_ha = map.lilp_list[i];
3460*fcf3ce44SJohn Forte 		}
3461*fcf3ce44SJohn Forte 		c1->payload.rls_linkfail =
3462*fcf3ce44SJohn Forte 				(uint_t)0xff000000; /* get LESB for this port */
3463*fcf3ce44SJohn Forte 		I_DPRINTF("  g_rdls:" " al_pa 0x%x\n", c1->payload.rls_portno);
3464*fcf3ce44SJohn Forte 
3465*fcf3ce44SJohn Forte 		if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) {
3466*fcf3ce44SJohn Forte 			/*
3467*fcf3ce44SJohn Forte 			 * The ifp driver will return ENXIO when rls
3468*fcf3ce44SJohn Forte 			 * is issued for same initiator on loop when
3469*fcf3ce44SJohn Forte 			 * there is more than one on the loop.
3470*fcf3ce44SJohn Forte 			 * Rather than completely fail, continue on.
3471*fcf3ce44SJohn Forte 			 * Set values in the payload struct to -1 as
3472*fcf3ce44SJohn Forte 			 * this is what socal is currently doing for
3473*fcf3ce44SJohn Forte 			 * the case of same initiator rls.
3474*fcf3ce44SJohn Forte 			 */
3475*fcf3ce44SJohn Forte 			if ((dev_type & FC4_PCI_FCA) && (errno == ENXIO)) {
3476*fcf3ce44SJohn Forte 				c1->payload.rls_linkfail =
3477*fcf3ce44SJohn Forte 				c1->payload.rls_syncfail =
3478*fcf3ce44SJohn Forte 				c1->payload.rls_sigfail =
3479*fcf3ce44SJohn Forte 				c1->payload.rls_primitiverr =
3480*fcf3ce44SJohn Forte 				c1->payload.rls_invalidword =
3481*fcf3ce44SJohn Forte 				c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3482*fcf3ce44SJohn Forte 			} else {
3483*fcf3ce44SJohn Forte 				I_DPRINTF("  FCIO_LINKSTATUS ioctl"
3484*fcf3ce44SJohn Forte 				" failed with errno %d.\n", errno);
3485*fcf3ce44SJohn Forte 				g_free_rls(rls);
3486*fcf3ce44SJohn Forte 				(void) close(fd);
3487*fcf3ce44SJohn Forte 				return (L_FCIO_LINKSTATUS_FAILED);
3488*fcf3ce44SJohn Forte 			}
3489*fcf3ce44SJohn Forte 		}
3490*fcf3ce44SJohn Forte 		I_DPRINTF("  g_rdls: al_pa returned by ioctl 0x%x\n",
3491*fcf3ce44SJohn Forte 			c1->payload.rls_portno);
3492*fcf3ce44SJohn Forte 	    }
3493*fcf3ce44SJohn Forte 	    *rls_ptr = rls; /* Pass back pointer */
3494*fcf3ce44SJohn Forte 
3495*fcf3ce44SJohn Forte 	    (void) close(fd);
3496*fcf3ce44SJohn Forte 	    return (0);
3497*fcf3ce44SJohn Forte 	}
3498*fcf3ce44SJohn Forte 
3499*fcf3ce44SJohn Forte 	/* Now we need to take care of FC_FCA_MASK case.	*/
3500*fcf3ce44SJohn Forte 	/* we have map created already via g_dev_map_init.	*/
3501*fcf3ce44SJohn Forte 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3502*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3503*fcf3ce44SJohn Forte 		return (err);
3504*fcf3ce44SJohn Forte 	}
3505*fcf3ce44SJohn Forte 
3506*fcf3ce44SJohn Forte 	if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
3507*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3508*fcf3ce44SJohn Forte 		if (err != L_NO_SUCH_DEV_FOUND) {
3509*fcf3ce44SJohn Forte 			return (err);
3510*fcf3ce44SJohn Forte 		} else {
3511*fcf3ce44SJohn Forte 			return (L_NO_DEVICES_FOUND);
3512*fcf3ce44SJohn Forte 		}
3513*fcf3ce44SJohn Forte 	}
3514*fcf3ce44SJohn Forte 
3515*fcf3ce44SJohn Forte 	while (map_dev) {
3516*fcf3ce44SJohn Forte 	    if ((err = g_dev_prop_lookup_ints(
3517*fcf3ce44SJohn Forte 		map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3518*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3519*fcf3ce44SJohn Forte 		g_free_rls(rls);
3520*fcf3ce44SJohn Forte 		return (err);
3521*fcf3ce44SJohn Forte 	    }
3522*fcf3ce44SJohn Forte 
3523*fcf3ce44SJohn Forte 	    if ((c2 = (struct al_rls *)
3524*fcf3ce44SJohn Forte 		g_zalloc(sizeof (struct al_rls))) == NULL) {
3525*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3526*fcf3ce44SJohn Forte 		g_free_rls(rls);
3527*fcf3ce44SJohn Forte 		close(fd);
3528*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
3529*fcf3ce44SJohn Forte 	    }
3530*fcf3ce44SJohn Forte 	    if (rls == NULL) {
3531*fcf3ce44SJohn Forte 		c1 = rls = c2;
3532*fcf3ce44SJohn Forte 	    } else {
3533*fcf3ce44SJohn Forte 		for (c1 = rls; c1->next; c1 =  c1->next) {};
3534*fcf3ce44SJohn Forte 		c1 = c1->next = c2;
3535*fcf3ce44SJohn Forte 	    }
3536*fcf3ce44SJohn Forte 	    /* Set the al_ha here */
3537*fcf3ce44SJohn Forte 	    c1->al_ha = rls_req.port_id = *port_addr;
3538*fcf3ce44SJohn Forte 
3539*fcf3ce44SJohn Forte 		/*
3540*fcf3ce44SJohn Forte 		 * fp uses different input/output structures for
3541*fcf3ce44SJohn Forte 		 * rls. Load the values returned for the fp ioctl
3542*fcf3ce44SJohn Forte 		 * into the structure passed back to the caller
3543*fcf3ce44SJohn Forte 		 * Note: There is no reason for the path
3544*fcf3ce44SJohn Forte 		 * to be loaded into AL_rls as is done for socal/ifp
3545*fcf3ce44SJohn Forte 		 * above.
3546*fcf3ce44SJohn Forte 		 */
3547*fcf3ce44SJohn Forte 	    if ((hba_port_top == FC_TOP_FABRIC) ||
3548*fcf3ce44SJohn Forte 		(hba_port_top == FC_TOP_PUBLIC_LOOP)) {
3549*fcf3ce44SJohn Forte 		if ((err = g_dev_prop_lookup_bytes(
3550*fcf3ce44SJohn Forte 			map_dev, PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) {
3551*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3552*fcf3ce44SJohn Forte 			g_free_rls(rls);
3553*fcf3ce44SJohn Forte 			return (err);
3554*fcf3ce44SJohn Forte 		}
3555*fcf3ce44SJohn Forte 		memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE);
3556*fcf3ce44SJohn Forte 		if ((err = g_get_dev_port_state(
3557*fcf3ce44SJohn Forte 			fp_path, port_wwn, &state)) == 0) {
3558*fcf3ce44SJohn Forte 		    if (state != PORT_DEVICE_LOGGED_IN) {
3559*fcf3ce44SJohn Forte 			if ((err = g_dev_login(fp_path, port_wwn)) != 0) {
3560*fcf3ce44SJohn Forte 				c1->payload.rls_linkfail =
3561*fcf3ce44SJohn Forte 				c1->payload.rls_syncfail =
3562*fcf3ce44SJohn Forte 				c1->payload.rls_sigfail =
3563*fcf3ce44SJohn Forte 				c1->payload.rls_primitiverr =
3564*fcf3ce44SJohn Forte 				c1->payload.rls_invalidword =
3565*fcf3ce44SJohn Forte 				c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3566*fcf3ce44SJohn Forte 				if (((map_dev =
3567*fcf3ce44SJohn Forte 					g_get_next_dev(map_dev, &err))
3568*fcf3ce44SJohn Forte 					== NULL) &&
3569*fcf3ce44SJohn Forte 					(err != L_NO_SUCH_DEV_FOUND)) {
3570*fcf3ce44SJohn Forte 					g_dev_map_fini(map_root);
3571*fcf3ce44SJohn Forte 					g_free_rls(rls);
3572*fcf3ce44SJohn Forte 					return (err);
3573*fcf3ce44SJohn Forte 				}
3574*fcf3ce44SJohn Forte 				continue;
3575*fcf3ce44SJohn Forte 			}
3576*fcf3ce44SJohn Forte 		    }
3577*fcf3ce44SJohn Forte 		} /* if g_get_dev_port_state fails proceed. */
3578*fcf3ce44SJohn Forte 	    }
3579*fcf3ce44SJohn Forte 
3580*fcf3ce44SJohn Forte 	    fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3581*fcf3ce44SJohn Forte 	    if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3582*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3583*fcf3ce44SJohn Forte 		g_free_rls(rls);
3584*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
3585*fcf3ce44SJohn Forte 	    }
3586*fcf3ce44SJohn Forte 	    fcio.fcio_cmd = FCIO_LINK_STATUS;
3587*fcf3ce44SJohn Forte 	    fcio.fcio_ibuf = (caddr_t)&rls_req;
3588*fcf3ce44SJohn Forte 	    fcio.fcio_ilen = sizeof (rls_req);
3589*fcf3ce44SJohn Forte 	    fcio.fcio_xfer = FCIO_XFER_RW;
3590*fcf3ce44SJohn Forte 	    fcio.fcio_flags = 0;
3591*fcf3ce44SJohn Forte 	    fcio.fcio_obuf = (caddr_t)&rls_payload;
3592*fcf3ce44SJohn Forte 	    fcio.fcio_olen = sizeof (rls_payload);
3593*fcf3ce44SJohn Forte 	    if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3594*fcf3ce44SJohn Forte 		c1->payload.rls_linkfail =
3595*fcf3ce44SJohn Forte 		c1->payload.rls_syncfail =
3596*fcf3ce44SJohn Forte 		c1->payload.rls_sigfail =
3597*fcf3ce44SJohn Forte 		c1->payload.rls_primitiverr =
3598*fcf3ce44SJohn Forte 		c1->payload.rls_invalidword =
3599*fcf3ce44SJohn Forte 		c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3600*fcf3ce44SJohn Forte 	    } else {
3601*fcf3ce44SJohn Forte 		/*
3602*fcf3ce44SJohn Forte 		 * Load the values into the struct passed
3603*fcf3ce44SJohn Forte 		 * back to the caller
3604*fcf3ce44SJohn Forte 		 */
3605*fcf3ce44SJohn Forte 		c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3606*fcf3ce44SJohn Forte 		c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3607*fcf3ce44SJohn Forte 		c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3608*fcf3ce44SJohn Forte 		c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err;
3609*fcf3ce44SJohn Forte 		c1->payload.rls_invalidword = rls_payload.rls_invalid_word;
3610*fcf3ce44SJohn Forte 		c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc;
3611*fcf3ce44SJohn Forte 	    }
3612*fcf3ce44SJohn Forte 	    (void) close(fp_fd);
3613*fcf3ce44SJohn Forte 
3614*fcf3ce44SJohn Forte 	    if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3615*fcf3ce44SJohn Forte 		(err != L_NO_SUCH_DEV_FOUND)) {
3616*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3617*fcf3ce44SJohn Forte 		g_free_rls(rls);
3618*fcf3ce44SJohn Forte 		return (err);
3619*fcf3ce44SJohn Forte 	    }
3620*fcf3ce44SJohn Forte 	}
3621*fcf3ce44SJohn Forte 
3622*fcf3ce44SJohn Forte 	/* for Leadville issue a final call for the initiator */
3623*fcf3ce44SJohn Forte 
3624*fcf3ce44SJohn Forte 	if ((err = g_dev_prop_lookup_ints(
3625*fcf3ce44SJohn Forte 		map_root, PORT_ADDR_PROP, &port_addr)) != 0) {
3626*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3627*fcf3ce44SJohn Forte 		g_free_rls(rls);
3628*fcf3ce44SJohn Forte 		return (err);
3629*fcf3ce44SJohn Forte 	}
3630*fcf3ce44SJohn Forte 
3631*fcf3ce44SJohn Forte 	if ((c2 = (struct al_rls *)
3632*fcf3ce44SJohn Forte 		g_zalloc(sizeof (struct al_rls))) == NULL) {
3633*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3634*fcf3ce44SJohn Forte 		g_free_rls(rls);
3635*fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
3636*fcf3ce44SJohn Forte 	}
3637*fcf3ce44SJohn Forte 	if (rls == NULL) {
3638*fcf3ce44SJohn Forte 		c1 = rls = c2;
3639*fcf3ce44SJohn Forte 	} else {
3640*fcf3ce44SJohn Forte 		for (c1 = rls; c1->next; c1 =  c1->next) {};
3641*fcf3ce44SJohn Forte 		c1 = c1->next = c2;
3642*fcf3ce44SJohn Forte 	}
3643*fcf3ce44SJohn Forte 
3644*fcf3ce44SJohn Forte 	c1->al_ha = rls_req.port_id = *port_addr;
3645*fcf3ce44SJohn Forte 
3646*fcf3ce44SJohn Forte 	if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3647*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3648*fcf3ce44SJohn Forte 		g_free_rls(rls);
3649*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
3650*fcf3ce44SJohn Forte 	}
3651*fcf3ce44SJohn Forte 
3652*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_LINK_STATUS;
3653*fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)&rls_req;
3654*fcf3ce44SJohn Forte 	fcio.fcio_ilen = sizeof (rls_req);
3655*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_RW;
3656*fcf3ce44SJohn Forte 	fcio.fcio_flags = 0;
3657*fcf3ce44SJohn Forte 	fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3658*fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)&rls_payload;
3659*fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (rls_payload);
3660*fcf3ce44SJohn Forte 
3661*fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3662*fcf3ce44SJohn Forte 		c1->payload.rls_linkfail =
3663*fcf3ce44SJohn Forte 		c1->payload.rls_syncfail =
3664*fcf3ce44SJohn Forte 		c1->payload.rls_sigfail =
3665*fcf3ce44SJohn Forte 		c1->payload.rls_primitiverr =
3666*fcf3ce44SJohn Forte 		c1->payload.rls_invalidword =
3667*fcf3ce44SJohn Forte 		c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3668*fcf3ce44SJohn Forte 	} else {
3669*fcf3ce44SJohn Forte 		/*
3670*fcf3ce44SJohn Forte 		 * Load the values into the struct passed
3671*fcf3ce44SJohn Forte 		 * back to the caller
3672*fcf3ce44SJohn Forte 		 */
3673*fcf3ce44SJohn Forte 		c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3674*fcf3ce44SJohn Forte 		c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3675*fcf3ce44SJohn Forte 		c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3676*fcf3ce44SJohn Forte 		c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err;
3677*fcf3ce44SJohn Forte 		c1->payload.rls_invalidword = rls_payload.rls_invalid_word;
3678*fcf3ce44SJohn Forte 		c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc;
3679*fcf3ce44SJohn Forte 		(void) close(fp_fd);
3680*fcf3ce44SJohn Forte 	}
3681*fcf3ce44SJohn Forte 	(void) close(fp_fd);
3682*fcf3ce44SJohn Forte 
3683*fcf3ce44SJohn Forte 	*rls_ptr = rls;	/* Pass back pointer */
3684*fcf3ce44SJohn Forte 
3685*fcf3ce44SJohn Forte 	g_dev_map_fini(map_root);
3686*fcf3ce44SJohn Forte 	return (0);
3687*fcf3ce44SJohn Forte }
3688*fcf3ce44SJohn Forte 
3689*fcf3ce44SJohn Forte static u_longlong_t wwnConversion(uchar_t *wwn)
3690*fcf3ce44SJohn Forte {
3691*fcf3ce44SJohn Forte 	u_longlong_t tmp;
3692*fcf3ce44SJohn Forte 	memcpy(&tmp, wwn, sizeof (u_longlong_t));
3693*fcf3ce44SJohn Forte 	return (tmp);
3694*fcf3ce44SJohn Forte }
3695*fcf3ce44SJohn Forte 
3696*fcf3ce44SJohn Forte /*
3697*fcf3ce44SJohn Forte  * Get device World Wide Name (port and node) for device at path
3698*fcf3ce44SJohn Forte  * and add all WWNs to the wwn_list_found list.
3699*fcf3ce44SJohn Forte  *
3700*fcf3ce44SJohn Forte  * RETURN: 0 O.K.
3701*fcf3ce44SJohn Forte  *
3702*fcf3ce44SJohn Forte  * INPUTS:
3703*fcf3ce44SJohn Forte  *	- path_phys must be of a device, either an IB or disk.
3704*fcf3ce44SJohn Forte  */
3705*fcf3ce44SJohn Forte static int
3706*fcf3ce44SJohn Forte get_wwns(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], int *al_pa,
3707*fcf3ce44SJohn Forte 	struct wwn_list_found_struct **wwn_list_found)
3708*fcf3ce44SJohn Forte {
3709*fcf3ce44SJohn Forte uint32_t	hba_port_top;
3710*fcf3ce44SJohn Forte int		i, err, count;
3711*fcf3ce44SJohn Forte char		*char_ptr, *ptr;
3712*fcf3ce44SJohn Forte int		found = 0, pathcnt, *port_addr;
3713*fcf3ce44SJohn Forte unsigned long long 	pwwn;
3714*fcf3ce44SJohn Forte uchar_t			*port_wwn_byte, *node_wwn_byte;
3715*fcf3ce44SJohn Forte char		drvr_path[MAXPATHLEN];
3716*fcf3ce44SJohn Forte int		p_on = 0, p_st = 0;
3717*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
3718*fcf3ce44SJohn Forte char		pwwn1[WWN_S_LEN];
3719*fcf3ce44SJohn Forte gfc_dev_t	map_root, map_dev;
3720*fcf3ce44SJohn Forte hrtime_t	start_time, end_time;
3721*fcf3ce44SJohn Forte char *env = NULL;
3722*fcf3ce44SJohn Forte 
3723*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_wwn: Getting device WWN"
3724*fcf3ce44SJohn Forte 			" and al_pa for device: %s\n",
3725*fcf3ce44SJohn Forte 			path_phys);
3726*fcf3ce44SJohn Forte 
3727*fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
3728*fcf3ce44SJohn Forte 		start_time = gethrtime();
3729*fcf3ce44SJohn Forte 	}
3730*fcf3ce44SJohn Forte 
3731*fcf3ce44SJohn Forte 	/*
3732*fcf3ce44SJohn Forte 	 * Get the loop identifier (switch setting) from the path.
3733*fcf3ce44SJohn Forte 	 *
3734*fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
3735*fcf3ce44SJohn Forte 	 * /devices/.../SUNW,socal@3,0/SUNW,sf@0,0/SUNW,ssd@x,0
3736*fcf3ce44SJohn Forte 	 * or
3737*fcf3ce44SJohn Forte 	 * /devices/.../SUNW,qlc@5/SUNW,fp@0,0/SUNW,ssd@x,0
3738*fcf3ce44SJohn Forte 	 */
3739*fcf3ce44SJohn Forte 	if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
3740*fcf3ce44SJohn Forte 		return (L_INVLD_PATH_NO_ATSIGN_FND);
3741*fcf3ce44SJohn Forte 	}
3742*fcf3ce44SJohn Forte 	char_ptr++;	/* point to the loop identifier or WWN */
3743*fcf3ce44SJohn Forte 
3744*fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path_phys);
3745*fcf3ce44SJohn Forte 	/* This function allocs mem for map.dev_addr on success */
3746*fcf3ce44SJohn Forte 	if (strstr(drvr_path, SCSI_VHCI)) {
3747*fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path, &pathlist)) {
3748*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
3749*fcf3ce44SJohn Forte 		}
3750*fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
3751*fcf3ce44SJohn Forte 		p_on = p_st = 0;
3752*fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
3753*fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3754*fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
3755*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_ONLINE) {
3756*fcf3ce44SJohn Forte 					p_on = i;
3757*fcf3ce44SJohn Forte 					break;
3758*fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
3759*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_STANDBY) {
3760*fcf3ce44SJohn Forte 					p_st = i;
3761*fcf3ce44SJohn Forte 				}
3762*fcf3ce44SJohn Forte 			}
3763*fcf3ce44SJohn Forte 		}
3764*fcf3ce44SJohn Forte 		if (p_on == i) {
3765*fcf3ce44SJohn Forte 			/* on_line path */
3766*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
3767*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_hba);
3768*fcf3ce44SJohn Forte 			(void) strncpy(pwwn1,
3769*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_addr,
3770*fcf3ce44SJohn Forte 				WWN_S_LEN - 1);
3771*fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
3772*fcf3ce44SJohn Forte 		} else {
3773*fcf3ce44SJohn Forte 			/* standby or path0 */
3774*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
3775*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_hba);
3776*fcf3ce44SJohn Forte 			(void) strncpy(pwwn1,
3777*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_addr,
3778*fcf3ce44SJohn Forte 				WWN_S_LEN - 1);
3779*fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
3780*fcf3ce44SJohn Forte 		}
3781*fcf3ce44SJohn Forte 		free(pathlist.path_info);
3782*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
3783*fcf3ce44SJohn Forte 	}
3784*fcf3ce44SJohn Forte 	if ((map_root = g_dev_map_init(drvr_path, &err,
3785*fcf3ce44SJohn Forte 		MAP_XPORT_PROP_ONLY)) == NULL) {
3786*fcf3ce44SJohn Forte 		return (err);
3787*fcf3ce44SJohn Forte 	}
3788*fcf3ce44SJohn Forte 
3789*fcf3ce44SJohn Forte 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3790*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3791*fcf3ce44SJohn Forte 		return (err);
3792*fcf3ce44SJohn Forte 	}
3793*fcf3ce44SJohn Forte 
3794*fcf3ce44SJohn Forte 	if (strstr(path_phys, SCSI_VHCI)) {
3795*fcf3ce44SJohn Forte 		char_ptr = pwwn1;
3796*fcf3ce44SJohn Forte 	} else {
3797*fcf3ce44SJohn Forte 		/*
3798*fcf3ce44SJohn Forte 		 * Format of WWN is
3799*fcf3ce44SJohn Forte 		 * ssd@w2200002037000f96,0:a,raw
3800*fcf3ce44SJohn Forte 		 */
3801*fcf3ce44SJohn Forte 		if (*char_ptr != 'w') {
3802*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3803*fcf3ce44SJohn Forte 			return (L_INVLD_WWN_FORMAT);
3804*fcf3ce44SJohn Forte 		}
3805*fcf3ce44SJohn Forte 		char_ptr++;
3806*fcf3ce44SJohn Forte 	}
3807*fcf3ce44SJohn Forte 	pwwn = strtoull(char_ptr, &ptr, 16);
3808*fcf3ce44SJohn Forte 	if (ptr == char_ptr) {
3809*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3810*fcf3ce44SJohn Forte 		return (L_NO_WWN_FOUND_IN_PATH);
3811*fcf3ce44SJohn Forte 	}
3812*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_wwn:  Looking for WWN "
3813*fcf3ce44SJohn Forte 	    "0x%llx\n", pwwn);
3814*fcf3ce44SJohn Forte 
3815*fcf3ce44SJohn Forte 	if (((map_dev = g_get_first_dev(map_root, &err)) == NULL) &&
3816*fcf3ce44SJohn Forte 	    (err != L_NO_SUCH_DEV_FOUND)) {
3817*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3818*fcf3ce44SJohn Forte 		return (err);
3819*fcf3ce44SJohn Forte 	}
3820*fcf3ce44SJohn Forte 
3821*fcf3ce44SJohn Forte 	while (map_dev) {
3822*fcf3ce44SJohn Forte 		if ((err = g_dev_prop_lookup_bytes(map_dev,
3823*fcf3ce44SJohn Forte 			PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) {
3824*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3825*fcf3ce44SJohn Forte 			return (err);
3826*fcf3ce44SJohn Forte 		}
3827*fcf3ce44SJohn Forte 		if ((err = g_dev_prop_lookup_bytes(map_dev,
3828*fcf3ce44SJohn Forte 			NODE_WWN_PROP, &count, &node_wwn_byte)) != 0) {
3829*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3830*fcf3ce44SJohn Forte 			return (err);
3831*fcf3ce44SJohn Forte 		}
3832*fcf3ce44SJohn Forte 
3833*fcf3ce44SJohn Forte 		if (pwwn == wwnConversion(port_wwn_byte) && found != 1) {
3834*fcf3ce44SJohn Forte 			found = 1;
3835*fcf3ce44SJohn Forte 			memcpy(port_wwn, port_wwn_byte, FC_WWN_SIZE);
3836*fcf3ce44SJohn Forte 			memcpy(node_wwn, node_wwn_byte, FC_WWN_SIZE);
3837*fcf3ce44SJohn Forte 			if ((err = g_dev_prop_lookup_ints(
3838*fcf3ce44SJohn Forte 				map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3839*fcf3ce44SJohn Forte 				g_dev_map_fini(map_root);
3840*fcf3ce44SJohn Forte 				return (err);
3841*fcf3ce44SJohn Forte 			}
3842*fcf3ce44SJohn Forte 			*al_pa = *port_addr;
3843*fcf3ce44SJohn Forte 		}
3844*fcf3ce44SJohn Forte 		add_wwn_entry(wwn_list_found, port_wwn_byte,
3845*fcf3ce44SJohn Forte 		    node_wwn_byte);
3846*fcf3ce44SJohn Forte 
3847*fcf3ce44SJohn Forte 		if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3848*fcf3ce44SJohn Forte 		    (err != L_NO_SUCH_DEV_FOUND)) {
3849*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3850*fcf3ce44SJohn Forte 			return (err);
3851*fcf3ce44SJohn Forte 		}
3852*fcf3ce44SJohn Forte 	}
3853*fcf3ce44SJohn Forte 	if (!found) {
3854*fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3855*fcf3ce44SJohn Forte 		return (L_NO_LOOP_ADDRS_FOUND);
3856*fcf3ce44SJohn Forte 	}
3857*fcf3ce44SJohn Forte 
3858*fcf3ce44SJohn Forte 	g_dev_map_fini(map_root);
3859*fcf3ce44SJohn Forte 	if (env != NULL) {
3860*fcf3ce44SJohn Forte 		end_time = gethrtime();
3861*fcf3ce44SJohn Forte 		fprintf(stdout, "      get_wwns: "
3862*fcf3ce44SJohn Forte 		"\t\tTime = %lld millisec\n",
3863*fcf3ce44SJohn Forte 		(end_time - start_time)/1000000);
3864*fcf3ce44SJohn Forte 	}
3865*fcf3ce44SJohn Forte 	return (0);
3866*fcf3ce44SJohn Forte }
3867*fcf3ce44SJohn Forte 
3868*fcf3ce44SJohn Forte /*
3869*fcf3ce44SJohn Forte  * Get device World Wide Name and AL_PA for device at path
3870*fcf3ce44SJohn Forte  *
3871*fcf3ce44SJohn Forte  * RETURN: 0 O.K.
3872*fcf3ce44SJohn Forte  *
3873*fcf3ce44SJohn Forte  * INPUTS:
3874*fcf3ce44SJohn Forte  *	- path_phys must be of a device, either an IB or disk.
3875*fcf3ce44SJohn Forte  */
3876*fcf3ce44SJohn Forte int
3877*fcf3ce44SJohn Forte g_get_wwn(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[],
3878*fcf3ce44SJohn Forte 	int *al_pa, int verbose)
3879*fcf3ce44SJohn Forte {
3880*fcf3ce44SJohn Forte 	struct wwn_list_found_struct *wwn_list_found = NULL;
3881*fcf3ce44SJohn Forte 	int ret;
3882*fcf3ce44SJohn Forte 
3883*fcf3ce44SJohn Forte 	/* return invalid path if the argument is NULL */
3884*fcf3ce44SJohn Forte 	if (path_phys == NULL) {
3885*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3886*fcf3ce44SJohn Forte 	}
3887*fcf3ce44SJohn Forte 	/* return invalid arg if the argument is NULL */
3888*fcf3ce44SJohn Forte 	if ((port_wwn == NULL) ||
3889*fcf3ce44SJohn Forte 		(node_wwn == NULL) || (al_pa == NULL)) {
3890*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3891*fcf3ce44SJohn Forte 	}
3892*fcf3ce44SJohn Forte 
3893*fcf3ce44SJohn Forte 	ret = get_wwns(path_phys, port_wwn, node_wwn, al_pa, &wwn_list_found);
3894*fcf3ce44SJohn Forte 	g_free_wwn_list_found(&wwn_list_found);
3895*fcf3ce44SJohn Forte 	return (ret);
3896*fcf3ce44SJohn Forte }
3897*fcf3ce44SJohn Forte 
3898*fcf3ce44SJohn Forte int
3899*fcf3ce44SJohn Forte g_get_serial_number(char *path, uchar_t *serial_number,
3900*fcf3ce44SJohn Forte     size_t *serial_number_len)
3901*fcf3ce44SJohn Forte {
3902*fcf3ce44SJohn Forte int	    fd, status = 0;
3903*fcf3ce44SJohn Forte L_inquiry80 inq80;
3904*fcf3ce44SJohn Forte 
3905*fcf3ce44SJohn Forte 	/* return invalid path if path is NULL */
3906*fcf3ce44SJohn Forte 	if (path == NULL) {
3907*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3908*fcf3ce44SJohn Forte 	}
3909*fcf3ce44SJohn Forte 	/* return invalid arg if serial_number is NULL */
3910*fcf3ce44SJohn Forte 	if (serial_number == NULL) {
3911*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3912*fcf3ce44SJohn Forte 	}
3913*fcf3ce44SJohn Forte 
3914*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_serial_number: path: %s\n", path);
3915*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) {
3916*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
3917*fcf3ce44SJohn Forte 	}
3918*fcf3ce44SJohn Forte 	/*
3919*fcf3ce44SJohn Forte 	 * Call the inquiry cmd on page 0x80 only if the vendor
3920*fcf3ce44SJohn Forte 	 * supports page 0x80.
3921*fcf3ce44SJohn Forte 	 */
3922*fcf3ce44SJohn Forte 	if ((g_find_supported_inq_page(fd, 0x80))) {
3923*fcf3ce44SJohn Forte 		/*
3924*fcf3ce44SJohn Forte 		 * Let's retrieve the serial number from page 0x80
3925*fcf3ce44SJohn Forte 		 * and store it in the inquiry structure
3926*fcf3ce44SJohn Forte 		 */
3927*fcf3ce44SJohn Forte 		status = g_scsi_inquiry_cmd80(fd,
3928*fcf3ce44SJohn Forte 		    (uchar_t *)&inq80,
3929*fcf3ce44SJohn Forte 		    sizeof (struct l_inquiry80_struct));
3930*fcf3ce44SJohn Forte 		if (status == 0) {
3931*fcf3ce44SJohn Forte 			if (*serial_number_len > inq80.inq_page_len)
3932*fcf3ce44SJohn Forte 				*serial_number_len = inq80.inq_page_len;
3933*fcf3ce44SJohn Forte 			strncpy((char *)serial_number, (char *)inq80.inq_serial,
3934*fcf3ce44SJohn Forte 			    *serial_number_len);
3935*fcf3ce44SJohn Forte 		} else {
3936*fcf3ce44SJohn Forte 			char unavail[] = "Unavailable";
3937*fcf3ce44SJohn Forte 			status = 0;
3938*fcf3ce44SJohn Forte 			if (*serial_number_len > strlen(unavail))
3939*fcf3ce44SJohn Forte 				*serial_number_len = strlen(unavail);
3940*fcf3ce44SJohn Forte 			strncpy((char *)serial_number, unavail,
3941*fcf3ce44SJohn Forte 			    *serial_number_len);
3942*fcf3ce44SJohn Forte 		}
3943*fcf3ce44SJohn Forte 	} else {
3944*fcf3ce44SJohn Forte 		/*
3945*fcf3ce44SJohn Forte 		 * page 0x80 is not supported, so print the
3946*fcf3ce44SJohn Forte 		 * appropriate message.
3947*fcf3ce44SJohn Forte 		 */
3948*fcf3ce44SJohn Forte 		char unsupp[] = "Unsupported";
3949*fcf3ce44SJohn Forte 		if (*serial_number_len > strlen(unsupp))
3950*fcf3ce44SJohn Forte 			*serial_number_len = strlen(unsupp);
3951*fcf3ce44SJohn Forte 		strncpy((char *)serial_number, unsupp,
3952*fcf3ce44SJohn Forte 		    *serial_number_len);
3953*fcf3ce44SJohn Forte 	}
3954*fcf3ce44SJohn Forte 	(void) close(fd);
3955*fcf3ce44SJohn Forte 	return (status);
3956*fcf3ce44SJohn Forte }
3957*fcf3ce44SJohn Forte 
3958*fcf3ce44SJohn Forte int
3959*fcf3ce44SJohn Forte g_get_inquiry(char *path, L_inquiry *l_inquiry)
3960*fcf3ce44SJohn Forte {
3961*fcf3ce44SJohn Forte int	    fd, status;
3962*fcf3ce44SJohn Forte 
3963*fcf3ce44SJohn Forte 	/* return invalid path if path is NULL */
3964*fcf3ce44SJohn Forte 	if (path == NULL) {
3965*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3966*fcf3ce44SJohn Forte 	}
3967*fcf3ce44SJohn Forte 	/* return invalid arg if l_inquiry is NULL */
3968*fcf3ce44SJohn Forte 	if (l_inquiry == NULL) {
3969*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3970*fcf3ce44SJohn Forte 	}
3971*fcf3ce44SJohn Forte 
3972*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_inquiry: path: %s\n", path);
3973*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
3974*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
3975*fcf3ce44SJohn Forte 	status = g_scsi_inquiry_cmd(fd,
3976*fcf3ce44SJohn Forte 		(uchar_t *)l_inquiry, sizeof (struct l_inquiry_struct));
3977*fcf3ce44SJohn Forte 
3978*fcf3ce44SJohn Forte 	(void) close(fd);
3979*fcf3ce44SJohn Forte 	return (status);
3980*fcf3ce44SJohn Forte }
3981*fcf3ce44SJohn Forte 
3982*fcf3ce44SJohn Forte /*
3983*fcf3ce44SJohn Forte  * Function to retrieve inquiry page 0x80 from the device
3984*fcf3ce44SJohn Forte  */
3985*fcf3ce44SJohn Forte static int
3986*fcf3ce44SJohn Forte g_scsi_inquiry_cmd80(int fd, uchar_t *buf_ptr, int buf_len)
3987*fcf3ce44SJohn Forte {
3988*fcf3ce44SJohn Forte struct uscsi_cmd	ucmd;
3989*fcf3ce44SJohn Forte my_cdb_g0	cdb = {SCMD_INQUIRY, 0x1, 0x80, 0, 0x10, 0};
3990*fcf3ce44SJohn Forte struct	scsi_extended_sense	sense;
3991*fcf3ce44SJohn Forte 
3992*fcf3ce44SJohn Forte 	(void) memset(buf_ptr, 0, buf_len);
3993*fcf3ce44SJohn Forte 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
3994*fcf3ce44SJohn Forte 	cdb.count = (uchar_t)buf_len;
3995*fcf3ce44SJohn Forte 	ucmd.uscsi_cdb = (caddr_t)&cdb;
3996*fcf3ce44SJohn Forte 	ucmd.uscsi_cdblen = CDB_GROUP0;
3997*fcf3ce44SJohn Forte 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
3998*fcf3ce44SJohn Forte 	ucmd.uscsi_buflen = buf_len;
3999*fcf3ce44SJohn Forte 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
4000*fcf3ce44SJohn Forte 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
4001*fcf3ce44SJohn Forte 	ucmd.uscsi_timeout = 60;
4002*fcf3ce44SJohn Forte 	return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT));
4003*fcf3ce44SJohn Forte }
4004*fcf3ce44SJohn Forte 
4005*fcf3ce44SJohn Forte /*
4006*fcf3ce44SJohn Forte  * Function to determine if the given page is supported by vendor.
4007*fcf3ce44SJohn Forte  */
4008*fcf3ce44SJohn Forte static int
4009*fcf3ce44SJohn Forte g_find_supported_inq_page(int fd, int page_num)
4010*fcf3ce44SJohn Forte {
4011*fcf3ce44SJohn Forte struct	uscsi_cmd	ucmd;
4012*fcf3ce44SJohn Forte my_cdb_g0	cdb = {SCMD_INQUIRY, 0x1, 0, 0, 0xff, 0};
4013*fcf3ce44SJohn Forte struct	scsi_extended_sense	sense;
4014*fcf3ce44SJohn Forte L_inquiry00			inq00;
4015*fcf3ce44SJohn Forte uchar_t				*data;
4016*fcf3ce44SJohn Forte int				status = 0;
4017*fcf3ce44SJohn Forte int				index;
4018*fcf3ce44SJohn Forte 
4019*fcf3ce44SJohn Forte 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
4020*fcf3ce44SJohn Forte 	cdb.count = (uchar_t)(sizeof (L_inquiry00));
4021*fcf3ce44SJohn Forte 	ucmd.uscsi_cdb = (caddr_t)&cdb;
4022*fcf3ce44SJohn Forte 	ucmd.uscsi_cdblen = CDB_GROUP0;
4023*fcf3ce44SJohn Forte 	ucmd.uscsi_bufaddr = (caddr_t)&inq00;
4024*fcf3ce44SJohn Forte 	ucmd.uscsi_buflen = sizeof (inq00);
4025*fcf3ce44SJohn Forte 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
4026*fcf3ce44SJohn Forte 	ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
4027*fcf3ce44SJohn Forte 	ucmd.uscsi_timeout = 60;
4028*fcf3ce44SJohn Forte 	status = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT);
4029*fcf3ce44SJohn Forte 	if (status) {
4030*fcf3ce44SJohn Forte 		return (0);
4031*fcf3ce44SJohn Forte 	}
4032*fcf3ce44SJohn Forte 	data = (uchar_t *)&inq00;
4033*fcf3ce44SJohn Forte 	for (index = 4; (index <= inq00.len+3)&&
4034*fcf3ce44SJohn Forte 	    (data[index] <= page_num); index ++) {
4035*fcf3ce44SJohn Forte 		if (data[index] == page_num) {
4036*fcf3ce44SJohn Forte 			return (1);
4037*fcf3ce44SJohn Forte 		}
4038*fcf3ce44SJohn Forte 	}
4039*fcf3ce44SJohn Forte 	return (0);
4040*fcf3ce44SJohn Forte }
4041*fcf3ce44SJohn Forte 
4042*fcf3ce44SJohn Forte int
4043*fcf3ce44SJohn Forte g_get_perf_statistics(char *path, uchar_t *perf_ptr)
4044*fcf3ce44SJohn Forte {
4045*fcf3ce44SJohn Forte int	fd;
4046*fcf3ce44SJohn Forte 
4047*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_perf_statistics: Get Performance Statistics:"
4048*fcf3ce44SJohn Forte 		"\n  Path:%s\n",
4049*fcf3ce44SJohn Forte 		path);
4050*fcf3ce44SJohn Forte 
4051*fcf3ce44SJohn Forte 	/* initialize tables */
4052*fcf3ce44SJohn Forte 	(void) memset(perf_ptr, 0, sizeof (int));
4053*fcf3ce44SJohn Forte 
4054*fcf3ce44SJohn Forte 	/* open controller */
4055*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4056*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4057*fcf3ce44SJohn Forte 
4058*fcf3ce44SJohn Forte 
4059*fcf3ce44SJohn Forte 	/* update parameters in the performance table */
4060*fcf3ce44SJohn Forte 
4061*fcf3ce44SJohn Forte 	/* get the period in seconds */
4062*fcf3ce44SJohn Forte 
4063*fcf3ce44SJohn Forte 
4064*fcf3ce44SJohn Forte 	(void) close(fd);
4065*fcf3ce44SJohn Forte 
4066*fcf3ce44SJohn Forte 	return (0);
4067*fcf3ce44SJohn Forte }
4068*fcf3ce44SJohn Forte 
4069*fcf3ce44SJohn Forte 
4070*fcf3ce44SJohn Forte int
4071*fcf3ce44SJohn Forte g_start(char *path)
4072*fcf3ce44SJohn Forte {
4073*fcf3ce44SJohn Forte int	status;
4074*fcf3ce44SJohn Forte int	fd;
4075*fcf3ce44SJohn Forte 
4076*fcf3ce44SJohn Forte 	P_DPRINTF("  g_start: Start: Path %s\n", path);
4077*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4078*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4079*fcf3ce44SJohn Forte 	status = g_scsi_start_cmd(fd);
4080*fcf3ce44SJohn Forte 	(void) close(fd);
4081*fcf3ce44SJohn Forte 	return (status);
4082*fcf3ce44SJohn Forte }
4083*fcf3ce44SJohn Forte 
4084*fcf3ce44SJohn Forte int
4085*fcf3ce44SJohn Forte g_stop(char *path, int immediate_flag)
4086*fcf3ce44SJohn Forte {
4087*fcf3ce44SJohn Forte int	status, fd;
4088*fcf3ce44SJohn Forte 
4089*fcf3ce44SJohn Forte 	P_DPRINTF("  g_stop: Stop: Path %s\n", path);
4090*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4091*fcf3ce44SJohn Forte 		return (errno);
4092*fcf3ce44SJohn Forte 	status = g_scsi_stop_cmd(fd, immediate_flag);
4093*fcf3ce44SJohn Forte 	(void) close(fd);
4094*fcf3ce44SJohn Forte 	return (status);
4095*fcf3ce44SJohn Forte }
4096*fcf3ce44SJohn Forte 
4097*fcf3ce44SJohn Forte int
4098*fcf3ce44SJohn Forte g_reserve(char *path)
4099*fcf3ce44SJohn Forte {
4100*fcf3ce44SJohn Forte int 	fd, status;
4101*fcf3ce44SJohn Forte 
4102*fcf3ce44SJohn Forte 	P_DPRINTF("  g_reserve: Reserve: Path %s\n", path);
4103*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4104*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4105*fcf3ce44SJohn Forte 	status = g_scsi_reserve_cmd(fd);
4106*fcf3ce44SJohn Forte 	(void) close(fd);
4107*fcf3ce44SJohn Forte 	return (status);
4108*fcf3ce44SJohn Forte }
4109*fcf3ce44SJohn Forte 
4110*fcf3ce44SJohn Forte int
4111*fcf3ce44SJohn Forte g_release(char *path)
4112*fcf3ce44SJohn Forte {
4113*fcf3ce44SJohn Forte int 	fd, status;
4114*fcf3ce44SJohn Forte 
4115*fcf3ce44SJohn Forte 	P_DPRINTF("  g_release: Release: Path %s\n", path);
4116*fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4117*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4118*fcf3ce44SJohn Forte 	status = g_scsi_release_cmd(fd);
4119*fcf3ce44SJohn Forte 	(void) close(fd);
4120*fcf3ce44SJohn Forte 	return (status);
4121*fcf3ce44SJohn Forte }
4122*fcf3ce44SJohn Forte 
4123*fcf3ce44SJohn Forte static char
4124*fcf3ce44SJohn Forte ctoi(char c)
4125*fcf3ce44SJohn Forte {
4126*fcf3ce44SJohn Forte 	if ((c >= '0') && (c <= '9'))
4127*fcf3ce44SJohn Forte 		c -= '0';
4128*fcf3ce44SJohn Forte 	else if ((c >= 'A') && (c <= 'F'))
4129*fcf3ce44SJohn Forte 		c = c - 'A' + 10;
4130*fcf3ce44SJohn Forte 	else if ((c >= 'a') && (c <= 'f'))
4131*fcf3ce44SJohn Forte 		c = c - 'a' + 10;
4132*fcf3ce44SJohn Forte 	else
4133*fcf3ce44SJohn Forte 		c = -1;
4134*fcf3ce44SJohn Forte 	return (c);
4135*fcf3ce44SJohn Forte }
4136*fcf3ce44SJohn Forte 
4137*fcf3ce44SJohn Forte int
4138*fcf3ce44SJohn Forte g_string_to_wwn(uchar_t *wwn, uchar_t *wwnp)
4139*fcf3ce44SJohn Forte {
4140*fcf3ce44SJohn Forte 	int	i;
4141*fcf3ce44SJohn Forte 	char	c, c1;
4142*fcf3ce44SJohn Forte 
4143*fcf3ce44SJohn Forte 	*wwnp++ = 0;
4144*fcf3ce44SJohn Forte 	*wwnp++ = 0;
4145*fcf3ce44SJohn Forte 	for (i = 0; i < WWN_SIZE - 2; i++, wwnp++) {
4146*fcf3ce44SJohn Forte 		c = ctoi(*wwn++);
4147*fcf3ce44SJohn Forte 		c1 = ctoi(*wwn++);
4148*fcf3ce44SJohn Forte 		if (c == -1 || c1 == -1)
4149*fcf3ce44SJohn Forte 			return (-1);
4150*fcf3ce44SJohn Forte 		*wwnp = ((c << 4) + c1);
4151*fcf3ce44SJohn Forte 	}
4152*fcf3ce44SJohn Forte 
4153*fcf3ce44SJohn Forte 	return (0);
4154*fcf3ce44SJohn Forte 
4155*fcf3ce44SJohn Forte }
4156*fcf3ce44SJohn Forte 
4157*fcf3ce44SJohn Forte /*
4158*fcf3ce44SJohn Forte  * Converts a string of WWN ASCII characters to a
4159*fcf3ce44SJohn Forte  * binary representation.
4160*fcf3ce44SJohn Forte  *
4161*fcf3ce44SJohn Forte  * Input: string - pointer to uchar_t array
4162*fcf3ce44SJohn Forte  *		WWN in ASCII
4163*fcf3ce44SJohn Forte  *		length: 16 bytes
4164*fcf3ce44SJohn Forte  * Output: wwn - pointer to uchar_t array
4165*fcf3ce44SJohn Forte  *		containing WWN result
4166*fcf3ce44SJohn Forte  *		length: 8 bytes
4167*fcf3ce44SJohn Forte  * Returns:
4168*fcf3ce44SJohn Forte  *	non-zero on error
4169*fcf3ce44SJohn Forte  *	zero on success
4170*fcf3ce44SJohn Forte  */
4171*fcf3ce44SJohn Forte int
4172*fcf3ce44SJohn Forte string_to_wwn(uchar_t *string, uchar_t *wwn)
4173*fcf3ce44SJohn Forte {
4174*fcf3ce44SJohn Forte 	int	i;
4175*fcf3ce44SJohn Forte 	char	c, c1;
4176*fcf3ce44SJohn Forte 	uchar_t *wwnp;
4177*fcf3ce44SJohn Forte 
4178*fcf3ce44SJohn Forte 	wwnp = wwn;
4179*fcf3ce44SJohn Forte 
4180*fcf3ce44SJohn Forte 	for (i = 0; i < WWN_SIZE; i++, wwnp++) {
4181*fcf3ce44SJohn Forte 
4182*fcf3ce44SJohn Forte 		c = ctoi(*string++);
4183*fcf3ce44SJohn Forte 		c1 = ctoi(*string++);
4184*fcf3ce44SJohn Forte 		if (c == -1 || c1 == -1)
4185*fcf3ce44SJohn Forte 			return (-1);
4186*fcf3ce44SJohn Forte 		*wwnp = ((c << 4) + c1);
4187*fcf3ce44SJohn Forte 	}
4188*fcf3ce44SJohn Forte 
4189*fcf3ce44SJohn Forte 	return (0);
4190*fcf3ce44SJohn Forte 
4191*fcf3ce44SJohn Forte }
4192*fcf3ce44SJohn Forte 
4193*fcf3ce44SJohn Forte 
4194*fcf3ce44SJohn Forte /*
4195*fcf3ce44SJohn Forte  * Get multiple paths to a given device port.
4196*fcf3ce44SJohn Forte  * INPUTS:
4197*fcf3ce44SJohn Forte  *	port WWN string.
4198*fcf3ce44SJohn Forte  */
4199*fcf3ce44SJohn Forte int
4200*fcf3ce44SJohn Forte g_get_port_multipath(char *port_wwn_s, struct dlist **dlh, int verbose)
4201*fcf3ce44SJohn Forte {
4202*fcf3ce44SJohn Forte int		err;
4203*fcf3ce44SJohn Forte WWN_list	*wwn_list, *wwn_list_ptr;
4204*fcf3ce44SJohn Forte struct dlist	*dlt, *dl;
4205*fcf3ce44SJohn Forte 
4206*fcf3ce44SJohn Forte 
4207*fcf3ce44SJohn Forte 	/* Initialize list structures. */
4208*fcf3ce44SJohn Forte 	dl = *dlh  = dlt = (struct dlist *)NULL;
4209*fcf3ce44SJohn Forte 	wwn_list = wwn_list_ptr = NULL;
4210*fcf3ce44SJohn Forte 
4211*fcf3ce44SJohn Forte 	H_DPRINTF("  g_get_port_multipath: Looking for multiple paths for"
4212*fcf3ce44SJohn Forte 		" device with\n    port WWW:"
4213*fcf3ce44SJohn Forte 		"%s\n", port_wwn_s);
4214*fcf3ce44SJohn Forte 
4215*fcf3ce44SJohn Forte 	if (err = g_get_wwn_list(&wwn_list, verbose)) {
4216*fcf3ce44SJohn Forte 		return (err);
4217*fcf3ce44SJohn Forte 	}
4218*fcf3ce44SJohn Forte 
4219*fcf3ce44SJohn Forte 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4220*fcf3ce44SJohn Forte 				wwn_list_ptr = wwn_list_ptr->wwn_next) {
4221*fcf3ce44SJohn Forte 		if (strcmp(port_wwn_s, wwn_list_ptr->port_wwn_s) == 0) {
4222*fcf3ce44SJohn Forte 			if ((dl = (struct dlist *)
4223*fcf3ce44SJohn Forte 				g_zalloc(sizeof (struct dlist))) == NULL) {
4224*fcf3ce44SJohn Forte 				while (*dlh != NULL) {
4225*fcf3ce44SJohn Forte 					dl = (*dlh)->next;
4226*fcf3ce44SJohn Forte 					(void) g_destroy_data(*dlh);
4227*fcf3ce44SJohn Forte 					*dlh = dl;
4228*fcf3ce44SJohn Forte 				}
4229*fcf3ce44SJohn Forte 				(void) g_free_wwn_list(&wwn_list);
4230*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
4231*fcf3ce44SJohn Forte 			}
4232*fcf3ce44SJohn Forte 			H_DPRINTF("  g_get_port_multipath:"
4233*fcf3ce44SJohn Forte 				" Found multipath:\n    %s\n",
4234*fcf3ce44SJohn Forte 				wwn_list_ptr->physical_path);
4235*fcf3ce44SJohn Forte 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
4236*fcf3ce44SJohn Forte 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
4237*fcf3ce44SJohn Forte 			if (*dlh == NULL) {
4238*fcf3ce44SJohn Forte 				*dlh = dlt = dl;
4239*fcf3ce44SJohn Forte 			} else {
4240*fcf3ce44SJohn Forte 				dlt->next = dl;
4241*fcf3ce44SJohn Forte 				dl->prev = dlt;
4242*fcf3ce44SJohn Forte 				dlt = dl;
4243*fcf3ce44SJohn Forte 			}
4244*fcf3ce44SJohn Forte 		}
4245*fcf3ce44SJohn Forte 	}
4246*fcf3ce44SJohn Forte 	(void) g_free_wwn_list(&wwn_list);
4247*fcf3ce44SJohn Forte 	return (0);
4248*fcf3ce44SJohn Forte }
4249*fcf3ce44SJohn Forte 
4250*fcf3ce44SJohn Forte 
4251*fcf3ce44SJohn Forte 
4252*fcf3ce44SJohn Forte /*
4253*fcf3ce44SJohn Forte  * Get multiple paths to a given disk/tape device.
4254*fcf3ce44SJohn Forte  * The arg: devpath should be the physical path to device.
4255*fcf3ce44SJohn Forte  *
4256*fcf3ce44SJohn Forte  * OUTPUT:
4257*fcf3ce44SJohn Forte  *	multipath_list	points to a list of multiple paths to the device.
4258*fcf3ce44SJohn Forte  *	NOTE: The caller must free the allocated list (dlist).
4259*fcf3ce44SJohn Forte  *
4260*fcf3ce44SJohn Forte  * RETURNS:
4261*fcf3ce44SJohn Forte  *	0	 if O.K.
4262*fcf3ce44SJohn Forte  *	non-zero otherwise
4263*fcf3ce44SJohn Forte  */
4264*fcf3ce44SJohn Forte int
4265*fcf3ce44SJohn Forte g_get_multipath(char *devpath, struct dlist **multipath_list,
4266*fcf3ce44SJohn Forte 	struct wwn_list_struct *wwn_list, int verbose)
4267*fcf3ce44SJohn Forte {
4268*fcf3ce44SJohn Forte int	err;
4269*fcf3ce44SJohn Forte 
4270*fcf3ce44SJohn Forte 	H_DPRINTF("  g_get_multipath: Looking for multiple paths for"
4271*fcf3ce44SJohn Forte 		" device at path: %s\n", devpath);
4272*fcf3ce44SJohn Forte 
4273*fcf3ce44SJohn Forte 	/* return invalid path if devpath is NULL */
4274*fcf3ce44SJohn Forte 	if (devpath == NULL) {
4275*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4276*fcf3ce44SJohn Forte 	}
4277*fcf3ce44SJohn Forte 	/* return invalid arg if argument is NULL */
4278*fcf3ce44SJohn Forte 	if ((multipath_list == NULL) || (wwn_list == NULL)) {
4279*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
4280*fcf3ce44SJohn Forte 	}
4281*fcf3ce44SJohn Forte 
4282*fcf3ce44SJohn Forte 	if (strstr(devpath, DRV_NAME_SSD) != NULL) {
4283*fcf3ce44SJohn Forte 		err = get_multipath_disk(devpath, multipath_list, wwn_list);
4284*fcf3ce44SJohn Forte 	} else {
4285*fcf3ce44SJohn Forte 		err = get_multipath(devpath, multipath_list, wwn_list);
4286*fcf3ce44SJohn Forte 	}
4287*fcf3ce44SJohn Forte 
4288*fcf3ce44SJohn Forte 	return (err);
4289*fcf3ce44SJohn Forte }
4290*fcf3ce44SJohn Forte 
4291*fcf3ce44SJohn Forte 
4292*fcf3ce44SJohn Forte /*
4293*fcf3ce44SJohn Forte  * Returns multipath information for a ssd device.
4294*fcf3ce44SJohn Forte  * Inputs:
4295*fcf3ce44SJohn Forte  *	devpath: device path to for requested multipath info
4296*fcf3ce44SJohn Forte  *	wwn_list: returned from g_get_wwn_list or devices_get_all
4297*fcf3ce44SJohn Forte  * Output:
4298*fcf3ce44SJohn Forte  *	multipath_list: dlist list of paths
4299*fcf3ce44SJohn Forte  * Returns:
4300*fcf3ce44SJohn Forte  *	0 on success
4301*fcf3ce44SJohn Forte  *	non-zero on failure
4302*fcf3ce44SJohn Forte  */
4303*fcf3ce44SJohn Forte int
4304*fcf3ce44SJohn Forte get_multipath_disk(char *devpath, struct dlist **multipath_list,
4305*fcf3ce44SJohn Forte 	struct wwn_list_struct *wwn_list)
4306*fcf3ce44SJohn Forte {
4307*fcf3ce44SJohn Forte WWN_list	*wwn_list_ptr;
4308*fcf3ce44SJohn Forte struct dlist	*dl = NULL, *dlt = NULL;
4309*fcf3ce44SJohn Forte ddi_devid_t	devid = NULL;
4310*fcf3ce44SJohn Forte int		err;
4311*fcf3ce44SJohn Forte di_node_t	root;
4312*fcf3ce44SJohn Forte struct mplist_struct	*mplistp = NULL, *mplisth = NULL;
4313*fcf3ce44SJohn Forte 
4314*fcf3ce44SJohn Forte 	if (wwn_list == NULL || multipath_list == NULL || devpath == NULL) {
4315*fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
4316*fcf3ce44SJohn Forte 	}
4317*fcf3ce44SJohn Forte 
4318*fcf3ce44SJohn Forte 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
4319*fcf3ce44SJohn Forte 		return (L_DEV_SNAPSHOT_FAILED);
4320*fcf3ce44SJohn Forte 	}
4321*fcf3ce44SJohn Forte 
4322*fcf3ce44SJohn Forte 	if ((err = g_devid_get(devpath, &devid, root, SSD_DRVR_NAME)) != 0) {
4323*fcf3ce44SJohn Forte 		di_fini(root);
4324*fcf3ce44SJohn Forte 		return (err);
4325*fcf3ce44SJohn Forte 	}
4326*fcf3ce44SJohn Forte 
4327*fcf3ce44SJohn Forte 	*multipath_list = (struct dlist *)NULL;
4328*fcf3ce44SJohn Forte 	if ((err = devid_get_all(devid, root, SSD_DRVR_NAME, &mplisth)) != 0) {
4329*fcf3ce44SJohn Forte 		di_fini(root);
4330*fcf3ce44SJohn Forte 		return (err);
4331*fcf3ce44SJohn Forte 	}
4332*fcf3ce44SJohn Forte 
4333*fcf3ce44SJohn Forte 	if (mplisth == NULL) {
4334*fcf3ce44SJohn Forte 		di_fini(root);
4335*fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
4336*fcf3ce44SJohn Forte 	}
4337*fcf3ce44SJohn Forte 
4338*fcf3ce44SJohn Forte 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4339*fcf3ce44SJohn Forte 				wwn_list_ptr = wwn_list_ptr->wwn_next) {
4340*fcf3ce44SJohn Forte 		/*
4341*fcf3ce44SJohn Forte 		 * When a path is found from the list, load the logical
4342*fcf3ce44SJohn Forte 		 * and physical dev path
4343*fcf3ce44SJohn Forte 		 */
4344*fcf3ce44SJohn Forte 		for (mplistp = mplisth; mplistp != NULL;
4345*fcf3ce44SJohn Forte 				mplistp = mplistp->next) {
4346*fcf3ce44SJohn Forte 		    if (strncmp(mplistp->devpath, wwn_list_ptr->physical_path,
4347*fcf3ce44SJohn Forte 			strlen(mplistp->devpath)) == 0) {
4348*fcf3ce44SJohn Forte 
4349*fcf3ce44SJohn Forte 			/* Load multipath list */
4350*fcf3ce44SJohn Forte 			if ((dl = (struct dlist *)
4351*fcf3ce44SJohn Forte 				calloc(1, sizeof (struct dlist))) == NULL) {
4352*fcf3ce44SJohn Forte 				while (*multipath_list != NULL) {
4353*fcf3ce44SJohn Forte 					dl = dlt->next;
4354*fcf3ce44SJohn Forte 					g_destroy_data(dlt);
4355*fcf3ce44SJohn Forte 					dlt = dl;
4356*fcf3ce44SJohn Forte 				}
4357*fcf3ce44SJohn Forte 				di_fini(root);
4358*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
4359*fcf3ce44SJohn Forte 			}
4360*fcf3ce44SJohn Forte 			H_DPRINTF("  g_get_multipath: Found multipath=%s\n",
4361*fcf3ce44SJohn Forte 					wwn_list_ptr->physical_path);
4362*fcf3ce44SJohn Forte 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
4363*fcf3ce44SJohn Forte 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
4364*fcf3ce44SJohn Forte 			if (*multipath_list == NULL) {
4365*fcf3ce44SJohn Forte 				*multipath_list = dlt = dl;
4366*fcf3ce44SJohn Forte 			} else {
4367*fcf3ce44SJohn Forte 				dlt->next = dl;
4368*fcf3ce44SJohn Forte 				dl->prev = dlt;
4369*fcf3ce44SJohn Forte 				dlt = dl;
4370*fcf3ce44SJohn Forte 			}
4371*fcf3ce44SJohn Forte 		    }
4372*fcf3ce44SJohn Forte 		}
4373*fcf3ce44SJohn Forte 	}
4374*fcf3ce44SJohn Forte 	di_fini(root);
4375*fcf3ce44SJohn Forte 	mplist_free(mplisth);
4376*fcf3ce44SJohn Forte 	return (0);
4377*fcf3ce44SJohn Forte }
4378*fcf3ce44SJohn Forte 
4379*fcf3ce44SJohn Forte int
4380*fcf3ce44SJohn Forte get_multipath(char *devpath, struct dlist **multipath_list,
4381*fcf3ce44SJohn Forte 	struct wwn_list_struct *wwn_list)
4382*fcf3ce44SJohn Forte {
4383*fcf3ce44SJohn Forte WWN_list	*wwn_list_ptr;
4384*fcf3ce44SJohn Forte struct dlist	*dl, *dlt;
4385*fcf3ce44SJohn Forte char		path[MAXPATHLEN], m_phys_path[MAXPATHLEN], *ptr;
4386*fcf3ce44SJohn Forte int		len;
4387*fcf3ce44SJohn Forte int		lun_a = -1;
4388*fcf3ce44SJohn Forte char		node_wwn_s[WWN_S_LEN];
4389*fcf3ce44SJohn Forte 
4390*fcf3ce44SJohn Forte 	if (devpath == NULL) {
4391*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4392*fcf3ce44SJohn Forte 	}
4393*fcf3ce44SJohn Forte 
4394*fcf3ce44SJohn Forte 	/* Strip partition information. */
4395*fcf3ce44SJohn Forte 	if ((ptr = strrchr(devpath, ':')) != NULL) {
4396*fcf3ce44SJohn Forte 		len = strlen(devpath) - strlen(ptr);
4397*fcf3ce44SJohn Forte 		(void) strncpy(path, devpath, len);
4398*fcf3ce44SJohn Forte 		path[len] = '\0';
4399*fcf3ce44SJohn Forte 	} else {
4400*fcf3ce44SJohn Forte 		(void) strcpy(path, devpath);
4401*fcf3ce44SJohn Forte 	}
4402*fcf3ce44SJohn Forte 
4403*fcf3ce44SJohn Forte 	*multipath_list = dl = dlt = (struct dlist *)NULL;
4404*fcf3ce44SJohn Forte 
4405*fcf3ce44SJohn Forte 
4406*fcf3ce44SJohn Forte 	if (wwn_list == NULL) {
4407*fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
4408*fcf3ce44SJohn Forte 	}
4409*fcf3ce44SJohn Forte 
4410*fcf3ce44SJohn Forte 	for (*node_wwn_s = NULL, wwn_list_ptr = wwn_list;
4411*fcf3ce44SJohn Forte 				wwn_list_ptr != NULL;
4412*fcf3ce44SJohn Forte 				wwn_list_ptr = wwn_list_ptr->wwn_next) {
4413*fcf3ce44SJohn Forte 
4414*fcf3ce44SJohn Forte 		if ((ptr = strrchr(wwn_list_ptr->physical_path, ':')) != NULL) {
4415*fcf3ce44SJohn Forte 			len = strlen(wwn_list_ptr->physical_path) - strlen(ptr);
4416*fcf3ce44SJohn Forte 			(void) strncpy(m_phys_path, wwn_list_ptr->physical_path,
4417*fcf3ce44SJohn Forte 					len);
4418*fcf3ce44SJohn Forte 			m_phys_path[len] = '\0';
4419*fcf3ce44SJohn Forte 		} else {
4420*fcf3ce44SJohn Forte 			(void) strcpy(m_phys_path, wwn_list_ptr->physical_path);
4421*fcf3ce44SJohn Forte 		}
4422*fcf3ce44SJohn Forte 
4423*fcf3ce44SJohn Forte 		if (strcasecmp(m_phys_path, path) == 0) {
4424*fcf3ce44SJohn Forte 			(void) strcpy(node_wwn_s, wwn_list_ptr->node_wwn_s);
4425*fcf3ce44SJohn Forte 			break;
4426*fcf3ce44SJohn Forte 		}
4427*fcf3ce44SJohn Forte 	}
4428*fcf3ce44SJohn Forte 
4429*fcf3ce44SJohn Forte 	if (*node_wwn_s == NULL) {
4430*fcf3ce44SJohn Forte 		H_DPRINTF("node_wwn_s is NULL!\n");
4431*fcf3ce44SJohn Forte 		return (L_NO_NODE_WWN_IN_WWNLIST);
4432*fcf3ce44SJohn Forte 	}
4433*fcf3ce44SJohn Forte 
4434*fcf3ce44SJohn Forte 	lun_a = g_get_lun_number(wwn_list_ptr->physical_path);
4435*fcf3ce44SJohn Forte 
4436*fcf3ce44SJohn Forte 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4437*fcf3ce44SJohn Forte 				wwn_list_ptr = wwn_list_ptr->wwn_next) {
4438*fcf3ce44SJohn Forte 		if ((strcmp(node_wwn_s, wwn_list_ptr->node_wwn_s) == 0) &&
4439*fcf3ce44SJohn Forte 			((lun_a < 0) || (lun_a ==
4440*fcf3ce44SJohn Forte 			g_get_lun_number(wwn_list_ptr->physical_path)))) {
4441*fcf3ce44SJohn Forte 
4442*fcf3ce44SJohn Forte 			if ((dl = (struct dlist *)
4443*fcf3ce44SJohn Forte 				g_zalloc(sizeof (struct dlist))) == NULL) {
4444*fcf3ce44SJohn Forte 				while (*multipath_list != NULL) {
4445*fcf3ce44SJohn Forte 					dl = dlt->next;
4446*fcf3ce44SJohn Forte 					(void) g_destroy_data(dlt);
4447*fcf3ce44SJohn Forte 					dlt = dl;
4448*fcf3ce44SJohn Forte 				}
4449*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
4450*fcf3ce44SJohn Forte 			}
4451*fcf3ce44SJohn Forte 			H_DPRINTF("  g_get_multipath: Found multipath=%s\n",
4452*fcf3ce44SJohn Forte 					wwn_list_ptr->physical_path);
4453*fcf3ce44SJohn Forte 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
4454*fcf3ce44SJohn Forte 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
4455*fcf3ce44SJohn Forte 			if (*multipath_list == NULL) {
4456*fcf3ce44SJohn Forte 				*multipath_list = dlt = dl;
4457*fcf3ce44SJohn Forte 			} else {
4458*fcf3ce44SJohn Forte 				dlt->next = dl;
4459*fcf3ce44SJohn Forte 				dl->prev = dlt;
4460*fcf3ce44SJohn Forte 				dlt = dl;
4461*fcf3ce44SJohn Forte 			}
4462*fcf3ce44SJohn Forte 		}
4463*fcf3ce44SJohn Forte 	}
4464*fcf3ce44SJohn Forte 	return (0);
4465*fcf3ce44SJohn Forte }
4466*fcf3ce44SJohn Forte 
4467*fcf3ce44SJohn Forte /*
4468*fcf3ce44SJohn Forte  * Free a multipath list
4469*fcf3ce44SJohn Forte  *
4470*fcf3ce44SJohn Forte  */
4471*fcf3ce44SJohn Forte void
4472*fcf3ce44SJohn Forte g_free_multipath(struct dlist *dlh)
4473*fcf3ce44SJohn Forte {
4474*fcf3ce44SJohn Forte struct dlist	*dl;
4475*fcf3ce44SJohn Forte 
4476*fcf3ce44SJohn Forte 	while (dlh != NULL) {
4477*fcf3ce44SJohn Forte 		dl = dlh->next;
4478*fcf3ce44SJohn Forte 		if (dlh->dev_path != NULL)
4479*fcf3ce44SJohn Forte 			(void) g_destroy_data(dlh->dev_path);
4480*fcf3ce44SJohn Forte 		if (dlh->logical_path != NULL)
4481*fcf3ce44SJohn Forte 			(void) g_destroy_data(dlh->logical_path);
4482*fcf3ce44SJohn Forte 		(void) g_destroy_data(dlh);
4483*fcf3ce44SJohn Forte 		dlh = dl;
4484*fcf3ce44SJohn Forte 	}
4485*fcf3ce44SJohn Forte }
4486*fcf3ce44SJohn Forte 
4487*fcf3ce44SJohn Forte 
4488*fcf3ce44SJohn Forte 
4489*fcf3ce44SJohn Forte /*
4490*fcf3ce44SJohn Forte  * Get the path to the nexus (HBA) driver.
4491*fcf3ce44SJohn Forte  * This assumes the path looks something like this:
4492*fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4493*fcf3ce44SJohn Forte  * or maybe this
4494*fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
4495*fcf3ce44SJohn Forte  * or
4496*fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0
4497*fcf3ce44SJohn Forte  * or
4498*fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0:1
4499*fcf3ce44SJohn Forte  * or
4500*fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4501*fcf3ce44SJohn Forte  * (or "qlc" instead of "socal" and "fp" for "sf")
4502*fcf3ce44SJohn Forte  *
4503*fcf3ce44SJohn Forte  * Which should resolve to a path like this:
4504*fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0:1
4505*fcf3ce44SJohn Forte  * or
4506*fcf3ce44SJohn Forte  * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4507*fcf3ce44SJohn Forte  *
4508*fcf3ce44SJohn Forte  * or
4509*fcf3ce44SJohn Forte  * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
4510*fcf3ce44SJohn Forte  * which should resolve to
4511*fcf3ce44SJohn Forte  * /devices/pci@4,2000/scsi@1:devctl
4512*fcf3ce44SJohn Forte  */
4513*fcf3ce44SJohn Forte int
4514*fcf3ce44SJohn Forte g_get_nexus_path(char *path_phys, char **nexus_path)
4515*fcf3ce44SJohn Forte {
4516*fcf3ce44SJohn Forte uchar_t		port = 0;
4517*fcf3ce44SJohn Forte int		port_flag = 0, i = 0, pathcnt = 1;
4518*fcf3ce44SJohn Forte char		*char_ptr;
4519*fcf3ce44SJohn Forte char		drvr_path[MAXPATHLEN];
4520*fcf3ce44SJohn Forte char		buf[MAXPATHLEN];
4521*fcf3ce44SJohn Forte char		temp_buf[MAXPATHLEN];
4522*fcf3ce44SJohn Forte struct stat	stbuf;
4523*fcf3ce44SJohn Forte uint_t		path_type;
4524*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
4525*fcf3ce44SJohn Forte int		p_on = 0, p_st = 0;
4526*fcf3ce44SJohn Forte 
4527*fcf3ce44SJohn Forte 	/* return invalid path if the path_phys is NULL */
4528*fcf3ce44SJohn Forte 	if (path_phys == NULL) {
4529*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4530*fcf3ce44SJohn Forte 	}
4531*fcf3ce44SJohn Forte 
4532*fcf3ce44SJohn Forte 	*nexus_path = NULL;
4533*fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path_phys);
4534*fcf3ce44SJohn Forte 
4535*fcf3ce44SJohn Forte 	if (strstr(path_phys, SCSI_VHCI)) {
4536*fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path, &pathlist)) {
4537*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4538*fcf3ce44SJohn Forte 		}
4539*fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
4540*fcf3ce44SJohn Forte 		p_on = p_st = 0;
4541*fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
4542*fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
4543*fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
4544*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_ONLINE) {
4545*fcf3ce44SJohn Forte 					p_on = i;
4546*fcf3ce44SJohn Forte 					break;
4547*fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
4548*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_STANDBY) {
4549*fcf3ce44SJohn Forte 					p_st = i;
4550*fcf3ce44SJohn Forte 				}
4551*fcf3ce44SJohn Forte 			}
4552*fcf3ce44SJohn Forte 		}
4553*fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
4554*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
4555*fcf3ce44SJohn Forte 			/* on_line path */
4556*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4557*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_hba);
4558*fcf3ce44SJohn Forte 		} else {
4559*fcf3ce44SJohn Forte 			/* standby or path0 */
4560*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4561*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_hba);
4562*fcf3ce44SJohn Forte 		}
4563*fcf3ce44SJohn Forte 		free(pathlist.path_info);
4564*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
4565*fcf3ce44SJohn Forte 	} else {
4566*fcf3ce44SJohn Forte 		if (strstr(drvr_path, DRV_NAME_SSD) || strstr(drvr_path,
4567*fcf3ce44SJohn Forte 			DRV_NAME_ST) || strstr(drvr_path, SES_NAME)) {
4568*fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4569*fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
4570*fcf3ce44SJohn Forte 			}
4571*fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate string  */
4572*fcf3ce44SJohn Forte 		}
4573*fcf3ce44SJohn Forte 
4574*fcf3ce44SJohn Forte 	path_type = g_get_path_type(drvr_path);
4575*fcf3ce44SJohn Forte 
4576*fcf3ce44SJohn Forte 	if (path_type & FC4_SF_XPORT) {
4577*fcf3ce44SJohn Forte 
4578*fcf3ce44SJohn Forte 		/* sf driver in path so capture the port # */
4579*fcf3ce44SJohn Forte 		if ((char_ptr = strstr(drvr_path, "sf@")) == NULL) {
4580*fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
4581*fcf3ce44SJohn Forte 		}
4582*fcf3ce44SJohn Forte 		port = atoi(char_ptr + 3);
4583*fcf3ce44SJohn Forte 		if (port > 1) {
4584*fcf3ce44SJohn Forte 			return (L_INVLD_PORT_IN_PATH);
4585*fcf3ce44SJohn Forte 		}
4586*fcf3ce44SJohn Forte 
4587*fcf3ce44SJohn Forte 		if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4588*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4589*fcf3ce44SJohn Forte 		}
4590*fcf3ce44SJohn Forte 		*char_ptr = '\0';   /* Terminate string  */
4591*fcf3ce44SJohn Forte 		port_flag++;
4592*fcf3ce44SJohn Forte 
4593*fcf3ce44SJohn Forte 		L_DPRINTF("  g_get_nexus_path:"
4594*fcf3ce44SJohn Forte 			" sf driver in path so use port #%d.\n",
4595*fcf3ce44SJohn Forte 			port);
4596*fcf3ce44SJohn Forte 	} else if (path_type & FC_GEN_XPORT) {
4597*fcf3ce44SJohn Forte 		/*
4598*fcf3ce44SJohn Forte 		 * check to see if it 3rd party vendor FCA.
4599*fcf3ce44SJohn Forte 		 * if it is return error for this operation since
4600*fcf3ce44SJohn Forte 		 * we don't know how they creates FCA port related minor node.
4601*fcf3ce44SJohn Forte 		 *
4602*fcf3ce44SJohn Forte 		 * As of now there is no supported operation on FCA node so
4603*fcf3ce44SJohn Forte 		 * this should be okay.
4604*fcf3ce44SJohn Forte 		 */
4605*fcf3ce44SJohn Forte 		if ((path_type & FC_FCA_MASK) == FC_FCA_MASK) {
4606*fcf3ce44SJohn Forte 			return (L_INVALID_PATH_TYPE);
4607*fcf3ce44SJohn Forte 		}
4608*fcf3ce44SJohn Forte 		/*
4609*fcf3ce44SJohn Forte 		 * For current Sun FCA driver, appending
4610*fcf3ce44SJohn Forte 		 * port # doesn't work. Just remove transport layer from
4611*fcf3ce44SJohn Forte 		 * input path.
4612*fcf3ce44SJohn Forte 		 */
4613*fcf3ce44SJohn Forte 		if ((char_ptr = strstr(drvr_path, "/fp@")) == NULL) {
4614*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4615*fcf3ce44SJohn Forte 		}
4616*fcf3ce44SJohn Forte 		*char_ptr = '\0';   /* Terminate string  */
4617*fcf3ce44SJohn Forte 	}
4618*fcf3ce44SJohn Forte 
4619*fcf3ce44SJohn Forte 	if (stat(drvr_path, &stbuf) != 0) {
4620*fcf3ce44SJohn Forte 		return (L_LSTAT_ERROR);
4621*fcf3ce44SJohn Forte 	}
4622*fcf3ce44SJohn Forte 
4623*fcf3ce44SJohn Forte 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
4624*fcf3ce44SJohn Forte 		/*
4625*fcf3ce44SJohn Forte 		 * Found a directory.
4626*fcf3ce44SJohn Forte 		 * Now append a port number or devctl to the path.
4627*fcf3ce44SJohn Forte 		 */
4628*fcf3ce44SJohn Forte 		if (port_flag) {
4629*fcf3ce44SJohn Forte 			/* append port */
4630*fcf3ce44SJohn Forte 			(void) sprintf(buf, ":%d", port);
4631*fcf3ce44SJohn Forte 		} else {
4632*fcf3ce44SJohn Forte 			/* Try adding port 0 and see if node exists. */
4633*fcf3ce44SJohn Forte 			(void) sprintf(temp_buf, "%s:0", drvr_path);
4634*fcf3ce44SJohn Forte 			if (stat(temp_buf, &stbuf) != 0) {
4635*fcf3ce44SJohn Forte 				/*
4636*fcf3ce44SJohn Forte 				 * Path we guessed at does not
4637*fcf3ce44SJohn Forte 				 * exist so it may be a driver
4638*fcf3ce44SJohn Forte 				 * that ends in :devctl.
4639*fcf3ce44SJohn Forte 				 */
4640*fcf3ce44SJohn Forte 				(void) sprintf(buf, ":devctl");
4641*fcf3ce44SJohn Forte 			} else {
4642*fcf3ce44SJohn Forte 				/*
4643*fcf3ce44SJohn Forte 				 * The path that was entered
4644*fcf3ce44SJohn Forte 				 * did not include a port number
4645*fcf3ce44SJohn Forte 				 * so the port was set to zero, and
4646*fcf3ce44SJohn Forte 				 * then checked. The default path
4647*fcf3ce44SJohn Forte 				 * did exist.
4648*fcf3ce44SJohn Forte 				 */
4649*fcf3ce44SJohn Forte 				ER_DPRINTF("Since a complete path"
4650*fcf3ce44SJohn Forte 					" was not supplied "
4651*fcf3ce44SJohn Forte 					"a default path is being"
4652*fcf3ce44SJohn Forte 					" used:\n  %s\n",
4653*fcf3ce44SJohn Forte 					temp_buf);
4654*fcf3ce44SJohn Forte 				(void) sprintf(buf, ":0");
4655*fcf3ce44SJohn Forte 			}
4656*fcf3ce44SJohn Forte 		}
4657*fcf3ce44SJohn Forte 
4658*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, buf);
4659*fcf3ce44SJohn Forte 	}
4660*fcf3ce44SJohn Forte 
4661*fcf3ce44SJohn Forte 	}
4662*fcf3ce44SJohn Forte 	*nexus_path = g_alloc_string(drvr_path);
4663*fcf3ce44SJohn Forte 	L_DPRINTF("  g_get_nexus_path: Nexus path = %s\n", drvr_path);
4664*fcf3ce44SJohn Forte 	return (0);
4665*fcf3ce44SJohn Forte }
4666*fcf3ce44SJohn Forte 
4667*fcf3ce44SJohn Forte 
4668*fcf3ce44SJohn Forte /*
4669*fcf3ce44SJohn Forte  * Get the FC topology for the input device or nexus(HBA) path.
4670*fcf3ce44SJohn Forte  *
4671*fcf3ce44SJohn Forte  * The routine calls g_get_path_type to determine the stack of
4672*fcf3ce44SJohn Forte  * the input path.
4673*fcf3ce44SJohn Forte  *
4674*fcf3ce44SJohn Forte  * 	If it a socal path
4675*fcf3ce44SJohn Forte  *		it returns FC_TOP_PRIVATE_LOOP
4676*fcf3ce44SJohn Forte  *	else
4677*fcf3ce44SJohn Forte  *		calls fc_get_topology ioctl to
4678*fcf3ce44SJohn Forte  *		get the fp topolgy from the driver.
4679*fcf3ce44SJohn Forte  *
4680*fcf3ce44SJohn Forte  * INPUTS:
4681*fcf3ce44SJohn Forte  *	path - a string of device path, transport path.
4682*fcf3ce44SJohn Forte  *		NOTE:  "path" SHOULD NOT BE OPEN BEFORE CALLING
4683*fcf3ce44SJohn Forte  *			THIS FUNCTION BECAUSE THIS FUNCTION DOES
4684*fcf3ce44SJohn Forte  *			AN "O_EXCL" OPEN.
4685*fcf3ce44SJohn Forte  *	port_top - a pointer to the toplogy type.
4686*fcf3ce44SJohn Forte  *
4687*fcf3ce44SJohn Forte  * RETURNS:
4688*fcf3ce44SJohn Forte  *	0 if there is no error.
4689*fcf3ce44SJohn Forte  *	error code.
4690*fcf3ce44SJohn Forte  *
4691*fcf3ce44SJohn Forte  * The input path is expected to be something like below:
4692*fcf3ce44SJohn Forte  * 	1)
4693*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4694*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@..
4695*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
4696*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0
4697*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0:1
4698*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4699*fcf3ce44SJohn Forte  * 	(or "qlc" instead of "socal" and "fp" for "sf")
4700*fcf3ce44SJohn Forte  *
4701*fcf3ce44SJohn Forte  * 	Which should resolve to a path like this:
4702*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0:1
4703*fcf3ce44SJohn Forte  * 	/devices/pci@6,2000/pci@2/SUNW,qlc@5
4704*fcf3ce44SJohn Forte  *
4705*fcf3ce44SJohn Forte  * 	2)
4706*fcf3ce44SJohn Forte  * 	/devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
4707*fcf3ce44SJohn Forte  * 	which should resolve to
4708*fcf3ce44SJohn Forte  * 	/devices/pci@4,2000/scsi@1:devctl
4709*fcf3ce44SJohn Forte  *
4710*fcf3ce44SJohn Forte  *      3) The nexus(hba or nexus) path will get an error only for qlc
4711*fcf3ce44SJohn Forte  *	since the routine need to open fp :devctl node for fcio ioctl.
4712*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0
4713*fcf3ce44SJohn Forte  * 	/devices/sbus@1f,0/SUNW,socal@1,0:1
4714*fcf3ce44SJohn Forte  * 	/devices/pci@6,2000/pci@2/SUNW,qlc@5 => error
4715*fcf3ce44SJohn Forte  */
4716*fcf3ce44SJohn Forte int
4717*fcf3ce44SJohn Forte g_get_fca_port_topology(char *path, uint32_t *port_top, int verbose)
4718*fcf3ce44SJohn Forte {
4719*fcf3ce44SJohn Forte fcio_t		fcio;
4720*fcf3ce44SJohn Forte int		fd, i = 0, pathcnt = 1;
4721*fcf3ce44SJohn Forte char		drvr_path[MAXPATHLEN];
4722*fcf3ce44SJohn Forte char		*char_ptr;
4723*fcf3ce44SJohn Forte struct stat	stbuf;
4724*fcf3ce44SJohn Forte uint_t		dev_type;
4725*fcf3ce44SJohn Forte mp_pathlist_t	pathlist;
4726*fcf3ce44SJohn Forte int		p_on = 0, p_st = 0;
4727*fcf3ce44SJohn Forte 
4728*fcf3ce44SJohn Forte 	/* return invalid path if the path is NULL */
4729*fcf3ce44SJohn Forte 	if (path == NULL) {
4730*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4731*fcf3ce44SJohn Forte 	}
4732*fcf3ce44SJohn Forte 	/* return invalid arg if the argument is NULL */
4733*fcf3ce44SJohn Forte 	if (port_top == NULL) {
4734*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
4735*fcf3ce44SJohn Forte 	}
4736*fcf3ce44SJohn Forte 
4737*fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
4738*fcf3ce44SJohn Forte 	if (strstr(path, SCSI_VHCI)) {
4739*fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path, &pathlist)) {
4740*fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4741*fcf3ce44SJohn Forte 		}
4742*fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
4743*fcf3ce44SJohn Forte 		p_on = p_st = 0;
4744*fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
4745*fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
4746*fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
4747*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_ONLINE) {
4748*fcf3ce44SJohn Forte 					p_on = i;
4749*fcf3ce44SJohn Forte 					break;
4750*fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
4751*fcf3ce44SJohn Forte 					MDI_PATHINFO_STATE_STANDBY) {
4752*fcf3ce44SJohn Forte 					p_st = i;
4753*fcf3ce44SJohn Forte 				}
4754*fcf3ce44SJohn Forte 			}
4755*fcf3ce44SJohn Forte 		}
4756*fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
4757*fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
4758*fcf3ce44SJohn Forte 			/* on_line path */
4759*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4760*fcf3ce44SJohn Forte 				pathlist.path_info[p_on].path_hba);
4761*fcf3ce44SJohn Forte 		} else {
4762*fcf3ce44SJohn Forte 			/* standby or path0 */
4763*fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4764*fcf3ce44SJohn Forte 				pathlist.path_info[p_st].path_hba);
4765*fcf3ce44SJohn Forte 		}
4766*fcf3ce44SJohn Forte 		free(pathlist.path_info);
4767*fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
4768*fcf3ce44SJohn Forte 	} else {
4769*fcf3ce44SJohn Forte 	/*
4770*fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
4771*fcf3ce44SJohn Forte 	 *
4772*fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
4773*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4774*fcf3ce44SJohn Forte 	 * or
4775*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
4776*fcf3ce44SJohn Forte 	 * or
4777*fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4778*fcf3ce44SJohn Forte 	 * or
4779*fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
4780*fcf3ce44SJohn Forte 	 * (or "qlc" in the place of "socal" and "fp" for "sf")
4781*fcf3ce44SJohn Forte 	 *
4782*fcf3ce44SJohn Forte 	 * The dir below doesn't have corresponding :devctl node.
4783*fcf3ce44SJohn Forte 	 * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4784*fcf3ce44SJohn Forte 	 * /devices/sbus@2,0/SUNW,socal@1,0
4785*fcf3ce44SJohn Forte 	 *
4786*fcf3ce44SJohn Forte 	 */
4787*fcf3ce44SJohn Forte 		if ((strstr(drvr_path, DRV_NAME_SSD) ||
4788*fcf3ce44SJohn Forte 			strstr(drvr_path, SES_NAME)) ||
4789*fcf3ce44SJohn Forte 			strstr(drvr_path, DRV_NAME_ST)) {
4790*fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4791*fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
4792*fcf3ce44SJohn Forte 			}
4793*fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate sting  */
4794*fcf3ce44SJohn Forte 			/* append controller */
4795*fcf3ce44SJohn Forte 			(void) strcat(drvr_path, FC_CTLR);
4796*fcf3ce44SJohn Forte 		} else {
4797*fcf3ce44SJohn Forte 			if (stat(drvr_path, &stbuf) < 0) {
4798*fcf3ce44SJohn Forte 				return (L_LSTAT_ERROR);
4799*fcf3ce44SJohn Forte 			}
4800*fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
4801*fcf3ce44SJohn Forte 				/* append controller */
4802*fcf3ce44SJohn Forte 				(void) strcat(drvr_path, FC_CTLR);
4803*fcf3ce44SJohn Forte 			}
4804*fcf3ce44SJohn Forte 		}
4805*fcf3ce44SJohn Forte 	}
4806*fcf3ce44SJohn Forte 
4807*fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(drvr_path)) == 0) {
4808*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4809*fcf3ce44SJohn Forte 	}
4810*fcf3ce44SJohn Forte 
4811*fcf3ce44SJohn Forte 	if ((dev_type & FC4_XPORT_MASK) || (dev_type & FC4_FCA_MASK)) {
4812*fcf3ce44SJohn Forte 		*port_top = FC_TOP_PRIVATE_LOOP;
4813*fcf3ce44SJohn Forte 		return (0);
4814*fcf3ce44SJohn Forte 	}
4815*fcf3ce44SJohn Forte 
4816*fcf3ce44SJohn Forte 	/* To contiue the path type should be fp :devctl node */
4817*fcf3ce44SJohn Forte 	if (!(dev_type & FC_XPORT_MASK)) {
4818*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4819*fcf3ce44SJohn Forte 	}
4820*fcf3ce44SJohn Forte 
4821*fcf3ce44SJohn Forte 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
4822*fcf3ce44SJohn Forte 		return (errno);
4823*fcf3ce44SJohn Forte 
4824*fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_fca_port_topology: Geting topology from:"
4825*fcf3ce44SJohn Forte 		" %s\n", drvr_path);
4826*fcf3ce44SJohn Forte 
4827*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_TOPOLOGY;
4828*fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (uint32_t);
4829*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
4830*fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)port_top;
4831*fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
4832*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n");
4833*fcf3ce44SJohn Forte 		close(fd);
4834*fcf3ce44SJohn Forte 		return (L_FCIO_GET_TOPOLOGY_FAIL);
4835*fcf3ce44SJohn Forte 	}
4836*fcf3ce44SJohn Forte 	close(fd);
4837*fcf3ce44SJohn Forte 	return (0);
4838*fcf3ce44SJohn Forte }
4839*fcf3ce44SJohn Forte 
4840*fcf3ce44SJohn Forte 
4841*fcf3ce44SJohn Forte /*
4842*fcf3ce44SJohn Forte  * This functions enables or disables a FCA port depending on the
4843*fcf3ce44SJohn Forte  * argument, cmd, passed to it. If cmd is PORT_OFFLINE, the function
4844*fcf3ce44SJohn Forte  * tries to disable the port specified by the argument 'phys_path'. If
4845*fcf3ce44SJohn Forte  * cmd is PORT_ONLINE, the function tries to enable the port specified
4846*fcf3ce44SJohn Forte  * by the argument 'phys_path'.
4847*fcf3ce44SJohn Forte  * INPUTS :
4848*fcf3ce44SJohn Forte  *	nexus_port_ptr - Pointer to the nexus path of the FCA port to
4849*fcf3ce44SJohn Forte  *			operate on
4850*fcf3ce44SJohn Forte  *	cmd       - PORT_OFFLINE or PORT_ONLINE
4851*fcf3ce44SJohn Forte  * RETURNS :
4852*fcf3ce44SJohn Forte  *	0 on success and non-zero otherwise
4853*fcf3ce44SJohn Forte  */
4854*fcf3ce44SJohn Forte static int
4855*fcf3ce44SJohn Forte g_set_port_state(char *nexus_port_ptr, int cmd)
4856*fcf3ce44SJohn Forte {
4857*fcf3ce44SJohn Forte 	int	path_type, fd;
4858*fcf3ce44SJohn Forte 
4859*fcf3ce44SJohn Forte 	if ((path_type = g_get_path_type(nexus_port_ptr)) == 0) {
4860*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4861*fcf3ce44SJohn Forte 	}
4862*fcf3ce44SJohn Forte 
4863*fcf3ce44SJohn Forte 	if ((fd = g_object_open(nexus_port_ptr, O_NDELAY|O_RDONLY)) == -1) {
4864*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4865*fcf3ce44SJohn Forte 	}
4866*fcf3ce44SJohn Forte 
4867*fcf3ce44SJohn Forte 	switch (cmd) {
4868*fcf3ce44SJohn Forte 		case PORT_OFFLINE:
4869*fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
4870*fcf3ce44SJohn Forte 				/*
4871*fcf3ce44SJohn Forte 				 * Socal/sf drivers -
4872*fcf3ce44SJohn Forte 				 * The socal driver currently returns EFAULT
4873*fcf3ce44SJohn Forte 				 * even if the ioctl has completed successfully.
4874*fcf3ce44SJohn Forte 				 */
4875*fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
4876*fcf3ce44SJohn Forte 							NULL) == -1) {
4877*fcf3ce44SJohn Forte 					close(fd);
4878*fcf3ce44SJohn Forte 					return (L_PORT_OFFLINE_FAIL);
4879*fcf3ce44SJohn Forte 				}
4880*fcf3ce44SJohn Forte 			} else {
4881*fcf3ce44SJohn Forte 				/*
4882*fcf3ce44SJohn Forte 				 * QLogic card -
4883*fcf3ce44SJohn Forte 				 * Can't do much here since the driver currently
4884*fcf3ce44SJohn Forte 				 * doesn't support this feature. We'll just fail
4885*fcf3ce44SJohn Forte 				 * for now. Support can be added when the driver
4886*fcf3ce44SJohn Forte 				 * is enabled with the feature at a later date.
4887*fcf3ce44SJohn Forte 				 */
4888*fcf3ce44SJohn Forte 				close(fd);
4889*fcf3ce44SJohn Forte 				return (L_PORT_OFFLINE_UNSUPPORTED);
4890*fcf3ce44SJohn Forte 			}
4891*fcf3ce44SJohn Forte 			break;
4892*fcf3ce44SJohn Forte 		case PORT_ONLINE:
4893*fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
4894*fcf3ce44SJohn Forte 				/*
4895*fcf3ce44SJohn Forte 				 * Socal/sf drivers
4896*fcf3ce44SJohn Forte 				 * The socal driver currently returns EFAULT
4897*fcf3ce44SJohn Forte 				 * even if the ioctl has completed successfully.
4898*fcf3ce44SJohn Forte 				 */
4899*fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
4900*fcf3ce44SJohn Forte 					close(fd);
4901*fcf3ce44SJohn Forte 					return (L_PORT_ONLINE_FAIL);
4902*fcf3ce44SJohn Forte 				}
4903*fcf3ce44SJohn Forte 			} else {
4904*fcf3ce44SJohn Forte 				/*
4905*fcf3ce44SJohn Forte 				 * QLogic card -
4906*fcf3ce44SJohn Forte 				 * Can't do much here since the driver currently
4907*fcf3ce44SJohn Forte 				 * doesn't support this feature. We'll just fail
4908*fcf3ce44SJohn Forte 				 * for now. Support can be added when the driver
4909*fcf3ce44SJohn Forte 				 * is enabled with the feature at a later date.
4910*fcf3ce44SJohn Forte 				 */
4911*fcf3ce44SJohn Forte 				close(fd);
4912*fcf3ce44SJohn Forte 				return (L_PORT_ONLINE_UNSUPPORTED);
4913*fcf3ce44SJohn Forte 			}
4914*fcf3ce44SJohn Forte 			break;
4915*fcf3ce44SJohn Forte 		default:
4916*fcf3ce44SJohn Forte 			close(fd);
4917*fcf3ce44SJohn Forte 			return (-1);
4918*fcf3ce44SJohn Forte 	}
4919*fcf3ce44SJohn Forte 	close(fd);
4920*fcf3ce44SJohn Forte 	return (0);
4921*fcf3ce44SJohn Forte }
4922*fcf3ce44SJohn Forte 
4923*fcf3ce44SJohn Forte /*
4924*fcf3ce44SJohn Forte  * The interfaces defined below (g_port_offline() and g_port_online())
4925*fcf3ce44SJohn Forte  * are what will be exposed to applications. We will hide g_set_port_state().
4926*fcf3ce44SJohn Forte  * They have to be functions (as against macros) because making them
4927*fcf3ce44SJohn Forte  * macros will mean exposing g_set_port_state() and we dont want to do that
4928*fcf3ce44SJohn Forte  */
4929*fcf3ce44SJohn Forte 
4930*fcf3ce44SJohn Forte int
4931*fcf3ce44SJohn Forte g_port_offline(char *path)
4932*fcf3ce44SJohn Forte {
4933*fcf3ce44SJohn Forte 	return (g_set_port_state(path, PORT_OFFLINE));
4934*fcf3ce44SJohn Forte }
4935*fcf3ce44SJohn Forte 
4936*fcf3ce44SJohn Forte int
4937*fcf3ce44SJohn Forte g_port_online(char *path)
4938*fcf3ce44SJohn Forte {
4939*fcf3ce44SJohn Forte 	return (g_set_port_state(path, PORT_ONLINE));
4940*fcf3ce44SJohn Forte }
4941*fcf3ce44SJohn Forte 
4942*fcf3ce44SJohn Forte /*
4943*fcf3ce44SJohn Forte  * This function sets the loopback mode for a port on a HBA
4944*fcf3ce44SJohn Forte  * INPUTS :
4945*fcf3ce44SJohn Forte  *	portpath	- Pointer to the path of the FCA port on which to
4946*fcf3ce44SJohn Forte  *			set the loopback mode
4947*fcf3ce44SJohn Forte  *	cmd       	- EXT_LPBACK
4948*fcf3ce44SJohn Forte  *			  INT_LPBACK
4949*fcf3ce44SJohn Forte  *			  NO_LPBACK
4950*fcf3ce44SJohn Forte  * RETURNS :
4951*fcf3ce44SJohn Forte  *	0 on success and non-zero otherwise
4952*fcf3ce44SJohn Forte  */
4953*fcf3ce44SJohn Forte int
4954*fcf3ce44SJohn Forte g_loopback_mode(char *portpath, int cmd)
4955*fcf3ce44SJohn Forte {
4956*fcf3ce44SJohn Forte 	int	path_type, fd;
4957*fcf3ce44SJohn Forte 
4958*fcf3ce44SJohn Forte 	if ((path_type = g_get_path_type(portpath)) == 0) {
4959*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4960*fcf3ce44SJohn Forte 	}
4961*fcf3ce44SJohn Forte 
4962*fcf3ce44SJohn Forte 	if ((fd = g_object_open(portpath, O_NDELAY|O_RDONLY|O_EXCL)) == -1) {
4963*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4964*fcf3ce44SJohn Forte 	}
4965*fcf3ce44SJohn Forte 
4966*fcf3ce44SJohn Forte 	/*
4967*fcf3ce44SJohn Forte 	 * The loopback calls are currently not fully supported
4968*fcf3ce44SJohn Forte 	 * via fp.
4969*fcf3ce44SJohn Forte 	 *
4970*fcf3ce44SJohn Forte 	 * A fp based general solution is required to support Leadville FCAs
4971*fcf3ce44SJohn Forte 	 * including Qlgc and 3rd party FCA. As of now qlgc provides
4972*fcf3ce44SJohn Forte 	 * some diag functions like echo through qlc private ioctl
4973*fcf3ce44SJohn Forte 	 * which is not supproted by luxadm and libraries.
4974*fcf3ce44SJohn Forte 	 */
4975*fcf3ce44SJohn Forte 	switch (cmd) {
4976*fcf3ce44SJohn Forte 		case EXT_LPBACK:
4977*fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
4978*fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_LOOPBACK_MANUAL,
4979*fcf3ce44SJohn Forte 							NULL) == -1) {
4980*fcf3ce44SJohn Forte 					/* Check for previous mode set */
4981*fcf3ce44SJohn Forte 					if (errno != EALREADY) {
4982*fcf3ce44SJohn Forte 						close(fd);
4983*fcf3ce44SJohn Forte 						return (L_LOOPBACK_FAILED);
4984*fcf3ce44SJohn Forte 					}
4985*fcf3ce44SJohn Forte 				}
4986*fcf3ce44SJohn Forte 			} else {
4987*fcf3ce44SJohn Forte 				/*
4988*fcf3ce44SJohn Forte 				 * Well, it wasn't one of the above cards so..
4989*fcf3ce44SJohn Forte 				 */
4990*fcf3ce44SJohn Forte 				close(fd);
4991*fcf3ce44SJohn Forte 				return (L_LOOPBACK_UNSUPPORTED);
4992*fcf3ce44SJohn Forte 			}
4993*fcf3ce44SJohn Forte 			break;
4994*fcf3ce44SJohn Forte 		case NO_LPBACK:
4995*fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
4996*fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
4997*fcf3ce44SJohn Forte 					close(fd);
4998*fcf3ce44SJohn Forte 					return (L_LOOPBACK_FAILED);
4999*fcf3ce44SJohn Forte 				}
5000*fcf3ce44SJohn Forte 			} else {
5001*fcf3ce44SJohn Forte 				/*
5002*fcf3ce44SJohn Forte 				 * Well, it wasn't one of the above cards so..
5003*fcf3ce44SJohn Forte 				 */
5004*fcf3ce44SJohn Forte 				close(fd);
5005*fcf3ce44SJohn Forte 				return (L_LOOPBACK_UNSUPPORTED);
5006*fcf3ce44SJohn Forte 			}
5007*fcf3ce44SJohn Forte 			break;
5008*fcf3ce44SJohn Forte 		case INT_LPBACK:
5009*fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
5010*fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
5011*fcf3ce44SJohn Forte 					NULL) == -1) {
5012*fcf3ce44SJohn Forte 					/* Check for previous mode set */
5013*fcf3ce44SJohn Forte 					if (errno != EALREADY) {
5014*fcf3ce44SJohn Forte 						close(fd);
5015*fcf3ce44SJohn Forte 						return (L_LOOPBACK_FAILED);
5016*fcf3ce44SJohn Forte 					}
5017*fcf3ce44SJohn Forte 				}
5018*fcf3ce44SJohn Forte 			} else {
5019*fcf3ce44SJohn Forte 				/*
5020*fcf3ce44SJohn Forte 				 * Well, it wasn't one of the above cards so..
5021*fcf3ce44SJohn Forte 				 */
5022*fcf3ce44SJohn Forte 				close(fd);
5023*fcf3ce44SJohn Forte 				return (L_LOOPBACK_UNSUPPORTED);
5024*fcf3ce44SJohn Forte 			}
5025*fcf3ce44SJohn Forte 			break;
5026*fcf3ce44SJohn Forte 		default:
5027*fcf3ce44SJohn Forte 			close(fd);
5028*fcf3ce44SJohn Forte 			return (L_LOOPBACK_UNSUPPORTED);
5029*fcf3ce44SJohn Forte 	}
5030*fcf3ce44SJohn Forte 	close(fd);
5031*fcf3ce44SJohn Forte 	return (0);
5032*fcf3ce44SJohn Forte }
5033*fcf3ce44SJohn Forte 
5034*fcf3ce44SJohn Forte /*
5035*fcf3ce44SJohn Forte  * g_get_port_state(char *portpath, int port_state)
5036*fcf3ce44SJohn Forte  * Purpose: Get port state for a path
5037*fcf3ce44SJohn Forte  * Input:   portpath
5038*fcf3ce44SJohn Forte  *		set to path of port
5039*fcf3ce44SJohn Forte  * Output:  port_state
5040*fcf3ce44SJohn Forte  *	Set to one of the following:
5041*fcf3ce44SJohn Forte  *		PORT_CONNECTED
5042*fcf3ce44SJohn Forte  *		PORT_NOTCONNECTED
5043*fcf3ce44SJohn Forte  * Returns: 0 on success
5044*fcf3ce44SJohn Forte  *	    non-zero on failure
5045*fcf3ce44SJohn Forte  */
5046*fcf3ce44SJohn Forte int
5047*fcf3ce44SJohn Forte g_get_port_state(char *portpath, int *portstate, int verbose)
5048*fcf3ce44SJohn Forte {
5049*fcf3ce44SJohn Forte 	int	fd, err, num_devices = 0;
5050*fcf3ce44SJohn Forte 	struct lilpmap	map;
5051*fcf3ce44SJohn Forte 	uint_t	dev_type;
5052*fcf3ce44SJohn Forte 	gfc_dev_t	map_root;
5053*fcf3ce44SJohn Forte 
5054*fcf3ce44SJohn Forte 
5055*fcf3ce44SJohn Forte 	(void) memset(&map, 0, sizeof (struct lilpmap));
5056*fcf3ce44SJohn Forte 
5057*fcf3ce44SJohn Forte 	/* return invalid path if portpath is NULL */
5058*fcf3ce44SJohn Forte 	if (portpath == NULL) {
5059*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5060*fcf3ce44SJohn Forte 	}
5061*fcf3ce44SJohn Forte 	/* return invalid arg if argument is NULL */
5062*fcf3ce44SJohn Forte 	if ((portpath == NULL) || (portstate == NULL)) {
5063*fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
5064*fcf3ce44SJohn Forte 	}
5065*fcf3ce44SJohn Forte 
5066*fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(portpath)) == 0) {
5067*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5068*fcf3ce44SJohn Forte 	}
5069*fcf3ce44SJohn Forte 
5070*fcf3ce44SJohn Forte 	/*
5071*fcf3ce44SJohn Forte 	 * FCIO_GETMAP returns error when there are * no devices attached.
5072*fcf3ce44SJohn Forte 	 * ENOMEM is returned when no devices are attached.
5073*fcf3ce44SJohn Forte 	 * g_get_first_dev returns NULL without error when there is no
5074*fcf3ce44SJohn Forte 	 * devices are attached.
5075*fcf3ce44SJohn Forte 	 */
5076*fcf3ce44SJohn Forte 	if (dev_type & FC_FCA_MASK) {
5077*fcf3ce44SJohn Forte 		if ((map_root = g_dev_map_init(portpath, &err,
5078*fcf3ce44SJohn Forte 			MAP_XPORT_PROP_ONLY)) == NULL) {
5079*fcf3ce44SJohn Forte 			return (err);
5080*fcf3ce44SJohn Forte 		}
5081*fcf3ce44SJohn Forte 
5082*fcf3ce44SJohn Forte 		if (g_get_first_dev(map_root, &err) == NULL) {
5083*fcf3ce44SJohn Forte 			/* no device is found if err == 0 */
5084*fcf3ce44SJohn Forte 			if (err == L_NO_SUCH_DEV_FOUND) {
5085*fcf3ce44SJohn Forte 				*portstate = PORT_NOTCONNECTED;
5086*fcf3ce44SJohn Forte 			}
5087*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
5088*fcf3ce44SJohn Forte 			return (0);
5089*fcf3ce44SJohn Forte 		} else {
5090*fcf3ce44SJohn Forte 			/* Device found okay */
5091*fcf3ce44SJohn Forte 			*portstate = PORT_CONNECTED;
5092*fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
5093*fcf3ce44SJohn Forte 		}
5094*fcf3ce44SJohn Forte 
5095*fcf3ce44SJohn Forte 	} else {
5096*fcf3ce44SJohn Forte 		/* open controller */
5097*fcf3ce44SJohn Forte 		if ((fd = g_object_open(portpath, O_NDELAY | O_RDONLY)) == -1) {
5098*fcf3ce44SJohn Forte 			return (errno);
5099*fcf3ce44SJohn Forte 		}
5100*fcf3ce44SJohn Forte 
5101*fcf3ce44SJohn Forte 		/*
5102*fcf3ce44SJohn Forte 		 * Note: There is only one error returned by this ioctl. ENOMEM.
5103*fcf3ce44SJohn Forte 		 * Hence the lack of return on error.
5104*fcf3ce44SJohn Forte 		 */
5105*fcf3ce44SJohn Forte 		if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
5106*fcf3ce44SJohn Forte 			map.lilp_length = 0;
5107*fcf3ce44SJohn Forte 		}
5108*fcf3ce44SJohn Forte 		num_devices = map.lilp_length;
5109*fcf3ce44SJohn Forte 
5110*fcf3ce44SJohn Forte 		/* Non-Leadville stacks report the FCA in the count */
5111*fcf3ce44SJohn Forte 		*portstate = (num_devices > 1) ? PORT_CONNECTED :
5112*fcf3ce44SJohn Forte 							PORT_NOTCONNECTED;
5113*fcf3ce44SJohn Forte 		(void) close(fd);
5114*fcf3ce44SJohn Forte 	}
5115*fcf3ce44SJohn Forte 	return (0);
5116*fcf3ce44SJohn Forte }
5117*fcf3ce44SJohn Forte 
5118*fcf3ce44SJohn Forte /*
5119*fcf3ce44SJohn Forte  * g_dev_login(char *port_path, la_wwn_t port_wwn)
5120*fcf3ce44SJohn Forte  * Purpose: port login via g_dev_log_in_out()
5121*fcf3ce44SJohn Forte  * Input:   port_path
5122*fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5123*fcf3ce44SJohn Forte  *	    port_wwn
5124*fcf3ce44SJohn Forte  *		port wwn of device node to login
5125*fcf3ce44SJohn Forte  *
5126*fcf3ce44SJohn Forte  * Returns: return code from g_dev_log_in_out()
5127*fcf3ce44SJohn Forte  */
5128*fcf3ce44SJohn Forte int
5129*fcf3ce44SJohn Forte g_dev_login(char *port_path, la_wwn_t port_wwn)
5130*fcf3ce44SJohn Forte {
5131*fcf3ce44SJohn Forte 	return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGIN));
5132*fcf3ce44SJohn Forte }
5133*fcf3ce44SJohn Forte 
5134*fcf3ce44SJohn Forte 
5135*fcf3ce44SJohn Forte /*
5136*fcf3ce44SJohn Forte  * g_dev_logout(char *port_path, la_wwn_t port_wwn)
5137*fcf3ce44SJohn Forte  * Purpose: port login via g_dev_log_in_out()
5138*fcf3ce44SJohn Forte  * Input:   port_path
5139*fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5140*fcf3ce44SJohn Forte  *	    port_wwn
5141*fcf3ce44SJohn Forte  *		port wwn of device node to logout
5142*fcf3ce44SJohn Forte  *
5143*fcf3ce44SJohn Forte  * Returns: return code from g_dev_log_in_out()
5144*fcf3ce44SJohn Forte  */
5145*fcf3ce44SJohn Forte int
5146*fcf3ce44SJohn Forte g_dev_logout(char *port_path, la_wwn_t port_wwn)
5147*fcf3ce44SJohn Forte {
5148*fcf3ce44SJohn Forte 	return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGOUT));
5149*fcf3ce44SJohn Forte }
5150*fcf3ce44SJohn Forte 
5151*fcf3ce44SJohn Forte 
5152*fcf3ce44SJohn Forte /*
5153*fcf3ce44SJohn Forte  * g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
5154*fcf3ce44SJohn Forte  * Purpose: port login via FCIO_DEV_LOGOUT and port logout via FCIO_DEV_LOGOUT
5155*fcf3ce44SJohn Forte  *	    IOCTL requires EXCLUSIVE open.
5156*fcf3ce44SJohn Forte  * Input:   port_path
5157*fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5158*fcf3ce44SJohn Forte  *	    port_wwn
5159*fcf3ce44SJohn Forte  *		port wwn of device node to logout
5160*fcf3ce44SJohn Forte  *	    cmd
5161*fcf3ce44SJohn Forte  *		FCIO_DEV_LOGON or FCIO_DEV_LOGOUT
5162*fcf3ce44SJohn Forte  *
5163*fcf3ce44SJohn Forte  * Returns: 0 on success
5164*fcf3ce44SJohn Forte  *	    non-zero on failure
5165*fcf3ce44SJohn Forte  */
5166*fcf3ce44SJohn Forte static int
5167*fcf3ce44SJohn Forte g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
5168*fcf3ce44SJohn Forte {
5169*fcf3ce44SJohn Forte int		fd, err;
5170*fcf3ce44SJohn Forte uint32_t	hba_port_top;
5171*fcf3ce44SJohn Forte fcio_t		fcio;
5172*fcf3ce44SJohn Forte int		verbose = 0;
5173*fcf3ce44SJohn Forte 
5174*fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(port_path,
5175*fcf3ce44SJohn Forte 		&hba_port_top, verbose)) != 0) {
5176*fcf3ce44SJohn Forte 		return (err);
5177*fcf3ce44SJohn Forte 	}
5178*fcf3ce44SJohn Forte 
5179*fcf3ce44SJohn Forte 	if (!((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
5180*fcf3ce44SJohn Forte 		(hba_port_top == FC_TOP_FABRIC))) {
5181*fcf3ce44SJohn Forte 		return (L_OPNOSUPP_ON_TOPOLOGY);
5182*fcf3ce44SJohn Forte 	}
5183*fcf3ce44SJohn Forte 
5184*fcf3ce44SJohn Forte 	/* open controller */
5185*fcf3ce44SJohn Forte 	if ((fd = g_object_open(port_path, O_NDELAY | O_RDONLY | O_EXCL)) == -1)
5186*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
5187*fcf3ce44SJohn Forte 
5188*fcf3ce44SJohn Forte 	/*
5189*fcf3ce44SJohn Forte 	 * stores port_wwn to la_wwn_t raw_wwn field
5190*fcf3ce44SJohn Forte 	 * and construct fcio structures for FCIO_DEV_LOGIN.
5191*fcf3ce44SJohn Forte 	 */
5192*fcf3ce44SJohn Forte 	fcio.fcio_cmd = cmd;
5193*fcf3ce44SJohn Forte 	fcio.fcio_ilen = sizeof (port_wwn);
5194*fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)&port_wwn;
5195*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_WRITE;
5196*fcf3ce44SJohn Forte 	fcio.fcio_olen = fcio.fcio_alen = 0;
5197*fcf3ce44SJohn Forte 	fcio.fcio_obuf = fcio.fcio_abuf = NULL;
5198*fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
5199*fcf3ce44SJohn Forte 		I_DPRINTF((cmd == FCIO_DEV_LOGIN) ?
5200*fcf3ce44SJohn Forte 			" FCIO_DEV_LOGIN ioctl failed.\n"
5201*fcf3ce44SJohn Forte 			: " FCIO_DEV_LOGOUT ioctl failed.\n");
5202*fcf3ce44SJohn Forte 		(void) close(fd);
5203*fcf3ce44SJohn Forte 		return ((cmd == FCIO_DEV_LOGIN) ?
5204*fcf3ce44SJohn Forte 			L_FCIO_DEV_LOGIN_FAIL
5205*fcf3ce44SJohn Forte 			: L_FCIO_DEV_LOGOUT_FAIL);
5206*fcf3ce44SJohn Forte 	} else {
5207*fcf3ce44SJohn Forte 		(void) close(fd);
5208*fcf3ce44SJohn Forte 		return (0);
5209*fcf3ce44SJohn Forte 	}
5210*fcf3ce44SJohn Forte }
5211*fcf3ce44SJohn Forte 
5212*fcf3ce44SJohn Forte /*
5213*fcf3ce44SJohn Forte  * This function will verify if a FC device (represented by input WWN
5214*fcf3ce44SJohn Forte  * is connected on a FCA port by searching the device list from
5215*fcf3ce44SJohn Forte  * g_get_dev_list() for a WWN match.
5216*fcf3ce44SJohn Forte  *
5217*fcf3ce44SJohn Forte  * input:
5218*fcf3ce44SJohn Forte  *   fca_path: pointer to the physical path string, path to a fp node.
5219*fcf3ce44SJohn Forte  *             possible forms are
5220*fcf3ce44SJohn Forte  *		/devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl
5221*fcf3ce44SJohn Forte  *   dev_wwn: WWN string
5222*fcf3ce44SJohn Forte  *   flag: indicate that the input WWN is node or port
5223*fcf3ce44SJohn Forte  *
5224*fcf3ce44SJohn Forte  * returned values
5225*fcf3ce44SJohn Forte  *   0: if a match is found.
5226*fcf3ce44SJohn Forte  *   L_WWN_NOT_FOUND_IN_DEV_LIST: if no match found
5227*fcf3ce44SJohn Forte  *   L_UNEXPECTED_FC_TOPOLOGY: existing error code for an error
5228*fcf3ce44SJohn Forte  *	from the topology checking of the input fca path.
5229*fcf3ce44SJohn Forte  *   L_MALLOC_FAILED: existing error code for allocation eror from the
5230*fcf3ce44SJohn Forte  *	g_get_dev_list().
5231*fcf3ce44SJohn Forte  *   L_FCIO_GETMAP_IOCTL_FAIL: existing error code for an error from the
5232*fcf3ce44SJohn Forte  *	FCIO ioctl called by the g_get_dev_list()
5233*fcf3ce44SJohn Forte  *   -1: other failure
5234*fcf3ce44SJohn Forte  *
5235*fcf3ce44SJohn Forte  */
5236*fcf3ce44SJohn Forte int
5237*fcf3ce44SJohn Forte g_wwn_in_dev_list(char *fca_path, la_wwn_t dev_wwn, int flag)
5238*fcf3ce44SJohn Forte {
5239*fcf3ce44SJohn Forte uint_t		dev_type;
5240*fcf3ce44SJohn Forte int		i, err;
5241*fcf3ce44SJohn Forte fc_port_dev_t	*dev_list;
5242*fcf3ce44SJohn Forte fc_port_dev_t	*dev_list_save;
5243*fcf3ce44SJohn Forte int		num_devices = 0;
5244*fcf3ce44SJohn Forte 
5245*fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(fca_path)) == 0) {
5246*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5247*fcf3ce44SJohn Forte 	}
5248*fcf3ce44SJohn Forte 
5249*fcf3ce44SJohn Forte 	if (!(dev_type & FC_XPORT_MASK)) {
5250*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
5251*fcf3ce44SJohn Forte 	}
5252*fcf3ce44SJohn Forte 
5253*fcf3ce44SJohn Forte 	if (((err = g_get_dev_list(fca_path, &dev_list, &num_devices))
5254*fcf3ce44SJohn Forte 		!= 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) {
5255*fcf3ce44SJohn Forte 		return (err);
5256*fcf3ce44SJohn Forte 	}
5257*fcf3ce44SJohn Forte 
5258*fcf3ce44SJohn Forte 	dev_list_save = dev_list;
5259*fcf3ce44SJohn Forte 
5260*fcf3ce44SJohn Forte 	switch (flag) {
5261*fcf3ce44SJohn Forte 	case MATCH_NODE_WWN:
5262*fcf3ce44SJohn Forte 		for (i = 0; i < num_devices; i++, dev_list++) {
5263*fcf3ce44SJohn Forte 			if (memcmp(dev_list->dev_nwwn.raw_wwn,
5264*fcf3ce44SJohn Forte 					dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
5265*fcf3ce44SJohn Forte 				(void) free(dev_list_save);
5266*fcf3ce44SJohn Forte 				return (0);
5267*fcf3ce44SJohn Forte 			}
5268*fcf3ce44SJohn Forte 		}
5269*fcf3ce44SJohn Forte 		(void) free(dev_list_save);
5270*fcf3ce44SJohn Forte 		/* consider a new error code for not found. */
5271*fcf3ce44SJohn Forte 		return (L_WWN_NOT_FOUND_IN_DEV_LIST);
5272*fcf3ce44SJohn Forte 
5273*fcf3ce44SJohn Forte 	case MATCH_PORT_WWN:
5274*fcf3ce44SJohn Forte 		for (i = 0; i < num_devices; i++, dev_list++) {
5275*fcf3ce44SJohn Forte 			if (memcmp(dev_list->dev_pwwn.raw_wwn,
5276*fcf3ce44SJohn Forte 					dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
5277*fcf3ce44SJohn Forte 				(void) free(dev_list_save);
5278*fcf3ce44SJohn Forte 				return (0);
5279*fcf3ce44SJohn Forte 			}
5280*fcf3ce44SJohn Forte 		}
5281*fcf3ce44SJohn Forte 		(void) free(dev_list_save);
5282*fcf3ce44SJohn Forte 		/* consider a new error code for not found. */
5283*fcf3ce44SJohn Forte 		return (L_WWN_NOT_FOUND_IN_DEV_LIST);
5284*fcf3ce44SJohn Forte 	}
5285*fcf3ce44SJohn Forte 	(void) free(dev_list_save);
5286*fcf3ce44SJohn Forte 	return (-1);
5287*fcf3ce44SJohn Forte }
5288*fcf3ce44SJohn Forte 
5289*fcf3ce44SJohn Forte 
5290*fcf3ce44SJohn Forte /*
5291*fcf3ce44SJohn Forte  * g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
5292*fcf3ce44SJohn Forte  * Purpose: get the state of device port login via FCIO_GET_STATE ioctl.
5293*fcf3ce44SJohn Forte  *
5294*fcf3ce44SJohn Forte  * Input:   fca_path
5295*fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5296*fcf3ce44SJohn Forte  *	    port_wwn
5297*fcf3ce44SJohn Forte  *		port wwn of device node to logout
5298*fcf3ce44SJohn Forte  *	    state
5299*fcf3ce44SJohn Forte  *		port login or not
5300*fcf3ce44SJohn Forte  *
5301*fcf3ce44SJohn Forte  * Returns: 0 on success
5302*fcf3ce44SJohn Forte  *	    non-zero on failure
5303*fcf3ce44SJohn Forte  */
5304*fcf3ce44SJohn Forte static int
5305*fcf3ce44SJohn Forte g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
5306*fcf3ce44SJohn Forte {
5307*fcf3ce44SJohn Forte int		fd;
5308*fcf3ce44SJohn Forte int		dev_type;
5309*fcf3ce44SJohn Forte fcio_t		fcio;
5310*fcf3ce44SJohn Forte int		verbose = 0;
5311*fcf3ce44SJohn Forte 
5312*fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(fca_path)) == 0) {
5313*fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5314*fcf3ce44SJohn Forte 	}
5315*fcf3ce44SJohn Forte 
5316*fcf3ce44SJohn Forte 	if (!(dev_type & FC_XPORT_MASK)) {
5317*fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
5318*fcf3ce44SJohn Forte 	}
5319*fcf3ce44SJohn Forte 
5320*fcf3ce44SJohn Forte 	/* open controller */
5321*fcf3ce44SJohn Forte 	if ((fd = g_object_open(fca_path, O_NDELAY | O_RDONLY)) == -1)
5322*fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
5323*fcf3ce44SJohn Forte 
5324*fcf3ce44SJohn Forte 	/*
5325*fcf3ce44SJohn Forte 	 * stores port_wwn to la_wwn_t raw_wwn field
5326*fcf3ce44SJohn Forte 	 * and construct fcio structures for FCIO_DEV_LOGIN.
5327*fcf3ce44SJohn Forte 	 */
5328*fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_STATE;
5329*fcf3ce44SJohn Forte 	fcio.fcio_ilen = sizeof (port_wwn);
5330*fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)&port_wwn;
5331*fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE;
5332*fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (uint32_t);
5333*fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)state;
5334*fcf3ce44SJohn Forte 	fcio.fcio_alen = 0;
5335*fcf3ce44SJohn Forte 	fcio.fcio_abuf = NULL;
5336*fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
5337*fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
5338*fcf3ce44SJohn Forte 		(void) close(fd);
5339*fcf3ce44SJohn Forte 		return (L_FCIO_GET_STATE_FAIL);
5340*fcf3ce44SJohn Forte 	} else {
5341*fcf3ce44SJohn Forte 		(void) close(fd);
5342*fcf3ce44SJohn Forte 		return (0);
5343*fcf3ce44SJohn Forte 	}
5344*fcf3ce44SJohn Forte }
5345*fcf3ce44SJohn Forte 
5346*fcf3ce44SJohn Forte /*
5347*fcf3ce44SJohn Forte  * Name: lilp_map_cmp
5348*fcf3ce44SJohn Forte  *
5349*fcf3ce44SJohn Forte  * Description: This function is used to compare the physical location
5350*fcf3ce44SJohn Forte  *              of to fc devices in a gfc_map_t.dev_addr arrary.
5351*fcf3ce44SJohn Forte  *
5352*fcf3ce44SJohn Forte  * Params:
5353*fcf3ce44SJohn Forte  *	First device to compare
5354*fcf3ce44SJohn Forte  *	Second device to compare
5355*fcf3ce44SJohn Forte  *
5356*fcf3ce44SJohn Forte  * Return:
5357*fcf3ce44SJohn Forte  *   0 = Devices at equal phyiscal location, How did this happen?
5358*fcf3ce44SJohn Forte  *  >0 = First device have a higher physical location than second
5359*fcf3ce44SJohn Forte  *  <0 = Second device have a higher physical location than first
5360*fcf3ce44SJohn Forte  */
5361*fcf3ce44SJohn Forte static int lilp_map_cmp(const void* dev1, const void* dev2) {
5362*fcf3ce44SJohn Forte 	int i_dev1 = ((fc_port_dev_t *)dev1)->dev_did.priv_lilp_posit;
5363*fcf3ce44SJohn Forte 	int i_dev2 = ((fc_port_dev_t *)dev2)->dev_did.priv_lilp_posit;
5364*fcf3ce44SJohn Forte 
5365*fcf3ce44SJohn Forte 	if (i_dev1 > i_dev2)
5366*fcf3ce44SJohn Forte 		return (1);
5367*fcf3ce44SJohn Forte 	if (i_dev1 < i_dev2)
5368*fcf3ce44SJohn Forte 		return (-1);
5369*fcf3ce44SJohn Forte 	return (0);
5370*fcf3ce44SJohn Forte }
5371*fcf3ce44SJohn Forte 
5372*fcf3ce44SJohn Forte /*
5373*fcf3ce44SJohn Forte  * Description:
5374*fcf3ce44SJohn Forte  *    Retrieves multiple paths to a device based on devid
5375*fcf3ce44SJohn Forte  *    Caller must use mplist_free to free mplist structure
5376*fcf3ce44SJohn Forte  *    This currently only supports ssd devices.
5377*fcf3ce44SJohn Forte  *    The st driver does not register a device id.
5378*fcf3ce44SJohn Forte  *
5379*fcf3ce44SJohn Forte  * Input Values:
5380*fcf3ce44SJohn Forte  *
5381*fcf3ce44SJohn Forte  *    devid: ptr to valid ddi_devid_t struct
5382*fcf3ce44SJohn Forte  *    root: root handle to device tree snapshot
5383*fcf3ce44SJohn Forte  *    drvr_name: driver name to start the node tree search
5384*fcf3ce44SJohn Forte  *
5385*fcf3ce44SJohn Forte  * Return Value:
5386*fcf3ce44SJohn Forte  *    0 on success
5387*fcf3ce44SJohn Forte  *    non-zero on failure
5388*fcf3ce44SJohn Forte  */
5389*fcf3ce44SJohn Forte 
5390*fcf3ce44SJohn Forte static int
5391*fcf3ce44SJohn Forte devid_get_all(ddi_devid_t devid, di_node_t root, char *drvr_name,
5392*fcf3ce44SJohn Forte 		struct mplist_struct **mplistp)
5393*fcf3ce44SJohn Forte {
5394*fcf3ce44SJohn Forte ddi_devid_t mydevid;
5395*fcf3ce44SJohn Forte di_node_t node;
5396*fcf3ce44SJohn Forte char *devfs_path = NULL;
5397*fcf3ce44SJohn Forte struct mplist_struct *mpl, *mpln;
5398*fcf3ce44SJohn Forte 
5399*fcf3ce44SJohn Forte 	if (devid == NULL || root == NULL || drvr_name == NULL ||
5400*fcf3ce44SJohn Forte 		mplistp == NULL ||
5401*fcf3ce44SJohn Forte 		(strncmp(drvr_name, SSD_DRVR_NAME, strlen(SSD_DRVR_NAME))
5402*fcf3ce44SJohn Forte 			!= 0)) {
5403*fcf3ce44SJohn Forte 		return (EINVAL);
5404*fcf3ce44SJohn Forte 	}
5405*fcf3ce44SJohn Forte 
5406*fcf3ce44SJohn Forte 	*mplistp = mpl = mpln = (struct mplist_struct *)NULL;
5407*fcf3ce44SJohn Forte 
5408*fcf3ce44SJohn Forte 	/* point to first node which matches portdrvr */
5409*fcf3ce44SJohn Forte 	node = di_drv_first_node(drvr_name, root);
5410*fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
5411*fcf3ce44SJohn Forte 		return (L_NO_DRIVER_NODES_FOUND);
5412*fcf3ce44SJohn Forte 	}
5413*fcf3ce44SJohn Forte 
5414*fcf3ce44SJohn Forte 	while (node != DI_NODE_NIL) {
5415*fcf3ce44SJohn Forte 		if ((mydevid = di_devid(node)) != NULL) {
5416*fcf3ce44SJohn Forte 			if (((devid_compare(mydevid, devid)) == 0)) {
5417*fcf3ce44SJohn Forte 			    /* Load multipath list */
5418*fcf3ce44SJohn Forte 			    if ((mpl = (struct mplist_struct *)
5419*fcf3ce44SJohn Forte 				calloc(1, sizeof (struct mplist_struct)))
5420*fcf3ce44SJohn Forte 					== NULL) {
5421*fcf3ce44SJohn Forte 				mplist_free(*mplistp);
5422*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
5423*fcf3ce44SJohn Forte 			    }
5424*fcf3ce44SJohn Forte 			    if ((devfs_path = my_devfs_path(node)) == NULL) {
5425*fcf3ce44SJohn Forte 				node = di_drv_next_node(node);
5426*fcf3ce44SJohn Forte 				S_FREE(mpl);
5427*fcf3ce44SJohn Forte 				continue;
5428*fcf3ce44SJohn Forte 			    }
5429*fcf3ce44SJohn Forte 			    mpl->devpath = (char *)calloc(1,
5430*fcf3ce44SJohn Forte 					strlen(devfs_path) +
5431*fcf3ce44SJohn Forte 					strlen(SSD_MINOR_NAME) + 1);
5432*fcf3ce44SJohn Forte 			    if (mpl->devpath == NULL) {
5433*fcf3ce44SJohn Forte 				S_FREE(mpl);
5434*fcf3ce44SJohn Forte 				mplist_free(*mplistp);
5435*fcf3ce44SJohn Forte 				my_devfs_path_free(devfs_path);
5436*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
5437*fcf3ce44SJohn Forte 			    }
5438*fcf3ce44SJohn Forte 			    sprintf(mpl->devpath, "%s%s", devfs_path,
5439*fcf3ce44SJohn Forte 					SSD_MINOR_NAME);
5440*fcf3ce44SJohn Forte 			    if (*mplistp == NULL) {
5441*fcf3ce44SJohn Forte 				*mplistp = mpln = mpl;
5442*fcf3ce44SJohn Forte 			    } else {
5443*fcf3ce44SJohn Forte 				mpln->next = mpl;
5444*fcf3ce44SJohn Forte 				mpln = mpl;
5445*fcf3ce44SJohn Forte 			    }
5446*fcf3ce44SJohn Forte 			    my_devfs_path_free(devfs_path);
5447*fcf3ce44SJohn Forte 			}
5448*fcf3ce44SJohn Forte 		}
5449*fcf3ce44SJohn Forte 	node = di_drv_next_node(node);
5450*fcf3ce44SJohn Forte 	}
5451*fcf3ce44SJohn Forte 	return (0);
5452*fcf3ce44SJohn Forte }
5453*fcf3ce44SJohn Forte 
5454*fcf3ce44SJohn Forte /*
5455*fcf3ce44SJohn Forte  * Frees a previously allocated mplist_struct
5456*fcf3ce44SJohn Forte  */
5457*fcf3ce44SJohn Forte static void
5458*fcf3ce44SJohn Forte mplist_free(struct mplist_struct *mplistp)
5459*fcf3ce44SJohn Forte {
5460*fcf3ce44SJohn Forte struct mplist_struct *mplistn;
5461*fcf3ce44SJohn Forte 
5462*fcf3ce44SJohn Forte 	while (mplistp != NULL) {
5463*fcf3ce44SJohn Forte 		mplistn = mplistp->next;
5464*fcf3ce44SJohn Forte 		if (mplistp->devpath != NULL) {
5465*fcf3ce44SJohn Forte 			free(mplistp->devpath);
5466*fcf3ce44SJohn Forte 			mplistp->devpath = NULL;
5467*fcf3ce44SJohn Forte 		}
5468*fcf3ce44SJohn Forte 		free(mplistp);
5469*fcf3ce44SJohn Forte 		mplistp = mplistn;
5470*fcf3ce44SJohn Forte 	}
5471*fcf3ce44SJohn Forte }
5472*fcf3ce44SJohn Forte 
5473*fcf3ce44SJohn Forte /*
5474*fcf3ce44SJohn Forte  * Description
5475*fcf3ce44SJohn Forte  *	Retrieves all device nodes based on drvr_name
5476*fcf3ce44SJohn Forte  *	Currently supports SSD_DRVR_NAME, ST_DRVR_NAME
5477*fcf3ce44SJohn Forte  *	There will be a device node in the libdevinfo
5478*fcf3ce44SJohn Forte  *	snapshot only if there is at least one node bound.
5479*fcf3ce44SJohn Forte  *
5480*fcf3ce44SJohn Forte  * Input values:
5481*fcf3ce44SJohn Forte  *	root		valid snapshot handle from di_init(3DEVINFO)
5482*fcf3ce44SJohn Forte  *	drvr_name	name of driver to start node search
5483*fcf3ce44SJohn Forte  *	wwn_list_ptr	ptr to ptr to WWN_list struct
5484*fcf3ce44SJohn Forte  *
5485*fcf3ce44SJohn Forte  *
5486*fcf3ce44SJohn Forte  */
5487*fcf3ce44SJohn Forte static int
5488*fcf3ce44SJohn Forte devices_get_all(di_node_t root, char *drvr_name, char *minor_name,
5489*fcf3ce44SJohn Forte 	struct wwn_list_struct **wwn_list_ptr)
5490*fcf3ce44SJohn Forte {
5491*fcf3ce44SJohn Forte di_node_t node;
5492*fcf3ce44SJohn Forte char *devfs_path;
5493*fcf3ce44SJohn Forte char devicepath[MAXPATHLEN];
5494*fcf3ce44SJohn Forte uchar_t *nwwn = NULL, *pwwn = NULL;
5495*fcf3ce44SJohn Forte uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
5496*fcf3ce44SJohn Forte WWN_list *wwn_list, *l1, *l2;
5497*fcf3ce44SJohn Forte int scsi_vhci = 0;
5498*fcf3ce44SJohn Forte int err, devtype;
5499*fcf3ce44SJohn Forte 
5500*fcf3ce44SJohn Forte 	if (root == DI_NODE_NIL || drvr_name == NULL ||
5501*fcf3ce44SJohn Forte 		wwn_list_ptr == NULL) {
5502*fcf3ce44SJohn Forte 		return (EINVAL);
5503*fcf3ce44SJohn Forte 	}
5504*fcf3ce44SJohn Forte 
5505*fcf3ce44SJohn Forte 	wwn_list = *wwn_list_ptr = NULL;
5506*fcf3ce44SJohn Forte 
5507*fcf3ce44SJohn Forte 	memset(port_wwn, 0, sizeof (port_wwn));
5508*fcf3ce44SJohn Forte 	memset(node_wwn, 0, sizeof (node_wwn));
5509*fcf3ce44SJohn Forte 
5510*fcf3ce44SJohn Forte 	if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
5511*fcf3ce44SJohn Forte 		devtype = DTYPE_DIRECT;
5512*fcf3ce44SJohn Forte 	} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
5513*fcf3ce44SJohn Forte 		devtype = DTYPE_SEQUENTIAL;
5514*fcf3ce44SJohn Forte 	} else {
5515*fcf3ce44SJohn Forte 		/*
5516*fcf3ce44SJohn Forte 		 * An unsupported driver name was passed in
5517*fcf3ce44SJohn Forte 		 */
5518*fcf3ce44SJohn Forte 		return (L_DRIVER_NOTSUPP);
5519*fcf3ce44SJohn Forte 	}
5520*fcf3ce44SJohn Forte 
5521*fcf3ce44SJohn Forte 	/* point to first node which matches portdrvr */
5522*fcf3ce44SJohn Forte 	node = di_drv_first_node(drvr_name, root);
5523*fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
5524*fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5525*fcf3ce44SJohn Forte 	}
5526*fcf3ce44SJohn Forte 
5527*fcf3ce44SJohn Forte 	while (node != DI_NODE_NIL) {
5528*fcf3ce44SJohn Forte 
5529*fcf3ce44SJohn Forte 	    if ((devfs_path = my_devfs_path(node)) != NULL) {
5530*fcf3ce44SJohn Forte 
5531*fcf3ce44SJohn Forte 		/*
5532*fcf3ce44SJohn Forte 		 * Check for offline state
5533*fcf3ce44SJohn Forte 		 */
5534*fcf3ce44SJohn Forte 		if ((di_state(node) & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) {
5535*fcf3ce44SJohn Forte 			my_devfs_path_free(devfs_path);
5536*fcf3ce44SJohn Forte 			node = di_drv_next_node(node);
5537*fcf3ce44SJohn Forte 			continue;
5538*fcf3ce44SJohn Forte 		}
5539*fcf3ce44SJohn Forte 
5540*fcf3ce44SJohn Forte 		/*
5541*fcf3ce44SJohn Forte 		 * Only support st, ssd nodes
5542*fcf3ce44SJohn Forte 		 */
5543*fcf3ce44SJohn Forte 		if (!strstr(devfs_path, SLSH_DRV_NAME_SSD) &&
5544*fcf3ce44SJohn Forte 			!strstr(devfs_path, SLSH_DRV_NAME_ST)) {
5545*fcf3ce44SJohn Forte 			my_devfs_path_free(devfs_path);
5546*fcf3ce44SJohn Forte 			node = di_drv_next_node(node);
5547*fcf3ce44SJohn Forte 			continue;
5548*fcf3ce44SJohn Forte 		}
5549*fcf3ce44SJohn Forte 
5550*fcf3ce44SJohn Forte 		devicepath[0] = '\0';
5551*fcf3ce44SJohn Forte 
5552*fcf3ce44SJohn Forte 		/*
5553*fcf3ce44SJohn Forte 		 * form device path
5554*fcf3ce44SJohn Forte 		 */
5555*fcf3ce44SJohn Forte 		sprintf(devicepath, "%s%s", devfs_path, minor_name);
5556*fcf3ce44SJohn Forte 
5557*fcf3ce44SJohn Forte 		if ((strstr(devicepath, SCSI_VHCI) == NULL)) {
5558*fcf3ce44SJohn Forte 			if ((err = get_wwn_data(node, &nwwn, &pwwn)) != 0) {
5559*fcf3ce44SJohn Forte 				my_devfs_path_free(devfs_path);
5560*fcf3ce44SJohn Forte 				return (err);
5561*fcf3ce44SJohn Forte 			} else {
5562*fcf3ce44SJohn Forte 				memcpy(node_wwn, nwwn, sizeof (node_wwn));
5563*fcf3ce44SJohn Forte 				memcpy(port_wwn, pwwn, sizeof (port_wwn));
5564*fcf3ce44SJohn Forte 			}
5565*fcf3ce44SJohn Forte 		} else {
5566*fcf3ce44SJohn Forte 			/*
5567*fcf3ce44SJohn Forte 			 * Clear values for SCSI VHCI devices.
5568*fcf3ce44SJohn Forte 			 * node wwn, port wwn are irrevelant at
5569*fcf3ce44SJohn Forte 			 * the SCSI VHCI level
5570*fcf3ce44SJohn Forte 			 */
5571*fcf3ce44SJohn Forte 			scsi_vhci++;
5572*fcf3ce44SJohn Forte 			memset(port_wwn, 0, sizeof (port_wwn));
5573*fcf3ce44SJohn Forte 			memset(node_wwn, 0, sizeof (node_wwn));
5574*fcf3ce44SJohn Forte 		}
5575*fcf3ce44SJohn Forte 
5576*fcf3ce44SJohn Forte 		/* Got wwns, load data in list */
5577*fcf3ce44SJohn Forte 		if ((l2 = (struct  wwn_list_struct *)
5578*fcf3ce44SJohn Forte 			calloc(1, sizeof (struct  wwn_list_struct))) == NULL) {
5579*fcf3ce44SJohn Forte 			my_devfs_path_free(devfs_path);
5580*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
5581*fcf3ce44SJohn Forte 		}
5582*fcf3ce44SJohn Forte 		if ((l2->physical_path = (char *)
5583*fcf3ce44SJohn Forte 			calloc(1, strlen(devicepath) +1)) == NULL) {
5584*fcf3ce44SJohn Forte 			my_devfs_path_free(devfs_path);
5585*fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
5586*fcf3ce44SJohn Forte 		}
5587*fcf3ce44SJohn Forte 
5588*fcf3ce44SJohn Forte 		memcpy(l2->w_node_wwn, node_wwn, WWN_SIZE);
5589*fcf3ce44SJohn Forte 
5590*fcf3ce44SJohn Forte 		if (scsi_vhci) {
5591*fcf3ce44SJohn Forte 		    strcpy(l2->node_wwn_s, MSGSTR(12000, "N/A"));
5592*fcf3ce44SJohn Forte 		} else {
5593*fcf3ce44SJohn Forte 		    copy_wwn_data_to_str(l2->node_wwn_s, node_wwn);
5594*fcf3ce44SJohn Forte 		    copy_wwn_data_to_str(l2->port_wwn_s, port_wwn);
5595*fcf3ce44SJohn Forte 		}
5596*fcf3ce44SJohn Forte 
5597*fcf3ce44SJohn Forte 		strcpy(l2->physical_path, devicepath);
5598*fcf3ce44SJohn Forte 
5599*fcf3ce44SJohn Forte 		l2->device_type = devtype;
5600*fcf3ce44SJohn Forte 		if (wwn_list == NULL) {
5601*fcf3ce44SJohn Forte 			l1 = wwn_list = l2;
5602*fcf3ce44SJohn Forte 		} else {
5603*fcf3ce44SJohn Forte 			l2->wwn_prev = l1;
5604*fcf3ce44SJohn Forte 			l1 = l1->wwn_next = l2;
5605*fcf3ce44SJohn Forte 		}
5606*fcf3ce44SJohn Forte 		my_devfs_path_free(devfs_path);
5607*fcf3ce44SJohn Forte 		scsi_vhci = 0;
5608*fcf3ce44SJohn Forte 	    }
5609*fcf3ce44SJohn Forte 	    node = di_drv_next_node(node);
5610*fcf3ce44SJohn Forte 	}
5611*fcf3ce44SJohn Forte 
5612*fcf3ce44SJohn Forte 	*wwn_list_ptr = wwn_list; /* pass back ptr to list */
5613*fcf3ce44SJohn Forte 
5614*fcf3ce44SJohn Forte 	if (*wwn_list_ptr == NULL) {
5615*fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5616*fcf3ce44SJohn Forte 	} else {
5617*fcf3ce44SJohn Forte 		/*
5618*fcf3ce44SJohn Forte 		 * Now load the /dev/ paths
5619*fcf3ce44SJohn Forte 		 */
5620*fcf3ce44SJohn Forte 		if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
5621*fcf3ce44SJohn Forte 			if ((err = get_dev_path(wwn_list_ptr, DEV_RDIR,
5622*fcf3ce44SJohn Forte 					DIR_MATCH_SSD)) != 0) {
5623*fcf3ce44SJohn Forte 				g_free_wwn_list(wwn_list_ptr);
5624*fcf3ce44SJohn Forte 				return (err);
5625*fcf3ce44SJohn Forte 			}
5626*fcf3ce44SJohn Forte 		} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
5627*fcf3ce44SJohn Forte 			if ((err = get_dev_path(wwn_list_ptr, DEV_TAPE_DIR,
5628*fcf3ce44SJohn Forte 					DIR_MATCH_ST)) != 0) {
5629*fcf3ce44SJohn Forte 				g_free_wwn_list(wwn_list_ptr);
5630*fcf3ce44SJohn Forte 				return (err);
5631*fcf3ce44SJohn Forte 			}
5632*fcf3ce44SJohn Forte 		}
5633*fcf3ce44SJohn Forte 		return (0);
5634*fcf3ce44SJohn Forte 	}
5635*fcf3ce44SJohn Forte }
5636*fcf3ce44SJohn Forte 
5637*fcf3ce44SJohn Forte 
5638*fcf3ce44SJohn Forte /*
5639*fcf3ce44SJohn Forte  * Access the properties for the node to get the node-wwn, port-wwn property
5640*fcf3ce44SJohn Forte  * On error, contents of nwwn, pwwn are unspecified.
5641*fcf3ce44SJohn Forte  * On successful return nwwn and pwwn are WWN_SIZE bytes.
5642*fcf3ce44SJohn Forte  */
5643*fcf3ce44SJohn Forte static int
5644*fcf3ce44SJohn Forte get_wwn_data(di_node_t node, uchar_t **nwwn, uchar_t **pwwn)
5645*fcf3ce44SJohn Forte {
5646*fcf3ce44SJohn Forte 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
5647*fcf3ce44SJohn Forte 			nwwn) != WWN_SIZE) {
5648*fcf3ce44SJohn Forte 	/* If we didn't get back the right count, return error */
5649*fcf3ce44SJohn Forte 		return (L_NO_WWN_PROP_FOUND);
5650*fcf3ce44SJohn Forte 	}
5651*fcf3ce44SJohn Forte 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP,
5652*fcf3ce44SJohn Forte 			pwwn) != WWN_SIZE) {
5653*fcf3ce44SJohn Forte 	/* If we didn't get back the right count, return error */
5654*fcf3ce44SJohn Forte 		return (L_NO_WWN_PROP_FOUND);
5655*fcf3ce44SJohn Forte 	}
5656*fcf3ce44SJohn Forte 	return (0);
5657*fcf3ce44SJohn Forte }
5658*fcf3ce44SJohn Forte 
5659*fcf3ce44SJohn Forte /*
5660*fcf3ce44SJohn Forte  * Description
5661*fcf3ce44SJohn Forte  *	retrieves the /dev logical path for a WWN_list of devices.
5662*fcf3ce44SJohn Forte  * Input values
5663*fcf3ce44SJohn Forte  *	wwn_list_ptr	ptr to list returned by devices_get_all
5664*fcf3ce44SJohn Forte  *	dir_name	/dev/ directory to search
5665*fcf3ce44SJohn Forte  *
5666*fcf3ce44SJohn Forte  */
5667*fcf3ce44SJohn Forte static int
5668*fcf3ce44SJohn Forte get_dev_path(struct wwn_list_struct **wwn_list_ptr, char *dir_name,
5669*fcf3ce44SJohn Forte 	char *pattern_match)
5670*fcf3ce44SJohn Forte {
5671*fcf3ce44SJohn Forte DIR		*dirp;
5672*fcf3ce44SJohn Forte struct dirent	*entp;
5673*fcf3ce44SJohn Forte char		namebuf[MAXPATHLEN];
5674*fcf3ce44SJohn Forte char		*result = NULL;
5675*fcf3ce44SJohn Forte WWN_list	*wwn_list, *wwn_list_save;
5676*fcf3ce44SJohn Forte char		*env;
5677*fcf3ce44SJohn Forte hrtime_t	start_time, end_time;
5678*fcf3ce44SJohn Forte 
5679*fcf3ce44SJohn Forte 	if (wwn_list_ptr == NULL || *wwn_list_ptr == NULL ||
5680*fcf3ce44SJohn Forte 		dir_name == NULL || pattern_match == NULL) {
5681*fcf3ce44SJohn Forte 		return (EINVAL);
5682*fcf3ce44SJohn Forte 	}
5683*fcf3ce44SJohn Forte 
5684*fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
5685*fcf3ce44SJohn Forte 		start_time = gethrtime();
5686*fcf3ce44SJohn Forte 	}
5687*fcf3ce44SJohn Forte 
5688*fcf3ce44SJohn Forte 	wwn_list = *wwn_list_ptr;
5689*fcf3ce44SJohn Forte 
5690*fcf3ce44SJohn Forte 	if ((dirp = opendir(dir_name)) == NULL) {
5691*fcf3ce44SJohn Forte 		P_DPRINTF("  get_dev_path: No devices found\n");
5692*fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5693*fcf3ce44SJohn Forte 	}
5694*fcf3ce44SJohn Forte 
5695*fcf3ce44SJohn Forte 	while ((entp = readdir(dirp)) != NULL) {
5696*fcf3ce44SJohn Forte 		/*
5697*fcf3ce44SJohn Forte 		 * Ignore current directory and parent directory
5698*fcf3ce44SJohn Forte 		 * entries.
5699*fcf3ce44SJohn Forte 		 */
5700*fcf3ce44SJohn Forte 		if ((strcmp(entp->d_name, ".") == 0) ||
5701*fcf3ce44SJohn Forte 		    (strcmp(entp->d_name, "..") == 0) ||
5702*fcf3ce44SJohn Forte 		    (fnmatch(pattern_match, entp->d_name, 0) != 0))
5703*fcf3ce44SJohn Forte 			continue;
5704*fcf3ce44SJohn Forte 
5705*fcf3ce44SJohn Forte 		memset(namebuf, 0, sizeof (namebuf));
5706*fcf3ce44SJohn Forte 		sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
5707*fcf3ce44SJohn Forte 
5708*fcf3ce44SJohn Forte 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
5709*fcf3ce44SJohn Forte 			ER_DPRINTF("  Warning: Get physical name from"
5710*fcf3ce44SJohn Forte 				" link failed. Link=%s\n", namebuf);
5711*fcf3ce44SJohn Forte 			continue;
5712*fcf3ce44SJohn Forte 		}
5713*fcf3ce44SJohn Forte 		for (wwn_list = *wwn_list_ptr; wwn_list != NULL;
5714*fcf3ce44SJohn Forte 		    wwn_list = wwn_list->wwn_next) {
5715*fcf3ce44SJohn Forte 		    if (strcmp(wwn_list->physical_path, result) == 0) {
5716*fcf3ce44SJohn Forte 			/*
5717*fcf3ce44SJohn Forte 			 * Add information to the list.
5718*fcf3ce44SJohn Forte 			 */
5719*fcf3ce44SJohn Forte 			if ((wwn_list->logical_path = (char *)
5720*fcf3ce44SJohn Forte 				calloc(1, strlen(namebuf) + 1)) == NULL) {
5721*fcf3ce44SJohn Forte 				free(result);
5722*fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
5723*fcf3ce44SJohn Forte 			}
5724*fcf3ce44SJohn Forte 			strcpy(wwn_list->logical_path, namebuf);
5725*fcf3ce44SJohn Forte 			break;
5726*fcf3ce44SJohn Forte 		    }
5727*fcf3ce44SJohn Forte 		}
5728*fcf3ce44SJohn Forte 		free(result);
5729*fcf3ce44SJohn Forte 	}
5730*fcf3ce44SJohn Forte 	closedir(dirp);
5731*fcf3ce44SJohn Forte 
5732*fcf3ce44SJohn Forte 	/*
5733*fcf3ce44SJohn Forte 	 * Did we load all of the paths?
5734*fcf3ce44SJohn Forte 	 * Note: if there is a missing entry in /dev then
5735*fcf3ce44SJohn Forte 	 * the user probably did a cleanup of /dev.
5736*fcf3ce44SJohn Forte 	 * Whatever the case, remove the entry as it
5737*fcf3ce44SJohn Forte 	 * is invalid.
5738*fcf3ce44SJohn Forte 	 */
5739*fcf3ce44SJohn Forte 	wwn_list = *wwn_list_ptr;
5740*fcf3ce44SJohn Forte 	while (wwn_list != NULL) {
5741*fcf3ce44SJohn Forte 		if (wwn_list->logical_path == NULL) {
5742*fcf3ce44SJohn Forte 			free(wwn_list->physical_path);
5743*fcf3ce44SJohn Forte 			wwn_list_save = wwn_list;
5744*fcf3ce44SJohn Forte 			if (wwn_list->wwn_prev != NULL) {
5745*fcf3ce44SJohn Forte 				wwn_list->wwn_prev->wwn_next =
5746*fcf3ce44SJohn Forte 					wwn_list->wwn_next;
5747*fcf3ce44SJohn Forte 			} else {
5748*fcf3ce44SJohn Forte 				/*
5749*fcf3ce44SJohn Forte 				 * No previous entries
5750*fcf3ce44SJohn Forte 				 */
5751*fcf3ce44SJohn Forte 				*wwn_list_ptr = wwn_list->wwn_next;
5752*fcf3ce44SJohn Forte 			}
5753*fcf3ce44SJohn Forte 			if (wwn_list->wwn_next != NULL) {
5754*fcf3ce44SJohn Forte 				wwn_list->wwn_next->wwn_prev =
5755*fcf3ce44SJohn Forte 					wwn_list->wwn_prev;
5756*fcf3ce44SJohn Forte 			}
5757*fcf3ce44SJohn Forte 			wwn_list = wwn_list->wwn_next;
5758*fcf3ce44SJohn Forte 			free(wwn_list_save);
5759*fcf3ce44SJohn Forte 		} else {
5760*fcf3ce44SJohn Forte 			wwn_list = wwn_list->wwn_next;
5761*fcf3ce44SJohn Forte 		}
5762*fcf3ce44SJohn Forte 	}
5763*fcf3ce44SJohn Forte 
5764*fcf3ce44SJohn Forte 	if (env != NULL) {
5765*fcf3ce44SJohn Forte 		end_time = gethrtime();
5766*fcf3ce44SJohn Forte 		fprintf(stdout,
5767*fcf3ce44SJohn Forte 		"      get_dev_path %s:  "
5768*fcf3ce44SJohn Forte 		"\t\tTime = %lld millisec\n",
5769*fcf3ce44SJohn Forte 		dir_name, (end_time - start_time)/1000000);
5770*fcf3ce44SJohn Forte 	}
5771*fcf3ce44SJohn Forte 
5772*fcf3ce44SJohn Forte 	if (*wwn_list_ptr == NULL) {
5773*fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5774*fcf3ce44SJohn Forte 	} else {
5775*fcf3ce44SJohn Forte 		return (0);
5776*fcf3ce44SJohn Forte 	}
5777*fcf3ce44SJohn Forte }
5778*fcf3ce44SJohn Forte 
5779*fcf3ce44SJohn Forte /*
5780*fcf3ce44SJohn Forte  * This functions calls di_devfs_path and gets the path associated with a
5781*fcf3ce44SJohn Forte  * given devinfo node. If the path returned does not have a '@' in it, it
5782*fcf3ce44SJohn Forte  * checks if the driver is detached and creates a path after looking at the
5783*fcf3ce44SJohn Forte  * driver properties.
5784*fcf3ce44SJohn Forte  *
5785*fcf3ce44SJohn Forte  * di_devfs_path_free is called internally.
5786*fcf3ce44SJohn Forte  *
5787*fcf3ce44SJohn Forte  * The argument 'path' points to the final value upon return.
5788*fcf3ce44SJohn Forte  * Caller must use my_devfs_path_free on returned char *
5789*fcf3ce44SJohn Forte  * Note: Only support FC/SCSI_VHCI devices,
5790*fcf3ce44SJohn Forte  *       for FC check for node-wwn prop
5791*fcf3ce44SJohn Forte  *
5792*fcf3ce44SJohn Forte  */
5793*fcf3ce44SJohn Forte static char *
5794*fcf3ce44SJohn Forte my_devfs_path(di_node_t node)
5795*fcf3ce44SJohn Forte {
5796*fcf3ce44SJohn Forte 	uchar_t	*pwwn = NULL;
5797*fcf3ce44SJohn Forte 	char	pwwns[WWN_SIZE*2+1];
5798*fcf3ce44SJohn Forte 	char	*mypath;
5799*fcf3ce44SJohn Forte 	int	scsi_vhci = 0;
5800*fcf3ce44SJohn Forte 	char	*tptr = NULL, *lun_guid = NULL;
5801*fcf3ce44SJohn Forte 	int	*lunnump = NULL;
5802*fcf3ce44SJohn Forte 
5803*fcf3ce44SJohn Forte 	/* sanity check */
5804*fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
5805*fcf3ce44SJohn Forte 		return (NULL);
5806*fcf3ce44SJohn Forte 	}
5807*fcf3ce44SJohn Forte 
5808*fcf3ce44SJohn Forte 	/* Now go get the path for this node */
5809*fcf3ce44SJohn Forte 	if ((tptr = di_devfs_path(node)) == NULL) {
5810*fcf3ce44SJohn Forte 		return (NULL);
5811*fcf3ce44SJohn Forte 	}
5812*fcf3ce44SJohn Forte 
5813*fcf3ce44SJohn Forte 	if ((mypath = (char *)calloc(1, MAXPATHLEN + 1)) == NULL) {
5814*fcf3ce44SJohn Forte 		di_devfs_path_free(tptr);
5815*fcf3ce44SJohn Forte 		return (NULL);
5816*fcf3ce44SJohn Forte 	}
5817*fcf3ce44SJohn Forte 
5818*fcf3ce44SJohn Forte 	/* Prepend "/devices" to libdevinfo-returned paths */
5819*fcf3ce44SJohn Forte 	sprintf(mypath, "%s%s", DEVICES_DIR, tptr);
5820*fcf3ce44SJohn Forte 
5821*fcf3ce44SJohn Forte 	di_devfs_path_free(tptr);
5822*fcf3ce44SJohn Forte 
5823*fcf3ce44SJohn Forte 
5824*fcf3ce44SJohn Forte 	/*
5825*fcf3ce44SJohn Forte 	 * Is this a FC device?
5826*fcf3ce44SJohn Forte 	 * Check the pwwn property
5827*fcf3ce44SJohn Forte 	 */
5828*fcf3ce44SJohn Forte 	if (strstr(mypath, SCSI_VHCI) == NULL) {
5829*fcf3ce44SJohn Forte 		if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP,
5830*fcf3ce44SJohn Forte 				&pwwn) < 0) {
5831*fcf3ce44SJohn Forte 			/* Not a FC device. Free path and return */
5832*fcf3ce44SJohn Forte 			free(mypath);
5833*fcf3ce44SJohn Forte 			return (NULL);
5834*fcf3ce44SJohn Forte 		}
5835*fcf3ce44SJohn Forte 	} else {
5836*fcf3ce44SJohn Forte 		scsi_vhci++;
5837*fcf3ce44SJohn Forte 	}
5838*fcf3ce44SJohn Forte 
5839*fcf3ce44SJohn Forte 	if ((tptr = strrchr(mypath, '/')) == NULL) {
5840*fcf3ce44SJohn Forte 		free(mypath);
5841*fcf3ce44SJohn Forte 		return (NULL);
5842*fcf3ce44SJohn Forte 	}
5843*fcf3ce44SJohn Forte 
5844*fcf3ce44SJohn Forte 	if (strchr(tptr, '@') != NULL) {
5845*fcf3ce44SJohn Forte 		return (mypath);
5846*fcf3ce44SJohn Forte 	}
5847*fcf3ce44SJohn Forte 
5848*fcf3ce44SJohn Forte 	/*
5849*fcf3ce44SJohn Forte 	 * No '@' in path. This can happen when driver is detached.
5850*fcf3ce44SJohn Forte 	 * We'll check if the state is detached and if it is, we'll construct
5851*fcf3ce44SJohn Forte 	 * the path by looking at the properties.
5852*fcf3ce44SJohn Forte 	 */
5853*fcf3ce44SJohn Forte 
5854*fcf3ce44SJohn Forte 	if ((di_state(node) & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
5855*fcf3ce44SJohn Forte 		/*
5856*fcf3ce44SJohn Forte 		 * Driver is not detached and no '@' in path.
5857*fcf3ce44SJohn Forte 		 * Can't handle it.
5858*fcf3ce44SJohn Forte 		 */
5859*fcf3ce44SJohn Forte 		free(mypath);
5860*fcf3ce44SJohn Forte 		return (NULL);
5861*fcf3ce44SJohn Forte 	}
5862*fcf3ce44SJohn Forte 
5863*fcf3ce44SJohn Forte 	if (!scsi_vhci) {
5864*fcf3ce44SJohn Forte 		copy_wwn_data_to_str(pwwns, pwwn);
5865*fcf3ce44SJohn Forte 		di_prop_lookup_ints(DDI_DEV_T_ANY, node, LUN_PROP, &lunnump);
5866*fcf3ce44SJohn Forte 		sprintf(&mypath[strlen(mypath)], "@w%s,%x", pwwn, *lunnump);
5867*fcf3ce44SJohn Forte 	} else {
5868*fcf3ce44SJohn Forte 		di_prop_lookup_strings(DDI_DEV_T_ANY, node,
5869*fcf3ce44SJohn Forte 			LUN_GUID_PROP, &lun_guid);
5870*fcf3ce44SJohn Forte 		sprintf(&mypath[strlen(mypath)], "@g%s", lun_guid);
5871*fcf3ce44SJohn Forte 	}
5872*fcf3ce44SJohn Forte 	return (mypath);
5873*fcf3ce44SJohn Forte }
5874*fcf3ce44SJohn Forte 
5875*fcf3ce44SJohn Forte static void
5876*fcf3ce44SJohn Forte my_devfs_path_free(char *path)
5877*fcf3ce44SJohn Forte {
5878*fcf3ce44SJohn Forte 	if (path != NULL) {
5879*fcf3ce44SJohn Forte 		free(path);
5880*fcf3ce44SJohn Forte 	}
5881*fcf3ce44SJohn Forte }
5882*fcf3ce44SJohn Forte 
5883*fcf3ce44SJohn Forte /*
5884*fcf3ce44SJohn Forte  * from_ptr: ptr to uchar_t array of size WWN_SIZE
5885*fcf3ce44SJohn Forte  * to_ptr: char ptr to string of size WWN_SIZE*2+1
5886*fcf3ce44SJohn Forte  */
5887*fcf3ce44SJohn Forte static void
5888*fcf3ce44SJohn Forte copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
5889*fcf3ce44SJohn Forte {
5890*fcf3ce44SJohn Forte 	if ((to_ptr == NULL) || (from_ptr == NULL))
5891*fcf3ce44SJohn Forte 		return;
5892*fcf3ce44SJohn Forte 
5893*fcf3ce44SJohn Forte 	sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
5894*fcf3ce44SJohn Forte 	from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
5895*fcf3ce44SJohn Forte 	from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
5896*fcf3ce44SJohn Forte }
5897*fcf3ce44SJohn Forte 
5898*fcf3ce44SJohn Forte /*
5899*fcf3ce44SJohn Forte  * Open the requested directory and get one valid open.
5900*fcf3ce44SJohn Forte  * If a device is busy, return.
5901*fcf3ce44SJohn Forte  * Only need to open one device since
5902*fcf3ce44SJohn Forte  * that implies there will be a node returned from
5903*fcf3ce44SJohn Forte  * di_drv_first_node()
5904*fcf3ce44SJohn Forte  * dir_name: logical device name directory
5905*fcf3ce44SJohn Forte  *	(DEV_TAPE_DIR, DEV_RDIR)
5906*fcf3ce44SJohn Forte  * pattern_match: used by fnmatch on directory entry
5907*fcf3ce44SJohn Forte  *	(DIR_MATCH_SSD, DIR_MATCH_ST)
5908*fcf3ce44SJohn Forte  * drvr_path: path type to verify ("/ssd@", "/st@")
5909*fcf3ce44SJohn Forte  *	(SLSH_DRV_NAME_ST, SLSH_DRV_NAME_SSD)
5910*fcf3ce44SJohn Forte  *
5911*fcf3ce44SJohn Forte  * Returns: None
5912*fcf3ce44SJohn Forte  */
5913*fcf3ce44SJohn Forte static void
5914*fcf3ce44SJohn Forte init_drv(char *dir_name, char *pattern_match, char *drvr_path)
5915*fcf3ce44SJohn Forte {
5916*fcf3ce44SJohn Forte DIR		*dirp;
5917*fcf3ce44SJohn Forte struct dirent	*entp;
5918*fcf3ce44SJohn Forte char		namebuf[MAXPATHLEN];
5919*fcf3ce44SJohn Forte char		*result = NULL;
5920*fcf3ce44SJohn Forte int		fd;
5921*fcf3ce44SJohn Forte 
5922*fcf3ce44SJohn Forte 	if ((dirp = opendir(dir_name)) == NULL) {
5923*fcf3ce44SJohn Forte 		return;
5924*fcf3ce44SJohn Forte 	}
5925*fcf3ce44SJohn Forte 
5926*fcf3ce44SJohn Forte 	while ((entp = readdir(dirp)) != NULL) {
5927*fcf3ce44SJohn Forte 		/*
5928*fcf3ce44SJohn Forte 		 * Ignore current directory and parent directory
5929*fcf3ce44SJohn Forte 		 * entries.
5930*fcf3ce44SJohn Forte 		 */
5931*fcf3ce44SJohn Forte 		if ((strcmp(entp->d_name, ".") == 0) ||
5932*fcf3ce44SJohn Forte 		    (strcmp(entp->d_name, "..") == 0) ||
5933*fcf3ce44SJohn Forte 		    (fnmatch(pattern_match, entp->d_name, 0) != 0)) {
5934*fcf3ce44SJohn Forte 			continue;
5935*fcf3ce44SJohn Forte 		}
5936*fcf3ce44SJohn Forte 
5937*fcf3ce44SJohn Forte 		memset(namebuf, 0, sizeof (namebuf));
5938*fcf3ce44SJohn Forte 		sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
5939*fcf3ce44SJohn Forte 
5940*fcf3ce44SJohn Forte 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
5941*fcf3ce44SJohn Forte 			ER_DPRINTF("  Warning: Get physical name from"
5942*fcf3ce44SJohn Forte 				" link failed. Link=%s\n", namebuf);
5943*fcf3ce44SJohn Forte 			continue;
5944*fcf3ce44SJohn Forte 		}
5945*fcf3ce44SJohn Forte 
5946*fcf3ce44SJohn Forte 		if (strstr(result, drvr_path) == NULL) {
5947*fcf3ce44SJohn Forte 			free(result);
5948*fcf3ce44SJohn Forte 			result = NULL;
5949*fcf3ce44SJohn Forte 			continue;
5950*fcf3ce44SJohn Forte 		}
5951*fcf3ce44SJohn Forte 
5952*fcf3ce44SJohn Forte 		if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) != -1) {
5953*fcf3ce44SJohn Forte 			close(fd);
5954*fcf3ce44SJohn Forte 			break;
5955*fcf3ce44SJohn Forte 		} else if (errno != EBUSY) {
5956*fcf3ce44SJohn Forte 			free(result);
5957*fcf3ce44SJohn Forte 			result = NULL;
5958*fcf3ce44SJohn Forte 			continue;
5959*fcf3ce44SJohn Forte 		} else {
5960*fcf3ce44SJohn Forte 			break;
5961*fcf3ce44SJohn Forte 		}
5962*fcf3ce44SJohn Forte 	}
5963*fcf3ce44SJohn Forte 	free(result);
5964*fcf3ce44SJohn Forte 	closedir(dirp);
5965*fcf3ce44SJohn Forte }
5966