1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22063d642aSBill Gumbrell  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  */
25fcf3ce44SJohn Forte 
26fcf3ce44SJohn Forte 
27fcf3ce44SJohn Forte /*LINTLIBRARY*/
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte /*
30fcf3ce44SJohn Forte  * I18N message number ranges
31fcf3ce44SJohn Forte  *  This file: 12000 - 12499
32fcf3ce44SJohn Forte  *  Shared common messages: 1 - 1999
33fcf3ce44SJohn Forte  */
34fcf3ce44SJohn Forte 
35fcf3ce44SJohn Forte /*
36fcf3ce44SJohn Forte  *	This module is part of the Fibre Channel Interface library.
37fcf3ce44SJohn Forte  */
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte /* #define		_POSIX_SOURCE 1 */
40fcf3ce44SJohn Forte 
41fcf3ce44SJohn Forte 
42fcf3ce44SJohn Forte /*	Includes	*/
43fcf3ce44SJohn Forte #include	<stdlib.h>
44fcf3ce44SJohn Forte #include	<stdio.h>
45fcf3ce44SJohn Forte #include	<sys/file.h>
46fcf3ce44SJohn Forte #include	<sys/types.h>
47fcf3ce44SJohn Forte #include	<sys/stat.h>
48fcf3ce44SJohn Forte #include	<sys/mkdev.h>
49fcf3ce44SJohn Forte #include	<sys/param.h>
50fcf3ce44SJohn Forte #include	<fcntl.h>
51fcf3ce44SJohn Forte #include	<unistd.h>
52fcf3ce44SJohn Forte #include	<string.h>
53fcf3ce44SJohn Forte #include	<sys/scsi/scsi.h>
54fcf3ce44SJohn Forte #include	<dirent.h>		/* for DIR */
55fcf3ce44SJohn Forte #include	<sys/vtoc.h>
56fcf3ce44SJohn Forte #include	<nl_types.h>
57fcf3ce44SJohn Forte #include	<strings.h>
58fcf3ce44SJohn Forte #include	<errno.h>
59fcf3ce44SJohn Forte #include	<sys/ddi.h>		/* for max */
60fcf3ce44SJohn Forte #include	<fnmatch.h>
61fcf3ce44SJohn Forte #include	<l_common.h>
62fcf3ce44SJohn Forte #include	<stgcom.h>
63fcf3ce44SJohn Forte #include	<l_error.h>
64fcf3ce44SJohn Forte #include	<g_state.h>
65fcf3ce44SJohn Forte #include	<g_scsi.h>
66fcf3ce44SJohn Forte #include	<sys/fibre-channel/ulp/fcp_util.h>
67fcf3ce44SJohn Forte #include	<sys/fibre-channel/impl/fc_error.h>
68fcf3ce44SJohn Forte #include	<sys/fibre-channel/impl/fcph.h>
69fcf3ce44SJohn Forte #include	<sys/socalio.h>
70fcf3ce44SJohn Forte #include	<libdevinfo.h>
71fcf3ce44SJohn Forte #include	<ctype.h>
72fcf3ce44SJohn Forte #include	<devid.h>
73fcf3ce44SJohn Forte 
74fcf3ce44SJohn Forte /* Some forward declarations of static functions */
75fcf3ce44SJohn Forte /*
76fcf3ce44SJohn Forte  * becomes extern interface for Tapestry.
77fcf3ce44SJohn Forte  * static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *);
78fcf3ce44SJohn Forte  * static int g_get_dev_list(char *, fc_port_dev_t **, int *, int);
79fcf3ce44SJohn Forte  */
80fcf3ce44SJohn Forte static int	g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
81fcf3ce44SJohn Forte static int	g_set_port_state(char *, int);
82fcf3ce44SJohn Forte static int	g_dev_log_in_out(char *, la_wwn_t, uint16_t);
83fcf3ce44SJohn Forte static int	g_get_dev_port_state(char *, la_wwn_t, uint32_t *);
84fcf3ce44SJohn Forte static void	g_free_rls(AL_rls *);
85fcf3ce44SJohn Forte static int	g_scsi_inquiry_cmd80(int, uchar_t *, int);
86fcf3ce44SJohn Forte static int	get_fca_inq_dtype(char *, la_wwn_t, uchar_t *);
87fcf3ce44SJohn Forte static int	g_find_supported_inq_page(int, int);
88fcf3ce44SJohn Forte static int	wwn_list_name_compare(const void *, const void *);
89fcf3ce44SJohn Forte static int	devid_get_all(ddi_devid_t, di_node_t, char *,
90fcf3ce44SJohn Forte 			struct mplist_struct **);
91fcf3ce44SJohn Forte static int	get_multipath(char *, struct dlist **,
92fcf3ce44SJohn Forte 			struct wwn_list_struct *);
93fcf3ce44SJohn Forte static int	get_multipath_disk(char *, struct dlist **,
94fcf3ce44SJohn Forte 			struct wwn_list_struct *);
95fcf3ce44SJohn Forte static void	mplist_free(struct mplist_struct *);
96fcf3ce44SJohn Forte static int	get_wwn_data(di_node_t, uchar_t **, uchar_t **);
97fcf3ce44SJohn Forte static int	get_dev_path(struct wwn_list_struct **, char *, char *);
98fcf3ce44SJohn Forte static int	insert_missing_pwwn(char *, struct wwn_list_struct **);
99fcf3ce44SJohn Forte static int	get_scsi_vhci_port_wwn(char *, uchar_t *);
100fcf3ce44SJohn Forte static int	search_wwn_entry(struct wwn_list_found_struct *, uchar_t *,
101fcf3ce44SJohn Forte 		uchar_t *);
102fcf3ce44SJohn Forte static int	add_wwn_entry(struct wwn_list_found_struct **, uchar_t *,
103fcf3ce44SJohn Forte 		uchar_t *);
104fcf3ce44SJohn Forte static int	string_to_wwn(uchar_t *, uchar_t *);
105fcf3ce44SJohn Forte static int	get_wwns(char *, uchar_t *, uchar_t *, int *,
106fcf3ce44SJohn Forte 		struct wwn_list_found_struct **);
107fcf3ce44SJohn Forte 
108fcf3ce44SJohn Forte /* type for g_dev_map_init related routines */
109fcf3ce44SJohn Forte 
110fcf3ce44SJohn Forte #define	S_FREE(x)	(((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
111fcf3ce44SJohn Forte 
112fcf3ce44SJohn Forte typedef struct impl_map_dev_prop {
113fcf3ce44SJohn Forte 	char	prop_name[MAXNAMELEN];
114fcf3ce44SJohn Forte 	int	prop_type;
115fcf3ce44SJohn Forte 	int	prop_size;
116*926d645fSToomas Soome 	void	*prop_data;
117*926d645fSToomas Soome 	int	prop_error;
118fcf3ce44SJohn Forte 	struct impl_map_dev_prop	*next;
119fcf3ce44SJohn Forte } impl_map_dev_prop_t;
120fcf3ce44SJohn Forte 
121fcf3ce44SJohn Forte typedef struct impl_map_dev {
122fcf3ce44SJohn Forte 	int			flag;
123fcf3ce44SJohn Forte 	uint_t			topo;
124fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*prop_list;
125fcf3ce44SJohn Forte 	struct impl_map_dev	*parent;
126fcf3ce44SJohn Forte 	struct impl_map_dev	*child;
127*926d645fSToomas Soome 	struct impl_map_dev	*next;
128fcf3ce44SJohn Forte } impl_map_dev_t;
129fcf3ce44SJohn Forte 
130*926d645fSToomas Soome /*	Defines		*/
131fcf3ce44SJohn Forte #define	VERBPRINT	if (verbose) (void) printf
132fcf3ce44SJohn Forte 
133fcf3ce44SJohn Forte #define	DIR_MATCH_ST		"*[0-9+]n"
134fcf3ce44SJohn Forte #define	DIR_MATCH_SSD		"*s2"
135fcf3ce44SJohn Forte 
136fcf3ce44SJohn Forte #define	PROP_NOEXIST		0
137fcf3ce44SJohn Forte #define	PROP_EXIST		1
138fcf3ce44SJohn Forte 
139fcf3ce44SJohn Forte /*	Prototypes	*/
140fcf3ce44SJohn Forte static int create_map(char *, gfc_map_t *, int, int);
141fcf3ce44SJohn Forte static char ctoi(char);
142fcf3ce44SJohn Forte static int	lilp_map_cmp(const void*, const void*);
143fcf3ce44SJohn Forte static int	devices_get_all(di_node_t, char *, char *,
144fcf3ce44SJohn Forte 			struct wwn_list_struct **);
145fcf3ce44SJohn Forte static char	*my_devfs_path(di_node_t);
146fcf3ce44SJohn Forte static void	my_devfs_path_free(char *path);
147fcf3ce44SJohn Forte static void	copy_wwn_data_to_str(char *, const uchar_t *);
148fcf3ce44SJohn Forte static void	init_drv(char *, char *, char *);
149fcf3ce44SJohn Forte 
150fcf3ce44SJohn Forte /* static for g_dev_map_init related routines */
151fcf3ce44SJohn Forte 
152fcf3ce44SJohn Forte static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t,
153fcf3ce44SJohn Forte 	uchar_t *, uchar_t *, int, int);
154fcf3ce44SJohn Forte static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int);
155fcf3ce44SJohn Forte static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **);
156fcf3ce44SJohn Forte static void free_prop_list(impl_map_dev_prop_t **);
157fcf3ce44SJohn Forte static void free_child_list(impl_map_dev_t **);
158fcf3ce44SJohn Forte static u_longlong_t wwnConversion(uchar_t *wwn);
159fcf3ce44SJohn Forte 
160fcf3ce44SJohn Forte uchar_t g_switch_to_alpa[] = {
161fcf3ce44SJohn Forte 	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
162fcf3ce44SJohn Forte 	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
163fcf3ce44SJohn Forte 	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
164fcf3ce44SJohn Forte 	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
165fcf3ce44SJohn Forte 	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
166fcf3ce44SJohn Forte 	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
167fcf3ce44SJohn Forte 	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
168fcf3ce44SJohn Forte 	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
169fcf3ce44SJohn Forte 	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
170fcf3ce44SJohn Forte 	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
171fcf3ce44SJohn Forte 	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
172fcf3ce44SJohn Forte 	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
173fcf3ce44SJohn Forte 	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
174fcf3ce44SJohn Forte };
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte uchar_t g_sf_alpa_to_switch[] = {
177fcf3ce44SJohn Forte 	0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
178fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
179fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
180fcf3ce44SJohn Forte 	0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
181fcf3ce44SJohn Forte 	0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
182fcf3ce44SJohn Forte 	0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
183fcf3ce44SJohn Forte 	0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
184fcf3ce44SJohn Forte 	0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
185fcf3ce44SJohn Forte 	0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
186fcf3ce44SJohn Forte 	0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
187fcf3ce44SJohn Forte 	0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
188fcf3ce44SJohn Forte 	0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
189fcf3ce44SJohn Forte 	0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
190fcf3ce44SJohn Forte 	0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
191fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
192fcf3ce44SJohn Forte 	0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
193fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
194fcf3ce44SJohn Forte 	0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
195fcf3ce44SJohn Forte 	0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
196fcf3ce44SJohn Forte 	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
197fcf3ce44SJohn Forte 	0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
198fcf3ce44SJohn Forte 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
199fcf3ce44SJohn Forte 	0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
200fcf3ce44SJohn Forte 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
201fcf3ce44SJohn Forte };
202fcf3ce44SJohn Forte 
203fcf3ce44SJohn Forte 
204fcf3ce44SJohn Forte 
205fcf3ce44SJohn Forte /*
206fcf3ce44SJohn Forte  * Check if device is in the map.
207fcf3ce44SJohn Forte  *
208fcf3ce44SJohn Forte  * PARAMS:
209fcf3ce44SJohn Forte  *	map - loop map returned from fc port
210fcf3ce44SJohn Forte  *	tid - device ID for private map or 24-bit alpa for fabric map
211fcf3ce44SJohn Forte  *
212fcf3ce44SJohn Forte  * RETURNS:
213fcf3ce44SJohn Forte  *	 1 if device present in the map.
214fcf3ce44SJohn Forte  *	 0 otherwise.
215fcf3ce44SJohn Forte  *
216fcf3ce44SJohn Forte  */
217fcf3ce44SJohn Forte int
g_device_in_map(gfc_map_t * map,int tid)218fcf3ce44SJohn Forte g_device_in_map(gfc_map_t *map, int tid)
219fcf3ce44SJohn Forte {
220fcf3ce44SJohn Forte 	int i, j;
221fcf3ce44SJohn Forte 	gfc_port_dev_info_t	*dev_ptr;
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte 	dev_ptr = map->dev_addr;
224fcf3ce44SJohn Forte 	if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) ||
225063d642aSBill Gumbrell 	    (map->hba_addr.port_topology == FC_TOP_FABRIC)) {
226fcf3ce44SJohn Forte 		for (i = 0; i < map->count; i++, dev_ptr++) {
227fcf3ce44SJohn Forte 			if (dev_ptr->
228063d642aSBill Gumbrell 			    gfc_port_dev.pub_port.dev_did.port_id == tid) {
229fcf3ce44SJohn Forte 				/* Does not count if WWN == 0 */
230fcf3ce44SJohn Forte 				for (j = 0; j < FC_WWN_SIZE; j++)
231fcf3ce44SJohn Forte 					if (dev_ptr->gfc_port_dev.pub_port.
232063d642aSBill Gumbrell 					    dev_pwwn.raw_wwn[j] != 0)
233fcf3ce44SJohn Forte 						return (1);
234fcf3ce44SJohn Forte 			}
235fcf3ce44SJohn Forte 		}
236fcf3ce44SJohn Forte 	} else {
237fcf3ce44SJohn Forte 		for (i = 0; i < map->count; i++, dev_ptr++) {
238fcf3ce44SJohn Forte 			if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa ==
239063d642aSBill Gumbrell 			    (int)g_switch_to_alpa[tid]) {
240fcf3ce44SJohn Forte 				/* Does not count if WWN == 0 */
241fcf3ce44SJohn Forte 				for (j = 0; j < WWN_SIZE; j++)
242fcf3ce44SJohn Forte 					if (dev_ptr->gfc_port_dev.priv_port.
243063d642aSBill Gumbrell 					    sf_port_wwn[j] != 0)
244fcf3ce44SJohn Forte 						return (1);
245fcf3ce44SJohn Forte 			}
246fcf3ce44SJohn Forte 		}
247fcf3ce44SJohn Forte 	}
248fcf3ce44SJohn Forte 	return (0);
249fcf3ce44SJohn Forte }
250fcf3ce44SJohn Forte 
251fcf3ce44SJohn Forte /*
252fcf3ce44SJohn Forte  * Inserts any missing port wwns for mpxio device paths
253fcf3ce44SJohn Forte  * which are in ONLINE or STANDBY state.
254fcf3ce44SJohn Forte  */
255fcf3ce44SJohn Forte static int
insert_missing_pwwn(char * phys_path,struct wwn_list_struct ** wwn_list_ptr)256fcf3ce44SJohn Forte insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr)
257fcf3ce44SJohn Forte {
258063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
259063d642aSBill Gumbrell 	int	i, pathcnt, match;
260063d642aSBill Gumbrell 	struct	wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found;
261063d642aSBill Gumbrell 	char	pwwn1[WWN_S_LEN];
262fcf3ce44SJohn Forte 
263fcf3ce44SJohn Forte 	/*
264fcf3ce44SJohn Forte 	 * Now check each scsi_vhci device path to find any missed
265fcf3ce44SJohn Forte 	 * port wwns and insert a new wwn list entry for the missed
266fcf3ce44SJohn Forte 	 * port wwn
267fcf3ce44SJohn Forte 	 */
268fcf3ce44SJohn Forte 	if (g_get_pathlist(phys_path, &pathlist)) {
269fcf3ce44SJohn Forte 		/* Free memory for pathlist before return */
270fcf3ce44SJohn Forte 		S_FREE(pathlist.path_info);
271fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
272fcf3ce44SJohn Forte 	}
273fcf3ce44SJohn Forte 
274fcf3ce44SJohn Forte 	pathcnt = pathlist.path_count;
275fcf3ce44SJohn Forte 	for (i = 0; i < pathcnt; i++) {
276fcf3ce44SJohn Forte 		/*
277fcf3ce44SJohn Forte 		 * Just search for ONLINE and STANDBY paths as
278fcf3ce44SJohn Forte 		 * those should be the only missing wwn entries.
279fcf3ce44SJohn Forte 		 * There is a very small window for an offline
280fcf3ce44SJohn Forte 		 * to have occurred between the time we retrieved
281fcf3ce44SJohn Forte 		 * the device list and a call to this function.
282fcf3ce44SJohn Forte 		 * If that happens, we just won't add it to
283fcf3ce44SJohn Forte 		 * the list which is probably a good thing.
284fcf3ce44SJohn Forte 		 */
285fcf3ce44SJohn Forte 		if (pathlist.path_info[i].path_state ==
286fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE ||
287fcf3ce44SJohn Forte 		    pathlist.path_info[i].path_state ==
288fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_STANDBY) {
289fcf3ce44SJohn Forte 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
290063d642aSBill Gumbrell 			    WWN_S_LEN - 1);
291fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
292fcf3ce44SJohn Forte 			/*
293fcf3ce44SJohn Forte 			 * Now search through wwn list for matching
294fcf3ce44SJohn Forte 			 * device path AND pwwn
295fcf3ce44SJohn Forte 			 * If it's found, continue to next path.
296fcf3ce44SJohn Forte 			 * If it's not found, add it the wwn list.
297fcf3ce44SJohn Forte 			 */
298fcf3ce44SJohn Forte 			match = 0;
299fcf3ce44SJohn Forte 
300fcf3ce44SJohn Forte 			for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL;
301fcf3ce44SJohn Forte 			    wwn_list_s = wwn_list_s->wwn_next) {
302fcf3ce44SJohn Forte 				if (strncmp(phys_path,
303063d642aSBill Gumbrell 				    wwn_list_s->physical_path,
304063d642aSBill Gumbrell 				    strlen(phys_path)) == 0) {
305fcf3ce44SJohn Forte 					wwn_list_found = wwn_list_s;
306fcf3ce44SJohn Forte 					if (strncmp(pwwn1,
307063d642aSBill Gumbrell 					    wwn_list_s->port_wwn_s,
308063d642aSBill Gumbrell 					    WWN_S_LEN) == 0) {
309fcf3ce44SJohn Forte 						match++;
310fcf3ce44SJohn Forte 						break;
311fcf3ce44SJohn Forte 					}
312fcf3ce44SJohn Forte 				}
313fcf3ce44SJohn Forte 			}
314fcf3ce44SJohn Forte 			if (match) {
315fcf3ce44SJohn Forte 				continue;
316fcf3ce44SJohn Forte 			} else {
317fcf3ce44SJohn Forte 				/*
318fcf3ce44SJohn Forte 				 * didn't find a match but the mpxio
319fcf3ce44SJohn Forte 				 * device is in the list. Retrieve
320fcf3ce44SJohn Forte 				 * the info from the wwn_list_found
321fcf3ce44SJohn Forte 				 * and add it to the list.
322fcf3ce44SJohn Forte 				 */
323fcf3ce44SJohn Forte 				if ((new_wwn = (struct  wwn_list_struct *)
324063d642aSBill Gumbrell 				    calloc(1,
325063d642aSBill Gumbrell 				    sizeof (struct  wwn_list_struct)))
326063d642aSBill Gumbrell 				    == NULL) {
327063d642aSBill Gumbrell 					S_FREE(pathlist.path_info);
328063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
329fcf3ce44SJohn Forte 				}
330fcf3ce44SJohn Forte 				if ((new_wwn->physical_path = (char *)
331063d642aSBill Gumbrell 				    calloc(1,
332063d642aSBill Gumbrell 				    strlen(wwn_list_found->physical_path)
333063d642aSBill Gumbrell 				    + 1)) == NULL) {
334063d642aSBill Gumbrell 					S_FREE(pathlist.path_info);
335063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
336fcf3ce44SJohn Forte 				}
337fcf3ce44SJohn Forte 				if ((new_wwn->logical_path = (char *)
338063d642aSBill Gumbrell 				    calloc(1,
339063d642aSBill Gumbrell 				    strlen(wwn_list_found->logical_path)
340063d642aSBill Gumbrell 				    + 1)) == NULL) {
341063d642aSBill Gumbrell 					S_FREE(pathlist.path_info);
342063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
343fcf3ce44SJohn Forte 				}
344fcf3ce44SJohn Forte 
345fcf3ce44SJohn Forte 				/*
346fcf3ce44SJohn Forte 				 * Insert new_wwn at the beginning of the list.
347fcf3ce44SJohn Forte 				 */
348fcf3ce44SJohn Forte 				new_wwn->wwn_next = *wwn_list_ptr;
349fcf3ce44SJohn Forte 				(*wwn_list_ptr)->wwn_prev = new_wwn;
350fcf3ce44SJohn Forte 
351fcf3ce44SJohn Forte 				/* set new starting ptr */
352fcf3ce44SJohn Forte 				*wwn_list_ptr = new_wwn;
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 				memcpy(new_wwn->physical_path,
355fcf3ce44SJohn Forte 				    wwn_list_found->physical_path,
356063d642aSBill Gumbrell 				    strlen(wwn_list_found->physical_path));
357fcf3ce44SJohn Forte 				memcpy(new_wwn->logical_path,
358fcf3ce44SJohn Forte 				    wwn_list_found->logical_path,
359063d642aSBill Gumbrell 				    strlen(wwn_list_found->logical_path));
360fcf3ce44SJohn Forte 				/*
361fcf3ce44SJohn Forte 				 * Copy found node wwn data to this new entry
362fcf3ce44SJohn Forte 				 * Node wwn is required for the wwn_list
363fcf3ce44SJohn Forte 				 * however for mpxio devices it is not
364fcf3ce44SJohn Forte 				 * relevant as it may apply to multiple
365fcf3ce44SJohn Forte 				 * target controllers, so just use what
366fcf3ce44SJohn Forte 				 * we already have in wwn_list_found.
367fcf3ce44SJohn Forte 				 */
368fcf3ce44SJohn Forte 				memcpy(new_wwn->node_wwn_s,
369fcf3ce44SJohn Forte 				    wwn_list_found->node_wwn_s, WWN_S_LEN);
370fcf3ce44SJohn Forte 				memcpy(new_wwn->w_node_wwn,
371fcf3ce44SJohn Forte 				    wwn_list_found->w_node_wwn, WWN_SIZE);
372fcf3ce44SJohn Forte 				new_wwn->device_type =
373fcf3ce44SJohn Forte 				    wwn_list_found->device_type;
374fcf3ce44SJohn Forte 				memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN);
375fcf3ce44SJohn Forte 			}
376fcf3ce44SJohn Forte 		}
377fcf3ce44SJohn Forte 	}
378fcf3ce44SJohn Forte 	S_FREE(pathlist.path_info);
379fcf3ce44SJohn Forte 	return (0);
380fcf3ce44SJohn Forte }
381fcf3ce44SJohn Forte 
382fcf3ce44SJohn Forte /*
383fcf3ce44SJohn Forte  * gets the port wwn for a scsi_vhci device using ONLINE path priority
384fcf3ce44SJohn Forte  */
385fcf3ce44SJohn Forte static int
get_scsi_vhci_port_wwn(char * phys_path,uchar_t * port_wwn)386fcf3ce44SJohn Forte get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn)
387fcf3ce44SJohn Forte {
388063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
389063d642aSBill Gumbrell 	int	i, pathcnt, found;
390063d642aSBill Gumbrell 	char	pwwn1[WWN_S_LEN];
391fcf3ce44SJohn Forte 
392fcf3ce44SJohn Forte 	if (g_get_pathlist(phys_path, &pathlist)) {
393fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
394fcf3ce44SJohn Forte 	}
395fcf3ce44SJohn Forte 
396fcf3ce44SJohn Forte 	found = 0;
397fcf3ce44SJohn Forte 	pathcnt = pathlist.path_count;
398fcf3ce44SJohn Forte 	/*
399fcf3ce44SJohn Forte 	 * Look for an ONLINE path first.
400fcf3ce44SJohn Forte 	 * If that fails, get the STANDBY path port WWN
401fcf3ce44SJohn Forte 	 * If that fails, give up
402fcf3ce44SJohn Forte 	 */
403fcf3ce44SJohn Forte 	for (i = 0; found == 0 && i < pathcnt; i++) {
404fcf3ce44SJohn Forte 		if (pathlist.path_info[i].path_state ==
405fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
406fcf3ce44SJohn Forte 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
407063d642aSBill Gumbrell 			    WWN_S_LEN - 1);
408fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
409fcf3ce44SJohn Forte 			found++;
410fcf3ce44SJohn Forte 		}
411fcf3ce44SJohn Forte 	}
412fcf3ce44SJohn Forte 
413fcf3ce44SJohn Forte 	for (i = 0; found == 0 && i < pathcnt; i++) {
414fcf3ce44SJohn Forte 		if (pathlist.path_info[i].path_state ==
415fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_STANDBY) {
416fcf3ce44SJohn Forte 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
417063d642aSBill Gumbrell 			    WWN_S_LEN - 1);
418fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
419fcf3ce44SJohn Forte 			found++;
420fcf3ce44SJohn Forte 		}
421fcf3ce44SJohn Forte 	}
422fcf3ce44SJohn Forte 
423fcf3ce44SJohn Forte 	S_FREE(pathlist.path_info);
424fcf3ce44SJohn Forte 	if (found) {
425fcf3ce44SJohn Forte 		return (string_to_wwn((uchar_t *)pwwn1, port_wwn));
426fcf3ce44SJohn Forte 	} else {
427fcf3ce44SJohn Forte 		return (-1);
428fcf3ce44SJohn Forte 	}
429fcf3ce44SJohn Forte }
430fcf3ce44SJohn Forte 
431fcf3ce44SJohn Forte /*
432fcf3ce44SJohn Forte  * searches wwn_list_found for the pwwn passed in
433fcf3ce44SJohn Forte  * and sets the corresponding nwwn on return.
434fcf3ce44SJohn Forte  * If no match is found, -1 is returned and nwwn is not set.
435fcf3ce44SJohn Forte  */
436fcf3ce44SJohn Forte static int
search_wwn_entry(struct wwn_list_found_struct * wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)437fcf3ce44SJohn Forte search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn,
438063d642aSBill Gumbrell     uchar_t *nwwn)
439fcf3ce44SJohn Forte {
440063d642aSBill Gumbrell 	struct	wwn_list_found_struct *wwn_list_s;
441fcf3ce44SJohn Forte 
442fcf3ce44SJohn Forte 	for (wwn_list_s = wwn_list_found; wwn_list_s != NULL;
443fcf3ce44SJohn Forte 	    wwn_list_s = wwn_list_s->wwn_next) {
444063d642aSBill Gumbrell 		if (memcmp(pwwn, wwn_list_s->port_wwn, WWN_SIZE) == 0) {
445fcf3ce44SJohn Forte 			memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE);
446fcf3ce44SJohn Forte 			return (0);
447fcf3ce44SJohn Forte 		}
448fcf3ce44SJohn Forte 	}
449fcf3ce44SJohn Forte 	return (-1);
450fcf3ce44SJohn Forte }
451fcf3ce44SJohn Forte 
452fcf3ce44SJohn Forte /*
453fcf3ce44SJohn Forte  * adds a nwwn, pwwn entry to the next entry in wwn_list_found list
454fcf3ce44SJohn Forte  */
455fcf3ce44SJohn Forte static int
add_wwn_entry(struct wwn_list_found_struct ** wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)456fcf3ce44SJohn Forte add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn,
457063d642aSBill Gumbrell     uchar_t *nwwn)
458fcf3ce44SJohn Forte {
459063d642aSBill Gumbrell 	struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL;
460fcf3ce44SJohn Forte 
461fcf3ce44SJohn Forte 	/* Got wwns, load data in list */
462fcf3ce44SJohn Forte 	if ((new_wwn = (struct  wwn_list_found_struct *)
463063d642aSBill Gumbrell 	    calloc(1, sizeof (struct  wwn_list_found_struct))) == NULL) {
464fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
465fcf3ce44SJohn Forte 	}
466fcf3ce44SJohn Forte 
467fcf3ce44SJohn Forte 	memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE);
468fcf3ce44SJohn Forte 	memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE);
469fcf3ce44SJohn Forte 
470fcf3ce44SJohn Forte 	/*
471fcf3ce44SJohn Forte 	 * Insert new_wwn in the list
472fcf3ce44SJohn Forte 	 */
473fcf3ce44SJohn Forte 	if (*wwn_list_found != NULL) {
474fcf3ce44SJohn Forte 		temp_wwn_list_found = (*wwn_list_found)->wwn_next;
475fcf3ce44SJohn Forte 		(*wwn_list_found)->wwn_next = new_wwn;
476fcf3ce44SJohn Forte 	} else {
477fcf3ce44SJohn Forte 		*wwn_list_found = new_wwn;
478fcf3ce44SJohn Forte 	}
479fcf3ce44SJohn Forte 	new_wwn->wwn_next = temp_wwn_list_found;
480fcf3ce44SJohn Forte 
481fcf3ce44SJohn Forte 	return (0);
482fcf3ce44SJohn Forte }
483fcf3ce44SJohn Forte 
484fcf3ce44SJohn Forte 
485fcf3ce44SJohn Forte /*
486fcf3ce44SJohn Forte  * Create a linked list of all the WWN's for all FC_AL disks and
487fcf3ce44SJohn Forte  * tapes that are attached to this host.
488fcf3ce44SJohn Forte  *
489fcf3ce44SJohn Forte  * RETURN VALUES: 0 O.K.
490fcf3ce44SJohn Forte  *
491fcf3ce44SJohn Forte  * wwn_list pointer:
492fcf3ce44SJohn Forte  *			NULL: No devices found.
493fcf3ce44SJohn Forte  *			!NULL: Devices found
494fcf3ce44SJohn Forte  *                      wwn_list points to a linked list of wwn's.
495fcf3ce44SJohn Forte  */
496fcf3ce44SJohn Forte int
g_get_wwn_list(struct wwn_list_struct ** wwn_list_ptr,int verbose)497fcf3ce44SJohn Forte g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose)
498fcf3ce44SJohn Forte {
499063d642aSBill Gumbrell 	struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL;
500063d642aSBill Gumbrell 	struct wwn_list_found_struct *wwn_list_found = NULL;
501063d642aSBill Gumbrell 	int err;
502063d642aSBill Gumbrell 	int al_pa;
503063d642aSBill Gumbrell 	uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
504063d642aSBill Gumbrell 	hrtime_t	start_time, end_time;
505063d642aSBill Gumbrell 	char *env = NULL;
506fcf3ce44SJohn Forte 
507fcf3ce44SJohn Forte 	/* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */
508fcf3ce44SJohn Forte 	if (wwn_list_ptr == NULL) {
509fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
510fcf3ce44SJohn Forte 	}
511fcf3ce44SJohn Forte 
512fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
513fcf3ce44SJohn Forte 		start_time = gethrtime();
514fcf3ce44SJohn Forte 	}
515fcf3ce44SJohn Forte 
516063d642aSBill Gumbrell 	if ((err = g_devices_get_all(wwn_list_ptr)) != 0) {
517fcf3ce44SJohn Forte 		return (err);
518fcf3ce44SJohn Forte 	}
519fcf3ce44SJohn Forte 
520fcf3ce44SJohn Forte 	/*
521fcf3ce44SJohn Forte 	 * retain backward compatibility with g_get_wwn_list
522fcf3ce44SJohn Forte 	 * and retrieve the WWN for scsi_vhci devices in the
523fcf3ce44SJohn Forte 	 * same fashion
524fcf3ce44SJohn Forte 	 * Note that for scsi_vhci devices, the wwn fields are
525fcf3ce44SJohn Forte 	 * not relevant but in the previous versions
526fcf3ce44SJohn Forte 	 * we loaded the wwns so...
527fcf3ce44SJohn Forte 	 */
528fcf3ce44SJohn Forte 	wwn_list_p = *wwn_list_ptr;
529fcf3ce44SJohn Forte 	while (wwn_list_p != NULL) {
530063d642aSBill Gumbrell 		if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
531063d642aSBill Gumbrell 			/* get port wwn of first ONLINE, STANDBY */
532063d642aSBill Gumbrell 			if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path,
533063d642aSBill Gumbrell 			    port_wwn)) == 0) {
534063d642aSBill Gumbrell 				if ((search_wwn_entry(wwn_list_found, port_wwn,
535063d642aSBill Gumbrell 				    node_wwn)) != 0) {
536063d642aSBill Gumbrell 					if ((err =
537063d642aSBill Gumbrell 					    get_wwns(wwn_list_p->physical_path,
538063d642aSBill Gumbrell 					    port_wwn,
539063d642aSBill Gumbrell 					    node_wwn, &al_pa,
540063d642aSBill Gumbrell 					    &wwn_list_found)) != 0) {
541063d642aSBill Gumbrell 						g_free_wwn_list_found(
542063d642aSBill Gumbrell 						    &wwn_list_found);
543063d642aSBill Gumbrell 						return (err);
544063d642aSBill Gumbrell 					}
545063d642aSBill Gumbrell 				}
546fcf3ce44SJohn Forte 			} else {
547063d642aSBill Gumbrell 				/* Use g_get_wwn as a last resort */
548063d642aSBill Gumbrell 				if ((err = g_get_wwn(wwn_list_p->physical_path,
549063d642aSBill Gumbrell 				    port_wwn, node_wwn, &al_pa, 0)) != 0) {
550063d642aSBill Gumbrell 					/*
551063d642aSBill Gumbrell 					 * this is a bad WWN.
552063d642aSBill Gumbrell 					 * remove it from the wwn_list.
553063d642aSBill Gumbrell 					 *
554063d642aSBill Gumbrell 					 * After removing the bad WWN,
555063d642aSBill Gumbrell 					 * wwn_list_p should point to the next
556063d642aSBill Gumbrell 					 * node in the list.
557063d642aSBill Gumbrell 					 */
558063d642aSBill Gumbrell 					if ((wwn_list_p->wwn_prev == NULL) &&
559063d642aSBill Gumbrell 					    (wwn_list_p->wwn_next == NULL)) {
560063d642aSBill Gumbrell 						*wwn_list_ptr = NULL;
561063d642aSBill Gumbrell 						free(wwn_list_p);
562063d642aSBill Gumbrell 						g_free_wwn_list_found(
563063d642aSBill Gumbrell 						    &wwn_list_found);
564063d642aSBill Gumbrell 						return (L_NO_DEVICES_FOUND);
565063d642aSBill Gumbrell 					} else if (
566063d642aSBill Gumbrell 					    wwn_list_p->wwn_prev == NULL) {
567063d642aSBill Gumbrell 						*wwn_list_ptr =
568063d642aSBill Gumbrell 						    wwn_list_p->wwn_next;
569063d642aSBill Gumbrell 						free(wwn_list_p);
570063d642aSBill Gumbrell 						wwn_list_p = *wwn_list_ptr;
571063d642aSBill Gumbrell 						wwn_list_p->wwn_prev = NULL;
572063d642aSBill Gumbrell 					} else if (
573063d642aSBill Gumbrell 					    wwn_list_p->wwn_next == NULL) {
574063d642aSBill Gumbrell 						wwn_list_p->wwn_prev->wwn_next =
575063d642aSBill Gumbrell 						    NULL;
576063d642aSBill Gumbrell 						free(wwn_list_p);
577063d642aSBill Gumbrell 						wwn_list_p = NULL;
578063d642aSBill Gumbrell 					} else {
579063d642aSBill Gumbrell 						wwn_list_tmp_p =
580063d642aSBill Gumbrell 						    wwn_list_p->wwn_next;
581063d642aSBill Gumbrell 						wwn_list_p->wwn_prev->wwn_next =
582063d642aSBill Gumbrell 						    wwn_list_p->wwn_next;
583063d642aSBill Gumbrell 						wwn_list_p->wwn_next->wwn_prev =
584063d642aSBill Gumbrell 						    wwn_list_p->wwn_prev;
585063d642aSBill Gumbrell 						free(wwn_list_p);
586063d642aSBill Gumbrell 						wwn_list_p = wwn_list_tmp_p;
587063d642aSBill Gumbrell 					}
588063d642aSBill Gumbrell 					continue;
589063d642aSBill Gumbrell 				}
590fcf3ce44SJohn Forte 			}
591063d642aSBill Gumbrell 			copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn);
592063d642aSBill Gumbrell 			copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn);
593063d642aSBill Gumbrell 			memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE);
594fcf3ce44SJohn Forte 		}
595063d642aSBill Gumbrell 		wwn_list_p = wwn_list_p->wwn_next;
596fcf3ce44SJohn Forte 	}
597fcf3ce44SJohn Forte 	g_free_wwn_list_found(&wwn_list_found);
598fcf3ce44SJohn Forte 
599fcf3ce44SJohn Forte 	/*
600fcf3ce44SJohn Forte 	 * Now go through the list one more time to add entries for
601fcf3ce44SJohn Forte 	 * any missing port wwns.
602fcf3ce44SJohn Forte 	 * This allows a search on port wwn for any paths which are
603fcf3ce44SJohn Forte 	 * ONLINE or STANDBY. We don't care about OFFLINE as those won't
604fcf3ce44SJohn Forte 	 * and should not show up in the list
605fcf3ce44SJohn Forte 	 */
606fcf3ce44SJohn Forte 	for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL;
607fcf3ce44SJohn Forte 	    wwn_list_p = wwn_list_p->wwn_next) {
608063d642aSBill Gumbrell 		if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
609063d642aSBill Gumbrell 			if ((err = insert_missing_pwwn(
610063d642aSBill Gumbrell 			    wwn_list_p->physical_path, wwn_list_ptr)) != 0)
611063d642aSBill Gumbrell 				return (err);
612063d642aSBill Gumbrell 		}
613fcf3ce44SJohn Forte 	}
614fcf3ce44SJohn Forte 
615fcf3ce44SJohn Forte 	if (env != NULL) {
616fcf3ce44SJohn Forte 		end_time = gethrtime();
617fcf3ce44SJohn Forte 		fprintf(stdout, "      g_get_wwn_list: "
618063d642aSBill Gumbrell 		    "\t\tTime = %lld millisec\n",
619063d642aSBill Gumbrell 		    (end_time - start_time)/1000000);
620fcf3ce44SJohn Forte 	}
621fcf3ce44SJohn Forte 	return (0);
622fcf3ce44SJohn Forte 
623fcf3ce44SJohn Forte }
624fcf3ce44SJohn Forte 
625fcf3ce44SJohn Forte int
g_devices_get_all(struct wwn_list_struct ** wwn_list_ptr)626fcf3ce44SJohn Forte g_devices_get_all(struct wwn_list_struct **wwn_list_ptr)
627fcf3ce44SJohn Forte {
628063d642aSBill Gumbrell 	struct wwn_list_struct *tape_ptr = NULL;
629063d642aSBill Gumbrell 	struct wwn_list_struct *tmp;
630063d642aSBill Gumbrell 	int err;
631063d642aSBill Gumbrell 	di_node_t root;
632063d642aSBill Gumbrell 	hrtime_t	start_time, end_time;
633063d642aSBill Gumbrell 	char *env = NULL;
634fcf3ce44SJohn Forte 
635fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
636fcf3ce44SJohn Forte 		start_time = gethrtime();
637fcf3ce44SJohn Forte 	}
638fcf3ce44SJohn Forte 
639fcf3ce44SJohn Forte 	/*
640fcf3ce44SJohn Forte 	 * Try to prime di_drv_first_node()
641fcf3ce44SJohn Forte 	 * If there are no nodes bound, di_drv_first_node()
642fcf3ce44SJohn Forte 	 * will return nothing.
643fcf3ce44SJohn Forte 	 */
644fcf3ce44SJohn Forte 	init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST);
645fcf3ce44SJohn Forte 	init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD);
646fcf3ce44SJohn Forte 
647fcf3ce44SJohn Forte 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
648fcf3ce44SJohn Forte 		return (L_DEV_SNAPSHOT_FAILED);
649fcf3ce44SJohn Forte 	}
650fcf3ce44SJohn Forte 
651fcf3ce44SJohn Forte 	if (env != NULL) {
652fcf3ce44SJohn Forte 		end_time = gethrtime();
653fcf3ce44SJohn Forte 		fprintf(stdout, "      di_init - /:  "
654063d642aSBill Gumbrell 		    "\t\tTime = %lld millisec\n",
655063d642aSBill Gumbrell 		    (end_time - start_time)/1000000);
656fcf3ce44SJohn Forte 	}
657fcf3ce44SJohn Forte 
658fcf3ce44SJohn Forte 	if (env != NULL) {
659fcf3ce44SJohn Forte 		start_time = gethrtime();
660fcf3ce44SJohn Forte 	}
661fcf3ce44SJohn Forte 
662fcf3ce44SJohn Forte 	if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME,
663063d642aSBill Gumbrell 	    wwn_list_ptr)) != 0) {
664fcf3ce44SJohn Forte 		if (err != L_NO_DEVICES_FOUND) {
665fcf3ce44SJohn Forte 			di_fini(root);
666fcf3ce44SJohn Forte 			g_free_wwn_list(&tape_ptr);
667fcf3ce44SJohn Forte 			g_free_wwn_list(wwn_list_ptr);
668fcf3ce44SJohn Forte 			return (err);
669fcf3ce44SJohn Forte 		}
670fcf3ce44SJohn Forte 	}
671fcf3ce44SJohn Forte 
672fcf3ce44SJohn Forte 	if (env != NULL) {
673fcf3ce44SJohn Forte 		end_time = gethrtime();
674fcf3ce44SJohn Forte 		fprintf(stdout, "      devices_get_all - ssd:  "
675063d642aSBill Gumbrell 		    "\t\tTime = %lld millisec\n",
676063d642aSBill Gumbrell 		    (end_time - start_time)/1000000);
677fcf3ce44SJohn Forte 	}
678fcf3ce44SJohn Forte 
679fcf3ce44SJohn Forte 	if (env != NULL) {
680fcf3ce44SJohn Forte 		start_time = gethrtime();
681fcf3ce44SJohn Forte 	}
682fcf3ce44SJohn Forte 
683fcf3ce44SJohn Forte 	if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME,
684063d642aSBill Gumbrell 	    &tape_ptr)) != 0) {
685fcf3ce44SJohn Forte 		di_fini(root);
686fcf3ce44SJohn Forte 		if (err != L_NO_DEVICES_FOUND) {
687fcf3ce44SJohn Forte 			g_free_wwn_list(&tape_ptr);
688fcf3ce44SJohn Forte 			g_free_wwn_list(wwn_list_ptr);
689fcf3ce44SJohn Forte 			return (err);
690fcf3ce44SJohn Forte 		} else {
691fcf3ce44SJohn Forte 			/*
692fcf3ce44SJohn Forte 			 * if *wwn_list_ptr == NULL
693fcf3ce44SJohn Forte 			 * we have disks but no tapes
694fcf3ce44SJohn Forte 			 * Just return
695fcf3ce44SJohn Forte 			 */
696fcf3ce44SJohn Forte 			if (*wwn_list_ptr != NULL) {
697fcf3ce44SJohn Forte 				return (0);
698fcf3ce44SJohn Forte 			} else {
699fcf3ce44SJohn Forte 				/*
700fcf3ce44SJohn Forte 				 * No disks or tapes
701fcf3ce44SJohn Forte 				 */
702fcf3ce44SJohn Forte 				g_free_wwn_list(&tape_ptr);
703fcf3ce44SJohn Forte 				g_free_wwn_list(wwn_list_ptr);
704fcf3ce44SJohn Forte 				return (err);
705fcf3ce44SJohn Forte 			}
706fcf3ce44SJohn Forte 		}
707fcf3ce44SJohn Forte 	}
708fcf3ce44SJohn Forte 
709fcf3ce44SJohn Forte 	if (env != NULL) {
710fcf3ce44SJohn Forte 		end_time = gethrtime();
711fcf3ce44SJohn Forte 		fprintf(stdout, "      devices_get_all - st: "
712063d642aSBill Gumbrell 		    "\t\tTime = %lld millisec\n",
713063d642aSBill Gumbrell 		    (end_time - start_time)/1000000);
714fcf3ce44SJohn Forte 	}
715fcf3ce44SJohn Forte 
716fcf3ce44SJohn Forte 	/* Now link the two together */
717fcf3ce44SJohn Forte 	if (*wwn_list_ptr != NULL) { /* We have both disks and tapes */
718fcf3ce44SJohn Forte 		/* Walk to the end of it */
719fcf3ce44SJohn Forte 		for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL;
720063d642aSBill Gumbrell 		    tmp = tmp->wwn_next)
721063d642aSBill Gumbrell 			;
722fcf3ce44SJohn Forte 		tmp->wwn_next = tape_ptr;
723fcf3ce44SJohn Forte 		tape_ptr->wwn_prev = tmp;
724fcf3ce44SJohn Forte 		di_fini(root);
725fcf3ce44SJohn Forte 		return (0);
726fcf3ce44SJohn Forte 	}
727fcf3ce44SJohn Forte 
728fcf3ce44SJohn Forte 	/* else we have no disks */
729fcf3ce44SJohn Forte 	*wwn_list_ptr = tape_ptr;
730fcf3ce44SJohn Forte 	di_fini(root);
731fcf3ce44SJohn Forte 	return (0);
732fcf3ce44SJohn Forte }
733fcf3ce44SJohn Forte 
734fcf3ce44SJohn Forte void
g_free_wwn_list_found(struct wwn_list_found_struct ** wwn_list_found)735*926d645fSToomas Soome g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found)
736*926d645fSToomas Soome {
737fcf3ce44SJohn Forte 	WWN_list_found	    *next = NULL;
738fcf3ce44SJohn Forte 
739fcf3ce44SJohn Forte 	/* return if wwn_list_found is NULL */
740fcf3ce44SJohn Forte 	if (wwn_list_found == NULL) {
741fcf3ce44SJohn Forte 		return;
742fcf3ce44SJohn Forte 	}
743fcf3ce44SJohn Forte 	for (; *wwn_list_found != NULL; *wwn_list_found = next) {
744fcf3ce44SJohn Forte 		next = (*wwn_list_found)->wwn_next;
745fcf3ce44SJohn Forte 		g_destroy_data(*wwn_list_found);
746fcf3ce44SJohn Forte 		*wwn_list_found = NULL;
747fcf3ce44SJohn Forte 	}
748fcf3ce44SJohn Forte }
749fcf3ce44SJohn Forte 
750fcf3ce44SJohn Forte void
g_free_wwn_list(struct wwn_list_struct ** wwn_list)751fcf3ce44SJohn Forte g_free_wwn_list(struct wwn_list_struct **wwn_list)
752fcf3ce44SJohn Forte {
753063d642aSBill Gumbrell 	WWN_list	*next = NULL;
754fcf3ce44SJohn Forte 
755fcf3ce44SJohn Forte 	/* return if wwn_list is NULL */
756fcf3ce44SJohn Forte 	if (wwn_list == NULL) {
757fcf3ce44SJohn Forte 		return;
758fcf3ce44SJohn Forte 	}
759fcf3ce44SJohn Forte 
760fcf3ce44SJohn Forte 	for (; *wwn_list != NULL; *wwn_list = next) {
761fcf3ce44SJohn Forte 		next = (*wwn_list)->wwn_next;
762fcf3ce44SJohn Forte 		if ((*wwn_list)->physical_path != NULL)
763fcf3ce44SJohn Forte 			(void) g_destroy_data((*wwn_list)->physical_path);
764fcf3ce44SJohn Forte 		if ((*wwn_list)->logical_path != NULL)
765fcf3ce44SJohn Forte 			(void) g_destroy_data((*wwn_list)->logical_path);
766fcf3ce44SJohn Forte 		(void) g_destroy_data(*wwn_list);
767fcf3ce44SJohn Forte 	}
768fcf3ce44SJohn Forte 	wwn_list = NULL;
769fcf3ce44SJohn Forte }
770fcf3ce44SJohn Forte 
771fcf3ce44SJohn Forte 
772fcf3ce44SJohn Forte 
773fcf3ce44SJohn Forte 
774fcf3ce44SJohn Forte void
g_sort_wwn_list(struct wwn_list_struct ** wwn_list)775fcf3ce44SJohn Forte g_sort_wwn_list(struct wwn_list_struct **wwn_list)
776fcf3ce44SJohn Forte {
777fcf3ce44SJohn Forte 	int			i, n;
778fcf3ce44SJohn Forte 	struct wwn_list_struct	**wwn_list_array;
779fcf3ce44SJohn Forte 	struct wwn_list_struct	*wwn_list_ptr;
780fcf3ce44SJohn Forte 	struct wwn_list_struct	**wwn_list_array_ptr1;
781fcf3ce44SJohn Forte 	struct wwn_list_struct	**wwn_list_array_ptr2;
782fcf3ce44SJohn Forte 
783fcf3ce44SJohn Forte 	/*
784fcf3ce44SJohn Forte 	 * Count the number of wwn_list in the list
785fcf3ce44SJohn Forte 	 */
786fcf3ce44SJohn Forte 	for (n = 0,  wwn_list_ptr = *wwn_list;
787fcf3ce44SJohn Forte 	    wwn_list_ptr != NULL;
788fcf3ce44SJohn Forte 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
789fcf3ce44SJohn Forte 		n++;
790fcf3ce44SJohn Forte 	}
791fcf3ce44SJohn Forte 	if (n <= 1) {
792fcf3ce44SJohn Forte 		return;
793fcf3ce44SJohn Forte 	}
794fcf3ce44SJohn Forte 
795fcf3ce44SJohn Forte 	/*
796fcf3ce44SJohn Forte 	 * Allocate a simple wwn_list array and fill it in
797fcf3ce44SJohn Forte 	 */
798fcf3ce44SJohn Forte 	wwn_list_array = (struct wwn_list_struct **)
799fcf3ce44SJohn Forte 	    g_zalloc((n+1) * sizeof (struct wwn_list_struct *));
800fcf3ce44SJohn Forte 
801fcf3ce44SJohn Forte 	wwn_list_array_ptr1 = wwn_list_array;
802fcf3ce44SJohn Forte 	for (wwn_list_ptr = *wwn_list;
803fcf3ce44SJohn Forte 	    wwn_list_ptr != NULL;
804fcf3ce44SJohn Forte 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
805fcf3ce44SJohn Forte 		*wwn_list_array_ptr1++ = wwn_list_ptr;
806fcf3ce44SJohn Forte 	}
807fcf3ce44SJohn Forte 	*wwn_list_array_ptr1 = NULL;
808fcf3ce44SJohn Forte 
809fcf3ce44SJohn Forte 	/*
810fcf3ce44SJohn Forte 	 * Sort the wwn_list array
811fcf3ce44SJohn Forte 	 */
812fcf3ce44SJohn Forte 	qsort((void *) wwn_list_array, n,
813fcf3ce44SJohn Forte 	    sizeof (struct wwn_list_struct *), wwn_list_name_compare);
814fcf3ce44SJohn Forte 
815fcf3ce44SJohn Forte 	/*
816fcf3ce44SJohn Forte 	 * Rebuild the linked list wwn_list structure
817fcf3ce44SJohn Forte 	 */
818fcf3ce44SJohn Forte 	wwn_list_array_ptr1 = wwn_list_array;
819fcf3ce44SJohn Forte 	*wwn_list = *wwn_list_array_ptr1;
820fcf3ce44SJohn Forte 	wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1;
821fcf3ce44SJohn Forte 	(*wwn_list_array_ptr1)->wwn_prev = NULL;
822fcf3ce44SJohn Forte 	for (i = 0; i < n - 1; i++) {
823063d642aSBill Gumbrell 		(*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1;
824063d642aSBill Gumbrell 		(*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++;
825fcf3ce44SJohn Forte 	}
826fcf3ce44SJohn Forte 	(*wwn_list_array_ptr1)->wwn_next = NULL;
827fcf3ce44SJohn Forte 
828fcf3ce44SJohn Forte 	/*
829fcf3ce44SJohn Forte 	 * Clean up
830fcf3ce44SJohn Forte 	 */
831fcf3ce44SJohn Forte 	(void) g_destroy_data((void *)wwn_list_array);
832fcf3ce44SJohn Forte }
833fcf3ce44SJohn Forte 
834fcf3ce44SJohn Forte int
wwn_list_name_compare(const void * arg1,const void * arg2)835fcf3ce44SJohn Forte wwn_list_name_compare(const void *arg1, const void *arg2)
836fcf3ce44SJohn Forte {
837fcf3ce44SJohn Forte 	char	*s1, *s2;
838fcf3ce44SJohn Forte 	int	n1, n2;
839fcf3ce44SJohn Forte 	char	*p1, *p2;
840fcf3ce44SJohn Forte 
841fcf3ce44SJohn Forte 	s1 = (*((struct wwn_list_struct **)arg1))->logical_path;
842fcf3ce44SJohn Forte 	s2 = (*((struct wwn_list_struct **)arg2))->logical_path;
843fcf3ce44SJohn Forte 	for (;;) {
844fcf3ce44SJohn Forte 		if (*s1 == 0 || *s2 == 0)
845fcf3ce44SJohn Forte 			break;
846fcf3ce44SJohn Forte 		if ((isdigit(*s1) && isdigit(*s2))) {
847fcf3ce44SJohn Forte 			n1 = strtol(s1, &p1, 10);
848fcf3ce44SJohn Forte 			n2 = strtol(s2, &p2, 10);
849fcf3ce44SJohn Forte 			if (n1 != n2) {
850fcf3ce44SJohn Forte 				return (n1 - n2);
851fcf3ce44SJohn Forte 			}
852fcf3ce44SJohn Forte 			s1 = p1;
853fcf3ce44SJohn Forte 			s2 = p2;
854fcf3ce44SJohn Forte 		} else if (*s1 != *s2) {
855fcf3ce44SJohn Forte 			break;
856fcf3ce44SJohn Forte 		} else {
857fcf3ce44SJohn Forte 			s1++;
858fcf3ce44SJohn Forte 			s2++;
859fcf3ce44SJohn Forte 		}
860fcf3ce44SJohn Forte 	}
861fcf3ce44SJohn Forte 	return (*s1 - *s2);
862fcf3ce44SJohn Forte }
863fcf3ce44SJohn Forte 
864fcf3ce44SJohn Forte /*
865fcf3ce44SJohn Forte  * Get the limited map for FC4 devices.
866fcf3ce44SJohn Forte  * This function is specific to FC4
867fcf3ce44SJohn Forte  * devices and doesn't work for FC (leadville) devices.
868fcf3ce44SJohn Forte  *
869fcf3ce44SJohn Forte  * RETURN VALUES:
870fcf3ce44SJohn Forte  *	0	 O.K.
871fcf3ce44SJohn Forte  *	non-zero otherwise
872fcf3ce44SJohn Forte  *
873fcf3ce44SJohn Forte  * lilpmap *map_ptr:
874fcf3ce44SJohn Forte  *		NULL: No devices found
875fcf3ce44SJohn Forte  *		!NULL: if devices found
876fcf3ce44SJohn Forte  */
877fcf3ce44SJohn Forte int
g_get_limited_map(char * path,struct lilpmap * map_ptr,int verbose)878fcf3ce44SJohn Forte g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose)
879fcf3ce44SJohn Forte {
880063d642aSBill Gumbrell 	int	fd, i;
881063d642aSBill Gumbrell 	char	drvr_path[MAXPATHLEN];
882063d642aSBill Gumbrell 	struct	stat	stbuf;
883fcf3ce44SJohn Forte 
884fcf3ce44SJohn Forte 
885fcf3ce44SJohn Forte 	/* initialize map */
886fcf3ce44SJohn Forte 	(void) memset(map_ptr, 0, sizeof (struct lilpmap));
887fcf3ce44SJohn Forte 
888fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
889fcf3ce44SJohn Forte 	/*
890fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
891fcf3ce44SJohn Forte 	 *
892fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
893fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0:1
894fcf3ce44SJohn Forte 	 * or
895fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0
896fcf3ce44SJohn Forte 	 * or
897fcf3ce44SJohn Forte 	 * a 1 level PCI type driver
898fcf3ce44SJohn Forte 	 */
899fcf3ce44SJohn Forte 	if (stat(drvr_path, &stbuf) < 0) {
900fcf3ce44SJohn Forte 		return (L_LSTAT_ERROR);
901fcf3ce44SJohn Forte 	}
902fcf3ce44SJohn Forte 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
903fcf3ce44SJohn Forte 		/* append a port. Just try 0 since they did not give us one */
904fcf3ce44SJohn Forte 		(void) strcat(drvr_path, ":0");
905fcf3ce44SJohn Forte 	}
906fcf3ce44SJohn Forte 
907fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_limited_map: Geting drive map from:"
908063d642aSBill Gumbrell 	    " %s\n", drvr_path);
909fcf3ce44SJohn Forte 
910fcf3ce44SJohn Forte 	/* open controller */
911fcf3ce44SJohn Forte 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
912fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
913fcf3ce44SJohn Forte 
914fcf3ce44SJohn Forte 	if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) {
915fcf3ce44SJohn Forte 		I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
916fcf3ce44SJohn Forte 		(void) close(fd);
917fcf3ce44SJohn Forte 		return (L_FCIO_GETMAP_IOCTL_FAIL);
918fcf3ce44SJohn Forte 	}
919fcf3ce44SJohn Forte 	(void) close(fd);
920fcf3ce44SJohn Forte 
921fcf3ce44SJohn Forte 	/*
922fcf3ce44SJohn Forte 	 * Check for reasonableness.
923fcf3ce44SJohn Forte 	 */
924fcf3ce44SJohn Forte 	if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) {
925fcf3ce44SJohn Forte 		return (L_INVALID_LOOP_MAP);
926fcf3ce44SJohn Forte 	}
927fcf3ce44SJohn Forte 	for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) {
928fcf3ce44SJohn Forte 		if (map_ptr->lilp_list[i] > 0xef) {
929fcf3ce44SJohn Forte 			return (L_INVALID_LOOP_MAP);
930fcf3ce44SJohn Forte 		}
931fcf3ce44SJohn Forte 	}
932fcf3ce44SJohn Forte 
933fcf3ce44SJohn Forte 	return (0);
934fcf3ce44SJohn Forte }
935fcf3ce44SJohn Forte 
936fcf3ce44SJohn Forte 
937fcf3ce44SJohn Forte /*
938fcf3ce44SJohn Forte  * For leadville specific HBA's ONLY.
939fcf3ce44SJohn Forte  * Get the host specific parameters,
940fcf3ce44SJohn Forte  * al_pa, hard address, node/port WWN etc.
941fcf3ce44SJohn Forte  *
942fcf3ce44SJohn Forte  * OUTPUT:
943fcf3ce44SJohn Forte  *	fc_port_dev_t structure.
944fcf3ce44SJohn Forte  *
945fcf3ce44SJohn Forte  * RETURNS:
946fcf3ce44SJohn Forte  *	0	if  OK
947fcf3ce44SJohn Forte  *	non-zero in case of error.
948fcf3ce44SJohn Forte  */
949fcf3ce44SJohn Forte int
g_get_host_params(char * host_path,fc_port_dev_t * host_val,int verbose)950fcf3ce44SJohn Forte g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose)
951fcf3ce44SJohn Forte {
952063d642aSBill Gumbrell 	int		err;
953063d642aSBill Gumbrell 	int		fd;
954063d642aSBill Gumbrell 	int		dev_type;
955063d642aSBill Gumbrell 	fcio_t		fcio;
956fcf3ce44SJohn Forte 
957fcf3ce44SJohn Forte 	/* return invalid path if host_path is NULL */
958fcf3ce44SJohn Forte 	if (host_path == NULL) {
959fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
960fcf3ce44SJohn Forte 	}
961fcf3ce44SJohn Forte 	/* return invalid arg if host_val is NULL */
962fcf3ce44SJohn Forte 	if (host_val == NULL) {
963fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
964fcf3ce44SJohn Forte 	}
965fcf3ce44SJohn Forte 
966fcf3ce44SJohn Forte 	dev_type = g_get_path_type(host_path);
967fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
968fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
969fcf3ce44SJohn Forte 	}
970fcf3ce44SJohn Forte 	if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) {
971fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
972fcf3ce44SJohn Forte 	}
973fcf3ce44SJohn Forte 
974fcf3ce44SJohn Forte 	/* initialize structure */
975fcf3ce44SJohn Forte 	(void) memset(host_val, 0, sizeof (struct fc_port_dev));
976fcf3ce44SJohn Forte 
977fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
978fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
979fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)host_val;
980fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (fc_port_dev_t);
981fcf3ce44SJohn Forte 
982fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
983fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
984fcf3ce44SJohn Forte 		(void) close(fd);
985fcf3ce44SJohn Forte 		return (L_FCIO_GET_HOST_PARAMS_FAIL);
986fcf3ce44SJohn Forte 	}
987fcf3ce44SJohn Forte 	(void) close(fd);
988fcf3ce44SJohn Forte 
989fcf3ce44SJohn Forte 	/* get the inquiry information for the leadville HBA. */
990fcf3ce44SJohn Forte 	if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn,
991063d642aSBill Gumbrell 	    &host_val->dev_dtype)) != 0) {
992fcf3ce44SJohn Forte 		return (err);
993fcf3ce44SJohn Forte 	}
994fcf3ce44SJohn Forte 	return (0);
995fcf3ce44SJohn Forte }
996fcf3ce44SJohn Forte 
997fcf3ce44SJohn Forte 
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte /*
1000fcf3ce44SJohn Forte  * Issue FCIO ioctls to the port(fp) driver.
1001fcf3ce44SJohn Forte  * FCIO ioctl needs to be retried when it
1002fcf3ce44SJohn Forte  * is returned with an EINVAL error, wait
1003fcf3ce44SJohn Forte  * time between retries should be atleast
1004fcf3ce44SJohn Forte  * WAIT_FCIO_IOCTL (too much of a time to wait!!)
1005fcf3ce44SJohn Forte  *
1006fcf3ce44SJohn Forte  * OUTPUT:
1007fcf3ce44SJohn Forte  *	fcio_t structure
1008fcf3ce44SJohn Forte  *
1009fcf3ce44SJohn Forte  * RETURNS:
1010fcf3ce44SJohn Forte  *	0	 if O.K.
1011fcf3ce44SJohn Forte  *	non-zero otherwise.
1012fcf3ce44SJohn Forte  */
1013fcf3ce44SJohn Forte int
g_issue_fcio_ioctl(int fd,fcio_t * fcio,int verbose)1014fcf3ce44SJohn Forte g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose)
1015fcf3ce44SJohn Forte {
1016063d642aSBill Gumbrell 	int	ntries;
1017fcf3ce44SJohn Forte 
1018fcf3ce44SJohn Forte 	for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
1019fcf3ce44SJohn Forte 		if (ioctl(fd, FCIO_CMD, fcio) != 0) {
1020fcf3ce44SJohn Forte 			if ((errno == EAGAIN) &&
1021063d642aSBill Gumbrell 			    (ntries+1 < RETRY_FCIO_IOCTL)) {
1022fcf3ce44SJohn Forte 				/* wait WAIT_FCIO_IOCTL */
1023fcf3ce44SJohn Forte 				(void) usleep(WAIT_FCIO_IOCTL);
1024fcf3ce44SJohn Forte 				continue;
1025fcf3ce44SJohn Forte 			}
1026fcf3ce44SJohn Forte 			I_DPRINTF("FCIO ioctl failed.\n"
1027063d642aSBill Gumbrell 			    "Error: %s. fc_error = %d (0x%x)\n",
1028063d642aSBill Gumbrell 			    strerror(errno), fcio->fcio_errno,
1029063d642aSBill Gumbrell 			    fcio->fcio_errno);
1030fcf3ce44SJohn Forte 			if (errno == EINVAL) {
1031fcf3ce44SJohn Forte 				if (fcio->fcio_errno == FC_TOOMANY) {
1032fcf3ce44SJohn Forte 					return (L_INVALID_DEVICE_COUNT);
1033fcf3ce44SJohn Forte 				} else {
1034fcf3ce44SJohn Forte 					return (errno);
1035fcf3ce44SJohn Forte 				}
1036fcf3ce44SJohn Forte 			}
1037fcf3ce44SJohn Forte 			/*
1038fcf3ce44SJohn Forte 			 * When port is offlined, qlc
1039fcf3ce44SJohn Forte 			 * returns the FC_OFFLINE error and errno
1040fcf3ce44SJohn Forte 			 * is set to EIO.
1041fcf3ce44SJohn Forte 			 * We do want to ignore this error,
1042fcf3ce44SJohn Forte 			 * especially when an enclosure is
1043fcf3ce44SJohn Forte 			 * removed from the loop.
1044fcf3ce44SJohn Forte 			 */
1045fcf3ce44SJohn Forte 			if (fcio->fcio_errno == FC_OFFLINE)
1046fcf3ce44SJohn Forte 				break;
1047fcf3ce44SJohn Forte 			return (-1);
1048fcf3ce44SJohn Forte 		}
1049fcf3ce44SJohn Forte 		break;
1050fcf3ce44SJohn Forte 	}
1051fcf3ce44SJohn Forte 
1052fcf3ce44SJohn Forte 	return (0);
1053fcf3ce44SJohn Forte }
1054fcf3ce44SJohn Forte 
1055fcf3ce44SJohn Forte /*
1056fcf3ce44SJohn Forte  * This function issues the FCP_TGT_INQUIRY ioctl to
1057fcf3ce44SJohn Forte  * the fcp module
1058fcf3ce44SJohn Forte  *
1059fcf3ce44SJohn Forte  * OUTPUT:
1060fcf3ce44SJohn Forte  *	fcp_ioctl structure in fcp_data is filled in by fcp
1061fcf3ce44SJohn Forte  *
1062fcf3ce44SJohn Forte  * RETURN VALUES :
1063fcf3ce44SJohn Forte  *	0 on Success
1064fcf3ce44SJohn Forte  *	Non-zero otherwise
1065fcf3ce44SJohn Forte  */
1066fcf3ce44SJohn Forte static int
g_issue_fcp_ioctl(int fd,struct fcp_ioctl * fcp_data,int verbose)1067fcf3ce44SJohn Forte g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose)
1068fcf3ce44SJohn Forte {
1069*926d645fSToomas Soome 	int			num_tries = 0;
1070fcf3ce44SJohn Forte 	struct device_data	*dev_data = NULL;
1071fcf3ce44SJohn Forte 
1072fcf3ce44SJohn Forte 	/*
1073fcf3ce44SJohn Forte 	 * Issue the ioctl to FCP
1074fcf3ce44SJohn Forte 	 * The retries are required because the driver may
1075fcf3ce44SJohn Forte 	 * need some time to respond at times.
1076fcf3ce44SJohn Forte 	 */
1077fcf3ce44SJohn Forte 	while (num_tries++ < RETRY_FCP_IOCTL) {
1078fcf3ce44SJohn Forte 		/* if ioctl fails it is an error from Solaris operation. */
1079fcf3ce44SJohn Forte 		if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) {
1080fcf3ce44SJohn Forte 			if (errno == EAGAIN) {
1081fcf3ce44SJohn Forte 				(void) usleep(WAIT_FCP_IOCTL);
1082fcf3ce44SJohn Forte 				continue;
1083fcf3ce44SJohn Forte 			} else {
1084fcf3ce44SJohn Forte 				break;
1085fcf3ce44SJohn Forte 			}
1086fcf3ce44SJohn Forte 		}
1087fcf3ce44SJohn Forte 		dev_data = (struct device_data *)((void *)(fcp_data->list));
1088fcf3ce44SJohn Forte 		if (dev_data->dev_status == 0) {
1089fcf3ce44SJohn Forte 			return (0);
1090fcf3ce44SJohn Forte 		}
1091fcf3ce44SJohn Forte 
1092fcf3ce44SJohn Forte 		if (dev_data->dev_status == EAGAIN) {
1093fcf3ce44SJohn Forte 			(void) usleep(WAIT_FCP_IOCTL);
1094fcf3ce44SJohn Forte 			continue;
1095fcf3ce44SJohn Forte 		} else {
1096fcf3ce44SJohn Forte 			dev_data->dev0_type = DTYPE_UNKNOWN;
1097fcf3ce44SJohn Forte 			return (0);
1098fcf3ce44SJohn Forte 		}
1099fcf3ce44SJohn Forte 	}
1100fcf3ce44SJohn Forte 
1101fcf3ce44SJohn Forte 	return (L_FCP_TGT_INQUIRY_FAIL);
1102fcf3ce44SJohn Forte }
1103fcf3ce44SJohn Forte 
1104fcf3ce44SJohn Forte /*
1105fcf3ce44SJohn Forte  * Get the number of devices and also
1106fcf3ce44SJohn Forte  * a list of devices accessible through
1107fcf3ce44SJohn Forte  * the device's port as specified by path.
1108fcf3ce44SJohn Forte  * The calling function * is responsible for freeing the dev_list.
1109fcf3ce44SJohn Forte  *
1110fcf3ce44SJohn Forte  * Acquires inq_dtype from g_get_inq_dtype() and
1111fcf3ce44SJohn Forte  * stores into dev_dtype field of fc_port_dev.
1112fcf3ce44SJohn Forte  *
1113fcf3ce44SJohn Forte  * For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login
1114fcf3ce44SJohn Forte  * and get inq dtype.
1115fcf3ce44SJohn Forte  *
1116fcf3ce44SJohn Forte  * dev_list:
1117fcf3ce44SJohn Forte  *	NULL:	  No devices found, in case of an error
1118fcf3ce44SJohn Forte  *	Non-NULL: Devices found.
1119fcf3ce44SJohn Forte  * ndevs:
1120fcf3ce44SJohn Forte  *	set to the number of devices
1121fcf3ce44SJohn Forte  *	accessible through the port.
1122fcf3ce44SJohn Forte  *
1123fcf3ce44SJohn Forte  * RETURNS:
1124fcf3ce44SJohn Forte  *	0	 if O.K.
1125fcf3ce44SJohn Forte  *	non-zero otherwise
1126fcf3ce44SJohn Forte  */
1127fcf3ce44SJohn Forte int
g_get_dev_list(char * path,fc_port_dev_t ** dev_list,int * ndevs)1128fcf3ce44SJohn Forte g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs)
1129fcf3ce44SJohn Forte {
1130063d642aSBill Gumbrell 	int		num_devices = 0;
1131063d642aSBill Gumbrell 	int		i, err, ulp_failure = 0, new_count = 0;
1132063d642aSBill Gumbrell 	int		dev_type;
1133063d642aSBill Gumbrell 	int		fd;
1134063d642aSBill Gumbrell 	char		fcapath[MAXPATHLEN];
1135063d642aSBill Gumbrell 	char		*char_ptr;
1136063d642aSBill Gumbrell 	struct	stat	stbuf;
1137063d642aSBill Gumbrell 	fcio_t		fcio;
1138063d642aSBill Gumbrell 	uint32_t	port_top;
1139063d642aSBill Gumbrell 	fc_port_dev_t	*dlist;
1140fcf3ce44SJohn Forte 
1141fcf3ce44SJohn Forte 	*dev_list = dlist = NULL;
1142fcf3ce44SJohn Forte 	(void) strcpy(fcapath, path);
1143fcf3ce44SJohn Forte 	/*
1144fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
1145fcf3ce44SJohn Forte 	 *
1146fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
1147fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1148fcf3ce44SJohn Forte 	 * or
1149fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1150fcf3ce44SJohn Forte 	 * or
1151fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1152fcf3ce44SJohn Forte 	 * or
1153fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
1154fcf3ce44SJohn Forte 	 */
1155fcf3ce44SJohn Forte 	if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) {
1156fcf3ce44SJohn Forte 		if ((char_ptr = strrchr(fcapath, '/')) == NULL) {
1157fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
1158fcf3ce44SJohn Forte 		}
1159fcf3ce44SJohn Forte 		*char_ptr = '\0';   /* Terminate sting  */
1160fcf3ce44SJohn Forte 		/* append controller */
1161fcf3ce44SJohn Forte 		(void) strcat(fcapath, FC_CTLR);
1162fcf3ce44SJohn Forte 	} else {
1163fcf3ce44SJohn Forte 		if (stat(fcapath, &stbuf) < 0) {
1164fcf3ce44SJohn Forte 			return (L_LSTAT_ERROR);
1165fcf3ce44SJohn Forte 		}
1166fcf3ce44SJohn Forte 		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1167fcf3ce44SJohn Forte 			/* append controller */
1168fcf3ce44SJohn Forte 			(void) strcat(fcapath, FC_CTLR);
1169fcf3ce44SJohn Forte 		}
1170fcf3ce44SJohn Forte 	}
1171fcf3ce44SJohn Forte 	dev_type = g_get_path_type(fcapath);
1172fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1173fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1174fcf3ce44SJohn Forte 	}
1175fcf3ce44SJohn Forte 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1176fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1177fcf3ce44SJohn Forte 	}
1178fcf3ce44SJohn Forte 
1179fcf3ce44SJohn Forte 	/*
1180fcf3ce44SJohn Forte 	 * Get the device list from port driver
1181fcf3ce44SJohn Forte 	 */
1182fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
1183fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (num_devices);
1184fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
1185fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)&num_devices;
1186fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
1187fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
1188fcf3ce44SJohn Forte 		(void) close(fd);
1189fcf3ce44SJohn Forte 		return (L_FCIO_GET_NUM_DEVS_FAIL);
1190fcf3ce44SJohn Forte 	}
1191fcf3ce44SJohn Forte 	if (num_devices == 0) {
1192fcf3ce44SJohn Forte 		*ndevs = 0;
1193fcf3ce44SJohn Forte 		(void) close(fd);
1194fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
1195fcf3ce44SJohn Forte 	}
1196fcf3ce44SJohn Forte 
1197fcf3ce44SJohn Forte 	if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1198063d642aSBill Gumbrell 	    sizeof (fc_port_dev_t))) == NULL) {
1199fcf3ce44SJohn Forte 		(void) close(fd);
1200fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1201fcf3ce44SJohn Forte 	}
1202fcf3ce44SJohn Forte 	bzero((caddr_t)&fcio, sizeof (fcio));
1203fcf3ce44SJohn Forte 	/* Get the device list */
1204fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1205fcf3ce44SJohn Forte 	/* Information read operation */
1206fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
1207fcf3ce44SJohn Forte 	fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1208fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)dlist;
1209fcf3ce44SJohn Forte 	/* new device count */
1210fcf3ce44SJohn Forte 	fcio.fcio_alen = sizeof (new_count);
1211fcf3ce44SJohn Forte 	fcio.fcio_abuf = (caddr_t)&new_count;
1212fcf3ce44SJohn Forte 	if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1213063d642aSBill Gumbrell 		if (err == L_INVALID_DEVICE_COUNT) {
1214fcf3ce44SJohn Forte 			/*
1215063d642aSBill Gumbrell 			 * original buffer was small so allocate buffer
1216063d642aSBill Gumbrell 			 * with a new count and retry.
1217fcf3ce44SJohn Forte 			 */
1218063d642aSBill Gumbrell 			free(dlist);
1219063d642aSBill Gumbrell 			num_devices = new_count;
1220063d642aSBill Gumbrell 			new_count = 0;
1221063d642aSBill Gumbrell 			if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1222063d642aSBill Gumbrell 			    sizeof (fc_port_dev_t))) == NULL) {
1223063d642aSBill Gumbrell 				(void) close(fd);
1224063d642aSBill Gumbrell 				return (L_MALLOC_FAILED);
1225063d642aSBill Gumbrell 			}
1226063d642aSBill Gumbrell 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1227063d642aSBill Gumbrell 			/* Information read operation */
1228063d642aSBill Gumbrell 			fcio.fcio_xfer = FCIO_XFER_READ;
1229063d642aSBill Gumbrell 			fcio.fcio_obuf = (caddr_t)dlist;
1230063d642aSBill Gumbrell 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1231063d642aSBill Gumbrell 			/* new device count */
1232063d642aSBill Gumbrell 			fcio.fcio_alen = sizeof (new_count);
1233063d642aSBill Gumbrell 			fcio.fcio_abuf = (caddr_t)&new_count;
1234063d642aSBill Gumbrell 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1235063d642aSBill Gumbrell 				if (err == L_INVALID_DEVICE_COUNT) {
1236063d642aSBill Gumbrell 					/*
1237063d642aSBill Gumbrell 					 * No more retry. There may be severe
1238063d642aSBill Gumbrell 					 * hardware problem so return error
1239063d642aSBill Gumbrell 					 * here.
1240063d642aSBill Gumbrell 					 */
1241063d642aSBill Gumbrell 					I_DPRINTF(" Device count was %d"
1242063d642aSBill Gumbrell 					    " should have been %d\n",
1243063d642aSBill Gumbrell 					    num_devices, new_count);
1244063d642aSBill Gumbrell 				} else {
1245063d642aSBill Gumbrell 					I_DPRINTF(
1246063d642aSBill Gumbrell 					    " FCIO_GET_DEV_LIST ioctl failed.");
1247063d642aSBill Gumbrell 					err = L_FCIO_GET_DEV_LIST_FAIL;
1248063d642aSBill Gumbrell 				}
1249063d642aSBill Gumbrell 				free(dlist);
1250063d642aSBill Gumbrell 				(void) close(fd);
1251063d642aSBill Gumbrell 				return (err);
1252063d642aSBill Gumbrell 			}
1253063d642aSBill Gumbrell 		} else {
1254fcf3ce44SJohn Forte 			I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
1255063d642aSBill Gumbrell 			free(dlist);
1256063d642aSBill Gumbrell 			(void) close(fd);
1257063d642aSBill Gumbrell 			return (L_FCIO_GET_DEV_LIST_FAIL);
1258063d642aSBill Gumbrell 		}
1259fcf3ce44SJohn Forte 	}
1260fcf3ce44SJohn Forte 
1261fcf3ce44SJohn Forte 	/*
1262fcf3ce44SJohn Forte 	 * if new count is smaller than the original number from
1263fcf3ce44SJohn Forte 	 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
1264fcf3ce44SJohn Forte 	 * and continue.
1265fcf3ce44SJohn Forte 	 */
1266fcf3ce44SJohn Forte 	if (new_count < num_devices) {
1267fcf3ce44SJohn Forte 		if (new_count == 0) {
1268fcf3ce44SJohn Forte 			*ndevs = 0;
1269fcf3ce44SJohn Forte 			(void) close(fd);
1270fcf3ce44SJohn Forte 			S_FREE(dlist);
1271fcf3ce44SJohn Forte 			return (L_NO_DEVICES_FOUND);
1272fcf3ce44SJohn Forte 		}
1273fcf3ce44SJohn Forte 		num_devices = new_count;
1274fcf3ce44SJohn Forte 		if ((dlist = (fc_port_dev_t *)realloc(dlist,
1275063d642aSBill Gumbrell 		    (new_count * sizeof (fc_port_dev_t))))
1276063d642aSBill Gumbrell 		    == NULL) {
1277fcf3ce44SJohn Forte 			S_FREE(dlist);
1278fcf3ce44SJohn Forte 			(void) close(fd);
1279fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
1280fcf3ce44SJohn Forte 		}
1281fcf3ce44SJohn Forte 	}
1282fcf3ce44SJohn Forte 
1283fcf3ce44SJohn Forte 	*dev_list = dlist;
1284fcf3ce44SJohn Forte 	*ndevs = num_devices;
1285fcf3ce44SJohn Forte 
1286fcf3ce44SJohn Forte 	/* close here since fcapath will be passed to other routines. */
1287fcf3ce44SJohn Forte 	(void) close(fd);
1288fcf3ce44SJohn Forte 
1289fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1290fcf3ce44SJohn Forte 		free(*dev_list);
1291fcf3ce44SJohn Forte 		*dev_list = NULL;
1292fcf3ce44SJohn Forte 		return (err);
1293fcf3ce44SJohn Forte 	}
1294fcf3ce44SJohn Forte 
1295fcf3ce44SJohn Forte 	/* Get the inq_dtype for each device on dev list. */
1296fcf3ce44SJohn Forte 	for (i = 0; i < num_devices; i++, dlist++) {
1297fcf3ce44SJohn Forte 		/* Get the inq_dtype for each device. */
1298fcf3ce44SJohn Forte 		if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn,
1299063d642aSBill Gumbrell 		    &dlist->dev_dtype)) != 0) {
1300fcf3ce44SJohn Forte 			/*
1301fcf3ce44SJohn Forte 			 * if g_get_inq_dtype failed on g_dev_login
1302fcf3ce44SJohn Forte 			 * or g_issue_fcp_ioctl, continue to the next
1303fcf3ce44SJohn Forte 			 * dev on dlist.
1304fcf3ce44SJohn Forte 			 * L_GET_DEV_LIST_ULP_FAILURE is returned
1305fcf3ce44SJohn Forte 			 * after processing the whole dlist.
1306fcf3ce44SJohn Forte 			 */
1307fcf3ce44SJohn Forte 			if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
1308063d642aSBill Gumbrell 			    (err == L_FCP_TGT_INQUIRY_FAIL)) {
1309fcf3ce44SJohn Forte 				ulp_failure = 1;
1310fcf3ce44SJohn Forte 				dlist->dev_dtype = GFC_ERR_INQ_DTYPE;
1311fcf3ce44SJohn Forte 			} else {
1312fcf3ce44SJohn Forte 				(void) free(*dev_list);
1313fcf3ce44SJohn Forte 				*dev_list = NULL;
1314fcf3ce44SJohn Forte 				return (err);
1315fcf3ce44SJohn Forte 			}
1316fcf3ce44SJohn Forte 		}
1317fcf3ce44SJohn Forte 	}
1318fcf3ce44SJohn Forte 
1319fcf3ce44SJohn Forte 	if (ulp_failure) {
1320fcf3ce44SJohn Forte 		return (L_GET_DEV_LIST_ULP_FAILURE);
1321fcf3ce44SJohn Forte 	} else {
1322fcf3ce44SJohn Forte 		return (0);
1323fcf3ce44SJohn Forte 	}
1324fcf3ce44SJohn Forte }
1325fcf3ce44SJohn Forte 
1326fcf3ce44SJohn Forte 
1327fcf3ce44SJohn Forte /* Constant used by g_get_inq_dtype() */
1328fcf3ce44SJohn Forte #define	FCP_PATH	"/devices/pseudo/fcp@0:fcp"
1329fcf3ce44SJohn Forte 
1330fcf3ce44SJohn Forte /*
1331fcf3ce44SJohn Forte  * Gets the inq_dtype for devices on the fabric FC driver
1332fcf3ce44SJohn Forte  * through an ioctl to the FCP module.
1333fcf3ce44SJohn Forte  *
1334fcf3ce44SJohn Forte  * OUTPUT:
1335fcf3ce44SJohn Forte  *	inq_dtype is set to the dtype on success
1336fcf3ce44SJohn Forte  *
1337fcf3ce44SJohn Forte  * RETURN VALUES:
1338fcf3ce44SJohn Forte  *	0 on Success
1339fcf3ce44SJohn Forte  *	Non-zero on error
1340fcf3ce44SJohn Forte  */
1341fcf3ce44SJohn Forte int
g_get_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)1342fcf3ce44SJohn Forte g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1343fcf3ce44SJohn Forte {
1344fcf3ce44SJohn Forte 	int			dev_type, fd;
1345fcf3ce44SJohn Forte 	int			err, fcp_fd;
1346fcf3ce44SJohn Forte 	uint32_t		state;
1347fcf3ce44SJohn Forte 	uint32_t		port_top = 0;
1348fcf3ce44SJohn Forte 	struct fcp_ioctl	fcp_data;
1349fcf3ce44SJohn Forte 	struct device_data	inq_data;
1350fcf3ce44SJohn Forte 	struct stat		sbuf;
1351fcf3ce44SJohn Forte 
1352fcf3ce44SJohn Forte 	dev_type = g_get_path_type(fcapath);
1353fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1354fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1355fcf3ce44SJohn Forte 	}
1356fcf3ce44SJohn Forte 
1357fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1358fcf3ce44SJohn Forte 		return (err);
1359fcf3ce44SJohn Forte 	}
1360fcf3ce44SJohn Forte 
1361fcf3ce44SJohn Forte 	if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) {
1362fcf3ce44SJohn Forte 		/*
1363fcf3ce44SJohn Forte 		 * if there is an error on getting port state we will
1364fcf3ce44SJohn Forte 		 * continue to login.
1365fcf3ce44SJohn Forte 		 * state can be either of
1366fcf3ce44SJohn Forte 		 * PORT_DEVICE_INVALID, PORT_DEVICE_VALID,
1367fcf3ce44SJohn Forte 		 * PORT_DEVICE_LOGGED_IN.  Trying port login
1368fcf3ce44SJohn Forte 		 * unless already logged in.
1369fcf3ce44SJohn Forte 		 * It will be examined if there is an adverse
1370fcf3ce44SJohn Forte 		 * effect on invalid state device.
1371fcf3ce44SJohn Forte 		 */
1372fcf3ce44SJohn Forte 		if (((err = g_get_dev_port_state(fcapath, pwwn, &state))
1373063d642aSBill Gumbrell 		    != 0) || (state != PORT_DEVICE_LOGGED_IN)) {
1374fcf3ce44SJohn Forte 			/* do port login to fabric device.  */
1375fcf3ce44SJohn Forte 			if ((err = g_dev_login(fcapath, pwwn)) != 0) {
1376fcf3ce44SJohn Forte 				return (err);
1377fcf3ce44SJohn Forte 			}
1378fcf3ce44SJohn Forte 		}
1379fcf3ce44SJohn Forte 	}
1380fcf3ce44SJohn Forte 
1381fcf3ce44SJohn Forte 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1)
1382fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1383fcf3ce44SJohn Forte 
1384fcf3ce44SJohn Forte 	if (fstat(fd, &sbuf) == -1) {
1385fcf3ce44SJohn Forte 		(void) close(fd);
1386fcf3ce44SJohn Forte 		return (L_FSTAT_ERROR);
1387fcf3ce44SJohn Forte 	}
1388fcf3ce44SJohn Forte 
1389fcf3ce44SJohn Forte 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1390fcf3ce44SJohn Forte 		(void) close(fd);
1391fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1392fcf3ce44SJohn Forte 	}
1393fcf3ce44SJohn Forte 
1394fcf3ce44SJohn Forte 	/* Get the minor number for an fp instance */
1395fcf3ce44SJohn Forte 	fcp_data.fp_minor = minor(sbuf.st_rdev);
1396fcf3ce44SJohn Forte 
1397fcf3ce44SJohn Forte 	fcp_data.listlen = 1;
1398fcf3ce44SJohn Forte 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
1399fcf3ce44SJohn Forte 	fcp_data.list = (caddr_t)&inq_data;
1400fcf3ce44SJohn Forte 
1401fcf3ce44SJohn Forte 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1402fcf3ce44SJohn Forte 		close(fd);
1403fcf3ce44SJohn Forte 		close(fcp_fd);
1404fcf3ce44SJohn Forte 		return (err);
1405fcf3ce44SJohn Forte 	}
1406fcf3ce44SJohn Forte 	*inq_dtype = inq_data.dev0_type;
1407fcf3ce44SJohn Forte 
1408fcf3ce44SJohn Forte 	close(fd);
1409fcf3ce44SJohn Forte 	close(fcp_fd);
1410fcf3ce44SJohn Forte 
1411fcf3ce44SJohn Forte 	return (err);
1412fcf3ce44SJohn Forte }
1413fcf3ce44SJohn Forte 
1414fcf3ce44SJohn Forte /*
1415fcf3ce44SJohn Forte  * Gets the inq_dtype for devices on the fabric FC driver
1416fcf3ce44SJohn Forte  * through an ioctl to the FCP module.
1417fcf3ce44SJohn Forte  *
1418fcf3ce44SJohn Forte  * This is exactly same as g_get_inq_dtype except that it does not do
1419fcf3ce44SJohn Forte  * g_dev_login(). That is for the case when the FCA tries to get its own
1420fcf3ce44SJohn Forte  * inq_dtype and in such a case, it cannot PLOGI into itself.
1421fcf3ce44SJohn Forte  *
1422fcf3ce44SJohn Forte  * OUTPUT:
1423fcf3ce44SJohn Forte  *	inq_dtype is set to the dtype on success
1424fcf3ce44SJohn Forte  *
1425fcf3ce44SJohn Forte  * RETURN VALUES:
1426fcf3ce44SJohn Forte  *	0 on Success
1427fcf3ce44SJohn Forte  *	Non-zero on error
1428fcf3ce44SJohn Forte  */
1429fcf3ce44SJohn Forte static int
get_fca_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)1430fcf3ce44SJohn Forte get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1431fcf3ce44SJohn Forte {
1432fcf3ce44SJohn Forte 	int			dev_type, fd;
1433fcf3ce44SJohn Forte 	int			err, fcp_fd;
1434fcf3ce44SJohn Forte 	struct fcp_ioctl	fcp_data;
1435fcf3ce44SJohn Forte 	struct device_data	inq_data;
1436fcf3ce44SJohn Forte 	struct stat		sbuf;
1437fcf3ce44SJohn Forte 
1438fcf3ce44SJohn Forte 	dev_type = g_get_path_type(fcapath);
1439fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1440fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1441fcf3ce44SJohn Forte 	}
1442fcf3ce44SJohn Forte 
1443fcf3ce44SJohn Forte 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1444fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1445fcf3ce44SJohn Forte 	}
1446fcf3ce44SJohn Forte 
1447fcf3ce44SJohn Forte 	if (fstat(fd, &sbuf) == -1) {
1448fcf3ce44SJohn Forte 		(void) close(fd);
1449fcf3ce44SJohn Forte 		return (L_FSTAT_ERROR);
1450fcf3ce44SJohn Forte 	}
1451fcf3ce44SJohn Forte 
1452fcf3ce44SJohn Forte 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1453fcf3ce44SJohn Forte 		(void) close(fd);
1454fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
1455fcf3ce44SJohn Forte 	}
1456fcf3ce44SJohn Forte 
1457fcf3ce44SJohn Forte 	/* Get the minor number for an fp instance */
1458fcf3ce44SJohn Forte 	fcp_data.fp_minor = minor(sbuf.st_rdev);
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte 	fcp_data.listlen = 1;
1461fcf3ce44SJohn Forte 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
1462fcf3ce44SJohn Forte 	fcp_data.list = (caddr_t)&inq_data;
1463fcf3ce44SJohn Forte 
1464fcf3ce44SJohn Forte 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1465fcf3ce44SJohn Forte 		close(fd);
1466fcf3ce44SJohn Forte 		close(fcp_fd);
1467fcf3ce44SJohn Forte 		return (err);
1468fcf3ce44SJohn Forte 	}
1469fcf3ce44SJohn Forte 	*inq_dtype = inq_data.dev0_type;
1470fcf3ce44SJohn Forte 
1471fcf3ce44SJohn Forte 	close(fd);
1472fcf3ce44SJohn Forte 	close(fcp_fd);
1473fcf3ce44SJohn Forte 
1474fcf3ce44SJohn Forte 	return (0);
1475fcf3ce44SJohn Forte }
1476fcf3ce44SJohn Forte 
1477fcf3ce44SJohn Forte /*
1478fcf3ce44SJohn Forte  * This function returns the traditional g_get_dev_map. Device list
1479fcf3ce44SJohn Forte  * and local hba seperate.
1480fcf3ce44SJohn Forte  */
1481fcf3ce44SJohn Forte int
g_get_dev_map(char * path,gfc_map_t * map_ptr,int verbose)1482fcf3ce44SJohn Forte g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose)
1483fcf3ce44SJohn Forte {
1484fcf3ce44SJohn Forte 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD));
1485fcf3ce44SJohn Forte }
1486fcf3ce44SJohn Forte 
1487fcf3ce44SJohn Forte /*
1488fcf3ce44SJohn Forte  * This function returns the device map with local hba in physical
1489fcf3ce44SJohn Forte  * order.  Note: Physical order is only returned properly for
1490fcf3ce44SJohn Forte  * private loop. local hba is also included seperate
1491fcf3ce44SJohn Forte  */
1492fcf3ce44SJohn Forte int
g_get_lilp_map(char * path,gfc_map_t * map_ptr,int verbose)1493fcf3ce44SJohn Forte g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose)
1494fcf3ce44SJohn Forte {
1495fcf3ce44SJohn Forte 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP));
1496fcf3ce44SJohn Forte }
1497fcf3ce44SJohn Forte 
1498fcf3ce44SJohn Forte /*
1499fcf3ce44SJohn Forte  * Gets device map from nexus driver
1500fcf3ce44SJohn Forte  *
1501fcf3ce44SJohn Forte  * PARAMS:
1502fcf3ce44SJohn Forte  *	path -	must be the physical path to a device
1503fcf3ce44SJohn Forte  *	map  -	loop map returned from fc port.
1504fcf3ce44SJohn Forte  *	verbose - options.
1505fcf3ce44SJohn Forte  *
1506fcf3ce44SJohn Forte  * LOGIC:
1507fcf3ce44SJohn Forte  *	1. check the validity of path via g_get_path_type.
1508fcf3ce44SJohn Forte  *	2. If FC path, get the topology of the path via
1509fcf3ce44SJohn Forte  *		g_get_fca_port_topology.
1510fcf3ce44SJohn Forte  *
1511fcf3ce44SJohn Forte  *	3. If FC type(Leadville statck)
1512fcf3ce44SJohn Forte  *		g_get_dev_list to get the device node list of fc_port_dev_t.
1513fcf3ce44SJohn Forte  *		g_get_host_params to get the fca port node of fc_port_dev_t.
1514fcf3ce44SJohn Forte  *
1515fcf3ce44SJohn Forte  *		Case of fabric or public loop topology
1516fcf3ce44SJohn Forte  *			Check if the port id > 0xffff.
1517fcf3ce44SJohn Forte  *			Move device node and fca port node to
1518fcf3ce44SJohn Forte  *			gfc_map structure via gfc_port_dev_info_t
1519fcf3ce44SJohn Forte  *			pub_port union.
1520fcf3ce44SJohn Forte  *			Issue g_get_inq_dtype to get FCP inquiry data
1521fcf3ce44SJohn Forte  *			and store it into gfc_port_dev_info_t.
1522fcf3ce44SJohn Forte  *
1523fcf3ce44SJohn Forte  *		Case of private loop topology
1524fcf3ce44SJohn Forte  *			Check if the port id < 0xff.
1525fcf3ce44SJohn Forte  *			Move device node and fca port node to
1526fcf3ce44SJohn Forte  *			gfc_map structure via gfc_port_dev_info_t
1527fcf3ce44SJohn Forte  *			priv_port union.
1528fcf3ce44SJohn Forte  *			Issue g_get_inq_dtype to get FCP inquiry data
1529fcf3ce44SJohn Forte  *			and store it into gfc_port_dev_info_t.
1530fcf3ce44SJohn Forte  *
1531fcf3ce44SJohn Forte  *	   else FC4 type(socal/sf or ifp stack)
1532fcf3ce44SJohn Forte  *		SFIOCGMAP ioctl to get the device and hba nodes of
1533fcf3ce44SJohn Forte  *			sf_addr_pair_t.
1534fcf3ce44SJohn Forte  *
1535fcf3ce44SJohn Forte  *
1536fcf3ce44SJohn Forte  * RETURNS:
1537fcf3ce44SJohn Forte  *	0	: if OK
1538fcf3ce44SJohn Forte  *	non-zero: otherwise
1539fcf3ce44SJohn Forte  */
1540fcf3ce44SJohn Forte int
create_map(char * path,gfc_map_t * map_ptr,int verbose,int map_type)1541fcf3ce44SJohn Forte create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type)
1542fcf3ce44SJohn Forte {
1543063d642aSBill Gumbrell 	int		fd, i, j, num_devices = 0, err, pathcnt = 1;
1544063d642aSBill Gumbrell 	char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
1545063d642aSBill Gumbrell 	char		*char_ptr;
1546063d642aSBill Gumbrell 	struct stat	stbuf;
1547063d642aSBill Gumbrell 	fc_port_dev_t	*dev_list, *dlistptr;
1548063d642aSBill Gumbrell 	uint32_t	hba_port_top = 0;
1549063d642aSBill Gumbrell 	uint_t		dev_type;
1550063d642aSBill Gumbrell 	sf_al_map_t	sf_map;
1551063d642aSBill Gumbrell 	gfc_port_dev_info_t	*dev_ptr;
1552063d642aSBill Gumbrell 	fc_port_dev_t	fp_hba_port;
1553063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
1554063d642aSBill Gumbrell 	int		p_on = 0, p_st = 0;
1555fcf3ce44SJohn Forte 
1556fcf3ce44SJohn Forte 	/* return invalid path if path is NULL */
1557fcf3ce44SJohn Forte 	if (path == NULL) {
1558fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
1559fcf3ce44SJohn Forte 	}
1560fcf3ce44SJohn Forte 	/* return invalid arg if map_ptr is NULL */
1561fcf3ce44SJohn Forte 	if (map_ptr == NULL) {
1562fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
1563fcf3ce44SJohn Forte 	}
1564fcf3ce44SJohn Forte 
1565fcf3ce44SJohn Forte 	map_ptr->dev_addr = NULL;
1566fcf3ce44SJohn Forte 	map_ptr->count = 0;
1567fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
1568fcf3ce44SJohn Forte 	/*
1569fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
1570fcf3ce44SJohn Forte 	 *
1571fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
1572fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1573fcf3ce44SJohn Forte 	 * or
1574fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1575fcf3ce44SJohn Forte 	 * or
1576fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1577fcf3ce44SJohn Forte 	 * or
1578fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
1579fcf3ce44SJohn Forte 	 */
1580fcf3ce44SJohn Forte 	if (strstr(path, SCSI_VHCI)) {
1581fcf3ce44SJohn Forte 		(void) strcpy(drvr_path0, path);
1582fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path0, &pathlist)) {
1583fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
1584fcf3ce44SJohn Forte 		}
1585fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
1586fcf3ce44SJohn Forte 		p_on = p_st = 0;
1587fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
1588fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
1589fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
1590063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_ONLINE) {
1591fcf3ce44SJohn Forte 					p_on = i;
1592fcf3ce44SJohn Forte 					break;
1593fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
1594063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_STANDBY) {
1595fcf3ce44SJohn Forte 					p_st = i;
1596fcf3ce44SJohn Forte 				}
1597fcf3ce44SJohn Forte 			}
1598fcf3ce44SJohn Forte 		}
1599fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
1600fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
1601fcf3ce44SJohn Forte 			/* on_line path */
1602fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
1603063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_hba);
1604fcf3ce44SJohn Forte 		} else {
1605fcf3ce44SJohn Forte 			/* standby or path0 */
1606fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
1607063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_hba);
1608fcf3ce44SJohn Forte 		}
1609fcf3ce44SJohn Forte 		free(pathlist.path_info);
1610fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
1611fcf3ce44SJohn Forte 	} else {
1612fcf3ce44SJohn Forte 		(void) strcpy(drvr_path, path);
1613fcf3ce44SJohn Forte 		if (strstr(drvr_path, DRV_NAME_SSD) ||
1614063d642aSBill Gumbrell 		    strstr(drvr_path, SES_NAME) ||
1615063d642aSBill Gumbrell 		    strstr(drvr_path, DRV_NAME_ST)) {
1616fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
1617fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
1618fcf3ce44SJohn Forte 			}
1619fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate sting  */
1620fcf3ce44SJohn Forte 			/* append controller */
1621fcf3ce44SJohn Forte 			(void) strcat(drvr_path, FC_CTLR);
1622fcf3ce44SJohn Forte 		} else {
1623fcf3ce44SJohn Forte 			if (stat(drvr_path, &stbuf) < 0) {
1624fcf3ce44SJohn Forte 				return (L_LSTAT_ERROR);
1625fcf3ce44SJohn Forte 			}
1626fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1627fcf3ce44SJohn Forte 				/* append controller */
1628fcf3ce44SJohn Forte 				(void) strcat(drvr_path, FC_CTLR);
1629fcf3ce44SJohn Forte 			}
1630fcf3ce44SJohn Forte 		}
1631fcf3ce44SJohn Forte 	}
1632fcf3ce44SJohn Forte 
1633fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_dev_map: Geting drive map from:"
1634063d642aSBill Gumbrell 	    " %s\n", drvr_path);
1635fcf3ce44SJohn Forte 
1636fcf3ce44SJohn Forte 	dev_type = g_get_path_type(drvr_path);
1637fcf3ce44SJohn Forte 	if ((dev_type == 0) || !(dev_type & XPORT_MASK)) {
1638fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
1639fcf3ce44SJohn Forte 	}
1640fcf3ce44SJohn Forte 
1641fcf3ce44SJohn Forte 	/* get fiber topology */
1642fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(drvr_path,
1643063d642aSBill Gumbrell 	    &hba_port_top, verbose)) != 0) {
1644fcf3ce44SJohn Forte 		return (err);
1645fcf3ce44SJohn Forte 	}
1646fcf3ce44SJohn Forte 
1647fcf3ce44SJohn Forte 	/* for FC devices. */
1648fcf3ce44SJohn Forte 	if (dev_type & FC_FCA_MASK) {
1649fcf3ce44SJohn Forte 		/*
1650fcf3ce44SJohn Forte 		 * if g_get_dev_list fails with L_NO_DEVICES_FOUND
1651fcf3ce44SJohn Forte 		 * we still want to call g_get_host_params to try to find the
1652fcf3ce44SJohn Forte 		 * HBA.  If we do not see any HBAs on the loop, the
1653fcf3ce44SJohn Forte 		 * g_get_host_params will fail when it trys to issue the target
1654fcf3ce44SJohn Forte 		 * inquiry ioctl.  In this case, we would still like to return
1655fcf3ce44SJohn Forte 		 * L_NO_DEVICES_FOUND.
1656fcf3ce44SJohn Forte 		 *
1657fcf3ce44SJohn Forte 		 * If g_get_dev_list fails with L_NO_DEVICES_FOUND and
1658fcf3ce44SJohn Forte 		 * g_get_host_params fails, the function returns
1659fcf3ce44SJohn Forte 		 * L_NO_DEVICES_FOUND
1660fcf3ce44SJohn Forte 		 */
1661fcf3ce44SJohn Forte 		if ((err = g_get_dev_list(drvr_path, &dev_list,
1662063d642aSBill Gumbrell 		    &num_devices)) != 0) {
1663fcf3ce44SJohn Forte 			/*
1664fcf3ce44SJohn Forte 			 * g_get_dev_map doesn't allow ulp failure
1665fcf3ce44SJohn Forte 			 * to continue thus we need to free dev_list
1666fcf3ce44SJohn Forte 			 * here.
1667fcf3ce44SJohn Forte 			 */
1668fcf3ce44SJohn Forte 			if (err == L_GET_DEV_LIST_ULP_FAILURE) {
1669fcf3ce44SJohn Forte 				(void) free(dev_list);
1670fcf3ce44SJohn Forte 			}
1671fcf3ce44SJohn Forte 			if (err != L_NO_DEVICES_FOUND) {
1672fcf3ce44SJohn Forte 				return (err);
1673fcf3ce44SJohn Forte 			}
1674fcf3ce44SJohn Forte 		}
1675fcf3ce44SJohn Forte 
1676fcf3ce44SJohn Forte 		/* Get local HBA information */
1677fcf3ce44SJohn Forte 		if ((err = g_get_host_params(drvr_path, &fp_hba_port,
1678063d642aSBill Gumbrell 		    verbose)) != 0) {
1679fcf3ce44SJohn Forte 			(void) free(dev_list);
1680fcf3ce44SJohn Forte 			if (num_devices == 0)
1681fcf3ce44SJohn Forte 				return (L_NO_DEVICES_FOUND);
1682fcf3ce44SJohn Forte 			else
1683fcf3ce44SJohn Forte 				return (err);
1684fcf3ce44SJohn Forte 		}
1685fcf3ce44SJohn Forte 
1686fcf3ce44SJohn Forte 		/* If devices, other than local HBA are found	*/
1687fcf3ce44SJohn Forte 		/* allocate space for them in the gfc_map.	*/
1688fcf3ce44SJohn Forte 		if (num_devices > 0) {
1689fcf3ce44SJohn Forte 
1690fcf3ce44SJohn Forte 			/* If map type is on MAP_FORMAT_LILP we need	*/
1691fcf3ce44SJohn Forte 			/* to add space for the local HBA		*/
1692fcf3ce44SJohn Forte 			if (map_type == MAP_FORMAT_LILP) {
1693fcf3ce44SJohn Forte 				map_ptr->count = ++num_devices;
1694fcf3ce44SJohn Forte 			} else {
1695fcf3ce44SJohn Forte 				map_ptr->count = num_devices;
1696fcf3ce44SJohn Forte 			}
1697fcf3ce44SJohn Forte 
1698fcf3ce44SJohn Forte 			if ((map_ptr->dev_addr = (gfc_port_dev_info_t *)
1699fcf3ce44SJohn Forte 			    calloc(map_ptr->count,
1700063d642aSBill Gumbrell 			    sizeof (gfc_port_dev_info_t))) == NULL) {
1701063d642aSBill Gumbrell 				(void) free(dev_list);
1702063d642aSBill Gumbrell 				return (L_MALLOC_FAILED);
1703fcf3ce44SJohn Forte 			}
1704fcf3ce44SJohn Forte 		}
1705fcf3ce44SJohn Forte 
1706fcf3ce44SJohn Forte 		/* If we want the lilp map then we need to do a little	*/
1707fcf3ce44SJohn Forte 		/* work here.  The lilp map contains the local hba in	*/
1708fcf3ce44SJohn Forte 		/* the dev_addr.  Once this has been added qsort the	*/
1709fcf3ce44SJohn Forte 		/* dev_addr array so it's in physical order.		*/
1710fcf3ce44SJohn Forte 		/* The lilp map will contain the local hba in the	*/
1711fcf3ce44SJohn Forte 		/* dev_addr array only when num_devices > 0		*/
1712fcf3ce44SJohn Forte 		if (map_type == MAP_FORMAT_LILP && num_devices > 0) {
1713fcf3ce44SJohn Forte 
1714fcf3ce44SJohn Forte 			/* First we need to allocate one additional	*/
1715*926d645fSToomas Soome 			/* device to the dev_addr structure, for the	*/
1716fcf3ce44SJohn Forte 			/* local hba					*/
1717fcf3ce44SJohn Forte 			if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
1718063d642aSBill Gumbrell 			    (num_devices * sizeof (fc_port_dev_t))))
1719063d642aSBill Gumbrell 			    == NULL) {
1720fcf3ce44SJohn Forte 				S_FREE(dev_list);
1721fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1722fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1723fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
1724fcf3ce44SJohn Forte 			}
1725fcf3ce44SJohn Forte 
1726fcf3ce44SJohn Forte 			/* Next, copy the local hba into this new loc.	*/
1727fcf3ce44SJohn Forte 			if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
1728063d642aSBill Gumbrell 			    sizeof (fc_port_dev_t)) == NULL) {
1729fcf3ce44SJohn Forte 				(void) free(dev_list);
1730fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1731fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1732fcf3ce44SJohn Forte 				return (L_MEMCPY_FAILED);
1733fcf3ce44SJohn Forte 			}
1734fcf3ce44SJohn Forte 
1735fcf3ce44SJohn Forte 			/* Now sort by physical location		*/
1736fcf3ce44SJohn Forte 			qsort((void*)dev_list, num_devices,
1737063d642aSBill Gumbrell 			    sizeof (fc_port_dev_t), lilp_map_cmp);
1738fcf3ce44SJohn Forte 		}
1739fcf3ce44SJohn Forte 
1740fcf3ce44SJohn Forte 		dlistptr = dev_list;
1741fcf3ce44SJohn Forte 		dev_ptr = map_ptr->dev_addr;
1742fcf3ce44SJohn Forte 
1743fcf3ce44SJohn Forte 		switch (hba_port_top) {
1744fcf3ce44SJohn Forte 		case FC_TOP_FABRIC:
1745fcf3ce44SJohn Forte 		case FC_TOP_PUBLIC_LOOP:
1746fcf3ce44SJohn Forte 			if (fp_hba_port.dev_did.port_id <= 0xffff) {
1747fcf3ce44SJohn Forte 				(void) free(dlistptr);
1748fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1749fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1750fcf3ce44SJohn Forte 				return (L_INVALID_FABRIC_ADDRESS);
1751fcf3ce44SJohn Forte 			} else {
1752fcf3ce44SJohn Forte 				map_ptr->hba_addr.port_topology = hba_port_top;
1753fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.pub_port =
1754063d642aSBill Gumbrell 				    fp_hba_port;
1755fcf3ce44SJohn Forte 			}
1756fcf3ce44SJohn Forte 			for (i = 0; i < num_devices; i++, dev_ptr++,
1757063d642aSBill Gumbrell 			    dev_list++) {
1758fcf3ce44SJohn Forte 				if (dev_list->dev_did.port_id <= 0xffff) {
1759fcf3ce44SJohn Forte 					(void) free(dlistptr);
1760fcf3ce44SJohn Forte 					(void) free(map_ptr->dev_addr);
1761fcf3ce44SJohn Forte 					map_ptr->dev_addr = NULL;
1762fcf3ce44SJohn Forte 					return (L_INVALID_FABRIC_ADDRESS);
1763fcf3ce44SJohn Forte 				} else {
1764fcf3ce44SJohn Forte 					dev_ptr->port_topology = hba_port_top;
1765fcf3ce44SJohn Forte 					dev_ptr->gfc_port_dev.pub_port =
1766063d642aSBill Gumbrell 					    *dev_list;
1767fcf3ce44SJohn Forte 				}
1768fcf3ce44SJohn Forte 			}
1769fcf3ce44SJohn Forte 			break;
1770fcf3ce44SJohn Forte 		case FC_TOP_PRIVATE_LOOP:
1771fcf3ce44SJohn Forte 			/*
1772fcf3ce44SJohn Forte 			 * Map the (new->old) structures here.
1773fcf3ce44SJohn Forte 			 * Checking (i < SF_NUM_ENTRIES_IN_MAP) just to
1774fcf3ce44SJohn Forte 			 * make sure that we don't overrun the map structure
1775fcf3ce44SJohn Forte 			 * since it can hold data for upto 126 devices.
1776fcf3ce44SJohn Forte 			 */
1777fcf3ce44SJohn Forte 			if (fp_hba_port.dev_did.port_id > 0xff) {
1778fcf3ce44SJohn Forte 				(void) free(dlistptr);
1779fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1780fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1781fcf3ce44SJohn Forte 				return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1782fcf3ce44SJohn Forte 			} else {
1783fcf3ce44SJohn Forte 				map_ptr->hba_addr.port_topology = hba_port_top;
1784fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.
1785063d642aSBill Gumbrell 				    priv_port.sf_al_pa =
1786063d642aSBill Gumbrell 				    (uchar_t)fp_hba_port.dev_did.port_id;
1787fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.
1788063d642aSBill Gumbrell 				    priv_port.sf_hard_address = (uchar_t)
1789063d642aSBill Gumbrell 				    fp_hba_port.dev_hard_addr.hard_addr;
1790fcf3ce44SJohn Forte 				for (j = 0; j < FC_WWN_SIZE; j++) {
1791fcf3ce44SJohn Forte 					map_ptr->hba_addr.gfc_port_dev.
1792063d642aSBill Gumbrell 					    priv_port.sf_node_wwn[j] =
1793063d642aSBill Gumbrell 					    fp_hba_port.dev_nwwn.raw_wwn[j];
1794fcf3ce44SJohn Forte 					map_ptr->hba_addr.gfc_port_dev.
1795063d642aSBill Gumbrell 					    priv_port.sf_port_wwn[j] =
1796063d642aSBill Gumbrell 					    fp_hba_port.dev_pwwn.raw_wwn[j];
1797fcf3ce44SJohn Forte 				}
1798fcf3ce44SJohn Forte 				map_ptr->hba_addr.gfc_port_dev.
1799063d642aSBill Gumbrell 				    priv_port.sf_inq_dtype =
1800063d642aSBill Gumbrell 				    fp_hba_port.dev_dtype;
1801fcf3ce44SJohn Forte 			}
1802fcf3ce44SJohn Forte 
1803fcf3ce44SJohn Forte 			for (i = 0; (i < num_devices &&
1804063d642aSBill Gumbrell 			    i < SF_NUM_ENTRIES_IN_MAP);
1805063d642aSBill Gumbrell 			    i++, dev_ptr++, dev_list++) {
1806fcf3ce44SJohn Forte 				/*
1807fcf3ce44SJohn Forte 				 * Out of 24 bits of port_id, copy only
1808fcf3ce44SJohn Forte 				 * 8 bits to al_pa. This works okay for
1809fcf3ce44SJohn Forte 				 * devices that're on a private loop.
1810fcf3ce44SJohn Forte 				 */
1811fcf3ce44SJohn Forte 				if (dev_list->dev_did.port_id > 0xff) {
1812fcf3ce44SJohn Forte 					(void) free(dlistptr);
1813fcf3ce44SJohn Forte 					(void) free(map_ptr->dev_addr);
1814fcf3ce44SJohn Forte 					map_ptr->dev_addr = NULL;
1815fcf3ce44SJohn Forte 					return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1816fcf3ce44SJohn Forte 				}
1817fcf3ce44SJohn Forte 				dev_ptr->port_topology = hba_port_top;
1818fcf3ce44SJohn Forte 				dev_ptr->gfc_port_dev.priv_port.sf_al_pa
1819063d642aSBill Gumbrell 				    = (uchar_t)dev_list->dev_did.port_id;
1820063d642aSBill Gumbrell 
1821063d642aSBill Gumbrell 			/* Code refactorization is needed for C style */
1822063d642aSBill Gumbrell 			dev_ptr->gfc_port_dev.priv_port.sf_hard_address
1823063d642aSBill Gumbrell 			    = (uchar_t)dev_list->dev_hard_addr.hard_addr;
1824063d642aSBill Gumbrell 
1825fcf3ce44SJohn Forte 				for (j = 0; j < FC_WWN_SIZE; j++) {
1826063d642aSBill Gumbrell 
1827063d642aSBill Gumbrell 			dev_ptr->gfc_port_dev.priv_port.sf_node_wwn[j] =
1828063d642aSBill Gumbrell 			    dev_list->dev_nwwn.raw_wwn[j];
1829063d642aSBill Gumbrell 			dev_ptr->gfc_port_dev.priv_port.sf_port_wwn[j] =
1830063d642aSBill Gumbrell 			    dev_list->dev_pwwn.raw_wwn[j];
1831063d642aSBill Gumbrell 
1832fcf3ce44SJohn Forte 				}
1833fcf3ce44SJohn Forte 				dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype =
1834063d642aSBill Gumbrell 				    dev_list->dev_dtype;
1835fcf3ce44SJohn Forte 			}
1836fcf3ce44SJohn Forte 			break;
1837fcf3ce44SJohn Forte 		case FC_TOP_PT_PT:
1838fcf3ce44SJohn Forte 			(void) free(dlistptr);
1839fcf3ce44SJohn Forte 			(void) free(map_ptr->dev_addr);
1840fcf3ce44SJohn Forte 			map_ptr->dev_addr = NULL;
1841fcf3ce44SJohn Forte 			return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
1842fcf3ce44SJohn Forte 		default:
1843fcf3ce44SJohn Forte 			(void) free(dlistptr);
1844fcf3ce44SJohn Forte 			(void) free(map_ptr->dev_addr);
1845fcf3ce44SJohn Forte 			map_ptr->dev_addr = NULL;
1846fcf3ce44SJohn Forte 			return (L_UNEXPECTED_FC_TOPOLOGY);
1847fcf3ce44SJohn Forte 		}	/* End of switch on port_topology */
1848fcf3ce44SJohn Forte 		(void) free(dlistptr);
1849fcf3ce44SJohn Forte 
1850fcf3ce44SJohn Forte 	} else {	/* sf and fc4/pci devices */
1851fcf3ce44SJohn Forte 		if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
1852fcf3ce44SJohn Forte 			return (errno);
1853fcf3ce44SJohn Forte 		/* initialize map */
1854fcf3ce44SJohn Forte 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
1855fcf3ce44SJohn Forte 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
1856fcf3ce44SJohn Forte 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
1857fcf3ce44SJohn Forte 			(void) close(fd);
1858fcf3ce44SJohn Forte 			return (L_SFIOCGMAP_IOCTL_FAIL);
1859fcf3ce44SJohn Forte 		}
1860fcf3ce44SJohn Forte 		/* Check for reasonableness. */
1861fcf3ce44SJohn Forte 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
1862fcf3ce44SJohn Forte 			(void) close(fd);
1863fcf3ce44SJohn Forte 			return (L_INVALID_LOOP_MAP);
1864fcf3ce44SJohn Forte 		}
1865fcf3ce44SJohn Forte 		if (sf_map.sf_count == 0) {
1866fcf3ce44SJohn Forte 			(void) close(fd);
1867fcf3ce44SJohn Forte 			return (L_NO_DEVICES_FOUND);
1868fcf3ce44SJohn Forte 		}
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte 		map_ptr->count = sf_map.sf_count;
1871fcf3ce44SJohn Forte 		if ((map_ptr->dev_addr =
1872063d642aSBill Gumbrell 		    (gfc_port_dev_info_t *)calloc(map_ptr->count,
1873063d642aSBill Gumbrell 		    sizeof (gfc_port_dev_info_t))) == NULL) {
1874fcf3ce44SJohn Forte 			(void) close(fd);
1875fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
1876fcf3ce44SJohn Forte 		}
1877fcf3ce44SJohn Forte 		dev_ptr = map_ptr->dev_addr;
1878fcf3ce44SJohn Forte 		for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) {
1879fcf3ce44SJohn Forte 			if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) {
1880fcf3ce44SJohn Forte 				(void) free(map_ptr->dev_addr);
1881fcf3ce44SJohn Forte 				map_ptr->dev_addr = NULL;
1882fcf3ce44SJohn Forte 				(void) close(fd);
1883fcf3ce44SJohn Forte 				return (L_INVALID_LOOP_MAP);
1884fcf3ce44SJohn Forte 			}
1885fcf3ce44SJohn Forte 			dev_ptr->port_topology = hba_port_top;
1886fcf3ce44SJohn Forte 			dev_ptr->gfc_port_dev.priv_port =
1887063d642aSBill Gumbrell 			    sf_map.sf_addr_pair[i];
1888fcf3ce44SJohn Forte 		}
1889fcf3ce44SJohn Forte 		map_ptr->hba_addr.port_topology = hba_port_top;
1890fcf3ce44SJohn Forte 		map_ptr->hba_addr.gfc_port_dev.priv_port =
1891063d642aSBill Gumbrell 		    sf_map.sf_hba_addr;
1892fcf3ce44SJohn Forte 		(void) close(fd);
1893fcf3ce44SJohn Forte 	}
1894fcf3ce44SJohn Forte 
1895fcf3ce44SJohn Forte 	return (0);
1896fcf3ce44SJohn Forte }
1897fcf3ce44SJohn Forte 
1898fcf3ce44SJohn Forte /*
1899fcf3ce44SJohn Forte  * This function consturct FC proerty list using map_dev_fc_prop_list.
1900fcf3ce44SJohn Forte  *
1901fcf3ce44SJohn Forte  * port WWN, node WWN, port addr and hard addr properties is constructed.
1902fcf3ce44SJohn Forte  *
1903fcf3ce44SJohn Forte  * return 0 if OK.
1904fcf3ce44SJohn Forte  * otherwise returns error code.
1905fcf3ce44SJohn Forte  */
1906fcf3ce44SJohn Forte static int
update_map_dev_fc_prop(impl_map_dev_prop_t ** prop_list,uint32_t map_topo,uchar_t * port_wwn,uchar_t * node_wwn,int port_addr,int hard_addr)1907063d642aSBill Gumbrell update_map_dev_fc_prop(impl_map_dev_prop_t **prop_list, uint32_t map_topo,
1908063d642aSBill Gumbrell     uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr)
1909fcf3ce44SJohn Forte {
1910fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*prop_ptr, *pl_start = NULL, *pl_end = NULL;
1911fcf3ce44SJohn Forte 	uchar_t *port_wwn_data, *node_wwn_data;
1912fcf3ce44SJohn Forte 	int *port_addr_data, *hard_addr_data;
1913fcf3ce44SJohn Forte 
1914fcf3ce44SJohn Forte 	/* consrtruct port addr property. */
1915063d642aSBill Gumbrell 	if ((map_topo == FC_TOP_FABRIC) || (map_topo == FC_TOP_PUBLIC_LOOP)) {
1916fcf3ce44SJohn Forte 		if (port_addr <= 0xffff) {
1917063d642aSBill Gumbrell 			return (L_INVALID_FABRIC_ADDRESS);
1918fcf3ce44SJohn Forte 		}
1919fcf3ce44SJohn Forte 	} else if (map_topo == FC_TOP_PRIVATE_LOOP) {
1920fcf3ce44SJohn Forte 		if (port_addr > 0xff) {
1921063d642aSBill Gumbrell 			return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1922fcf3ce44SJohn Forte 		}
1923fcf3ce44SJohn Forte 	}
1924fcf3ce44SJohn Forte 
1925fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1926063d642aSBill Gumbrell 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1927fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1928fcf3ce44SJohn Forte 	}
1929fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP,
1930063d642aSBill Gumbrell 	    strlen(PORT_ADDR_PROP));
1931fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1932fcf3ce44SJohn Forte 
1933fcf3ce44SJohn Forte 	if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1934fcf3ce44SJohn Forte 		free(prop_ptr);
1935fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1936fcf3ce44SJohn Forte 	}
1937fcf3ce44SJohn Forte 	*port_addr_data = port_addr;
1938fcf3ce44SJohn Forte 	prop_ptr->prop_data = port_addr_data;
1939fcf3ce44SJohn Forte 
1940fcf3ce44SJohn Forte 	pl_start = pl_end = prop_ptr;
1941fcf3ce44SJohn Forte 
1942fcf3ce44SJohn Forte 	/* consrtruct port WWN property. */
1943fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1944063d642aSBill Gumbrell 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1945fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1946fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1947fcf3ce44SJohn Forte 	}
1948fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP,
1949063d642aSBill Gumbrell 	    strlen(PORT_WWN_PROP));
1950fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1951fcf3ce44SJohn Forte 
1952063d642aSBill Gumbrell 	if ((port_wwn_data = (uchar_t *)calloc(1, FC_WWN_SIZE)) == NULL) {
1953fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1954fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1955fcf3ce44SJohn Forte 	}
1956fcf3ce44SJohn Forte 	memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE);
1957fcf3ce44SJohn Forte 	prop_ptr->prop_data = port_wwn_data;
1958fcf3ce44SJohn Forte 	prop_ptr->prop_size = FC_WWN_SIZE;
1959fcf3ce44SJohn Forte 	pl_end->next = prop_ptr;
1960fcf3ce44SJohn Forte 	pl_end = prop_ptr;
1961fcf3ce44SJohn Forte 
1962fcf3ce44SJohn Forte 	/* consrtruct node WWN property. */
1963fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1964063d642aSBill Gumbrell 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1965fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1966fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1967fcf3ce44SJohn Forte 	}
1968fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP,
1969063d642aSBill Gumbrell 	    strlen(NODE_WWN_PROP));
1970fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1971fcf3ce44SJohn Forte 
1972fcf3ce44SJohn Forte 	if ((node_wwn_data = (uchar_t *)calloc(
1973063d642aSBill Gumbrell 	    1, FC_WWN_SIZE)) == NULL) {
1974fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1975fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1976fcf3ce44SJohn Forte 	}
1977fcf3ce44SJohn Forte 	memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE);
1978fcf3ce44SJohn Forte 	prop_ptr->prop_data = node_wwn_data;
1979fcf3ce44SJohn Forte 	prop_ptr->prop_size = FC_WWN_SIZE;
1980fcf3ce44SJohn Forte 	pl_end->next = prop_ptr;
1981fcf3ce44SJohn Forte 	pl_end = prop_ptr;
1982fcf3ce44SJohn Forte 
1983fcf3ce44SJohn Forte 	/* consrtruct hard addr property. */
1984fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1985063d642aSBill Gumbrell 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1986fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1987fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1988fcf3ce44SJohn Forte 	}
1989fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP,
1990063d642aSBill Gumbrell 	    strlen(HARD_ADDR_PROP));
1991fcf3ce44SJohn Forte 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1992fcf3ce44SJohn Forte 
1993063d642aSBill Gumbrell 	if ((hard_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1994fcf3ce44SJohn Forte 		free_prop_list(&pl_start);
1995fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
1996fcf3ce44SJohn Forte 	}
1997fcf3ce44SJohn Forte 	*hard_addr_data = hard_addr;
1998fcf3ce44SJohn Forte 	prop_ptr->prop_data = hard_addr_data;
1999fcf3ce44SJohn Forte 	pl_end->next = prop_ptr;
2000fcf3ce44SJohn Forte 	pl_end = prop_ptr;
2001fcf3ce44SJohn Forte 
2002fcf3ce44SJohn Forte 	if (*prop_list == NULL) {
2003fcf3ce44SJohn Forte 		*prop_list = pl_start;
2004fcf3ce44SJohn Forte 	} else {
2005fcf3ce44SJohn Forte 		pl_end->next = (*prop_list)->next;
2006fcf3ce44SJohn Forte 		*prop_list = pl_start;
2007fcf3ce44SJohn Forte 	}
2008fcf3ce44SJohn Forte 
2009fcf3ce44SJohn Forte 	return (0);
2010fcf3ce44SJohn Forte }
2011fcf3ce44SJohn Forte 
2012fcf3ce44SJohn Forte /*
2013fcf3ce44SJohn Forte  * This function consturct FCP inq dtype propery.
2014fcf3ce44SJohn Forte  * if inq_dtype is null the property is constrcted with err info.
2015fcf3ce44SJohn Forte  *
2016fcf3ce44SJohn Forte  * L_MALLOC_FAILED is the only possible error.
2017fcf3ce44SJohn Forte  */
2018fcf3ce44SJohn Forte static int
update_map_dev_FCP_prop(impl_map_dev_prop_t ** prop_list,uchar_t * inq_dtype,int err,int exist)2019063d642aSBill Gumbrell update_map_dev_FCP_prop(impl_map_dev_prop_t **prop_list,
2020063d642aSBill Gumbrell     uchar_t *inq_dtype, int err, int exist)
2021fcf3ce44SJohn Forte {
2022fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*prop_ptr, *old_prop_ptr;
2023fcf3ce44SJohn Forte 	uchar_t *inq_dtype_data;
2024fcf3ce44SJohn Forte 
2025fcf3ce44SJohn Forte 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
2026063d642aSBill Gumbrell 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
2027fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
2028fcf3ce44SJohn Forte 	}
2029fcf3ce44SJohn Forte 
2030fcf3ce44SJohn Forte 	(void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP,
2031063d642aSBill Gumbrell 	    strlen(INQ_DTYPE_PROP));
2032fcf3ce44SJohn Forte 
2033fcf3ce44SJohn Forte 	if (inq_dtype == NULL) {
2034fcf3ce44SJohn Forte 		prop_ptr->prop_data = NULL;
2035fcf3ce44SJohn Forte 		prop_ptr->prop_error = err;
2036fcf3ce44SJohn Forte 	} else {
2037fcf3ce44SJohn Forte 		if ((inq_dtype_data = (uchar_t *)calloc(
2038063d642aSBill Gumbrell 		    1, sizeof (uchar_t))) == NULL) {
2039fcf3ce44SJohn Forte 			free(prop_ptr);
2040fcf3ce44SJohn Forte 			return (L_MALLOC_FAILED);
2041fcf3ce44SJohn Forte 		}
2042fcf3ce44SJohn Forte 		memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t));
2043fcf3ce44SJohn Forte 		prop_ptr->prop_data = inq_dtype_data;
2044fcf3ce44SJohn Forte 		prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
2045fcf3ce44SJohn Forte 		prop_ptr->prop_size = sizeof (uchar_t);
2046fcf3ce44SJohn Forte 	}
2047fcf3ce44SJohn Forte 
2048fcf3ce44SJohn Forte 	if (*prop_list == NULL) {
2049fcf3ce44SJohn Forte 		*prop_list = prop_ptr;
2050fcf3ce44SJohn Forte 	} else {
2051fcf3ce44SJohn Forte 		if (exist == PROP_EXIST) {
2052fcf3ce44SJohn Forte 			prop_ptr->next = (*prop_list)->next;
2053fcf3ce44SJohn Forte 			old_prop_ptr = *prop_list;
2054fcf3ce44SJohn Forte 			*prop_list = prop_ptr;
2055fcf3ce44SJohn Forte 			free((uchar_t *)(old_prop_ptr->prop_data));
2056fcf3ce44SJohn Forte 			old_prop_ptr->prop_data = NULL;
2057fcf3ce44SJohn Forte 			S_FREE(old_prop_ptr);
2058fcf3ce44SJohn Forte 		} else {
2059fcf3ce44SJohn Forte 			prop_ptr->next = *prop_list;
2060fcf3ce44SJohn Forte 			*prop_list = prop_ptr;
2061fcf3ce44SJohn Forte 		}
2062fcf3ce44SJohn Forte 	}
2063fcf3ce44SJohn Forte 
2064fcf3ce44SJohn Forte 	return (0);
2065fcf3ce44SJohn Forte }
2066fcf3ce44SJohn Forte 
2067fcf3ce44SJohn Forte /*
2068fcf3ce44SJohn Forte  * This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl()
2069fcf3ce44SJohn Forte  * to get the inq_dtype of input device and calls update_map_dev_FCP_prop().
2070fcf3ce44SJohn Forte  * inq_dtype is set to NULL and pass error code if inq_dtype data is not
2071fcf3ce44SJohn Forte  * requried.
2072fcf3ce44SJohn Forte  *
2073fcf3ce44SJohn Forte  * return error from update_map_dev_FCP_prop().
2074fcf3ce44SJohn Forte  */
2075fcf3ce44SJohn Forte static int
handle_map_dev_FCP_prop(minor_t fp_xport_minor,la_wwn_t port_wwn,impl_map_dev_prop_t ** prop_list)2076063d642aSBill Gumbrell handle_map_dev_FCP_prop(minor_t fp_xport_minor, la_wwn_t port_wwn,
2077063d642aSBill Gumbrell     impl_map_dev_prop_t **prop_list)
2078fcf3ce44SJohn Forte {
2079fcf3ce44SJohn Forte 	struct device_data	inq_data;
2080*926d645fSToomas Soome 	int			fcp_fd, err;
2081fcf3ce44SJohn Forte 	struct fcp_ioctl	fcp_data;
2082fcf3ce44SJohn Forte 	uchar_t			inq_dtype;
2083fcf3ce44SJohn Forte 
2084fcf3ce44SJohn Forte 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
2085fcf3ce44SJohn Forte 		update_map_dev_FCP_prop(prop_list, NULL,
2086063d642aSBill Gumbrell 		    L_OPEN_PATH_FAIL, PROP_NOEXIST);
2087fcf3ce44SJohn Forte 	}
2088fcf3ce44SJohn Forte 
2089fcf3ce44SJohn Forte 	/* Get the minor number for an fp instance */
2090fcf3ce44SJohn Forte 	fcp_data.fp_minor = fp_xport_minor;
2091fcf3ce44SJohn Forte 
2092fcf3ce44SJohn Forte 	/* Get FCP prop for the hba first. */
2093fcf3ce44SJohn Forte 	fcp_data.listlen = 1;
2094fcf3ce44SJohn Forte 	inq_data.dev_pwwn = port_wwn;
2095fcf3ce44SJohn Forte 	fcp_data.list = (caddr_t)&inq_data;
2096fcf3ce44SJohn Forte 
2097fcf3ce44SJohn Forte 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
2098fcf3ce44SJohn Forte 		/* if ioctl error then set the prop_error.	*/
2099063d642aSBill Gumbrell 		if ((err = update_map_dev_FCP_prop(
2100063d642aSBill Gumbrell 		    prop_list, NULL, err, PROP_NOEXIST)) != 0) {
2101063d642aSBill Gumbrell 			return (err);
2102063d642aSBill Gumbrell 		}
2103fcf3ce44SJohn Forte 	} else {
2104063d642aSBill Gumbrell 		inq_dtype = inq_data.dev0_type;
2105063d642aSBill Gumbrell 		if ((err = update_map_dev_FCP_prop(
2106063d642aSBill Gumbrell 		    prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) {
2107063d642aSBill Gumbrell 			return (err);
2108063d642aSBill Gumbrell 		}
2109fcf3ce44SJohn Forte 	}
2110fcf3ce44SJohn Forte 
2111fcf3ce44SJohn Forte 	return (0);
2112fcf3ce44SJohn Forte }
2113fcf3ce44SJohn Forte 
2114fcf3ce44SJohn Forte /*
2115fcf3ce44SJohn Forte  * Construct device map tree from nexus driver
2116fcf3ce44SJohn Forte  *
2117fcf3ce44SJohn Forte  * PARAMS:
2118fcf3ce44SJohn Forte  *	path -	must be the physical path to a device
2119fcf3ce44SJohn Forte  *	l_err  - ptr to an error code.  Set when NULL is returned.
2120fcf3ce44SJohn Forte  *	flag -  device map fomat and property type.
2121fcf3ce44SJohn Forte  *
2122fcf3ce44SJohn Forte  * LOGIC:
2123fcf3ce44SJohn Forte  *	1. check the validity of path via g_get_path_type.
2124fcf3ce44SJohn Forte  *	2. If FC path, get the topology of the path via
2125fcf3ce44SJohn Forte  *		g_get_fca_port_topology.
2126fcf3ce44SJohn Forte  *
2127fcf3ce44SJohn Forte  *	3. If FC type(Leadville statck)
2128fcf3ce44SJohn Forte  *		FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t.
2129fcf3ce44SJohn Forte  *		FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t.
2130fcf3ce44SJohn Forte  *
2131fcf3ce44SJohn Forte  *		root of tree is set with host_params info
2132fcf3ce44SJohn Forte  *			FC propery is set.
2133fcf3ce44SJohn Forte  *			FCP property is set if reqyested through flag.
2134fcf3ce44SJohn Forte  *				Issue g_issue_fcp_ioctl to get FCP inquiry data
2135fcf3ce44SJohn Forte  *		consruruct list of children via dev_list.
2136fcf3ce44SJohn Forte  *			FC property is set.
2137fcf3ce44SJohn Forte  *			FCP property is set if reqyested through flag.
2138fcf3ce44SJohn Forte  *				Issue FCIO_DEV_LOGIN if it is fabric device.
2139fcf3ce44SJohn Forte  *				Issue g_issue_fcp_ioctl to get FCP inquiry data.
2140fcf3ce44SJohn Forte  *
2141fcf3ce44SJohn Forte  *	   else FC4 type(socal/sf or ifp stack)
2142fcf3ce44SJohn Forte  *		SFIOCGMAP ioctl to get the device and hba nodes of
2143fcf3ce44SJohn Forte  *			sf_addr_pair_t.
2144fcf3ce44SJohn Forte  *		FCIO_GETMAP ioctl to get hba port info.
2145fcf3ce44SJohn Forte  *		consturct map and child tree list and
2146fcf3ce44SJohn Forte  *		set the properties as private loop devices.
2147fcf3ce44SJohn Forte  *
2148fcf3ce44SJohn Forte  * RETURNS:
2149fcf3ce44SJohn Forte  *	ptr to map is returned if OK.
2150fcf3ce44SJohn Forte  *	NULL and l_err is set otherwise.
2151fcf3ce44SJohn Forte  */
2152fcf3ce44SJohn Forte gfc_dev_t
g_dev_map_init(char * path,int * l_err,int flag)2153fcf3ce44SJohn Forte g_dev_map_init(char *path, int *l_err, int flag)
2154fcf3ce44SJohn Forte {
2155063d642aSBill Gumbrell 	int		fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0;
2156063d642aSBill Gumbrell 	char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
2157063d642aSBill Gumbrell 	char		*char_ptr, *nexus_path;
2158063d642aSBill Gumbrell 	struct stat	stbuf;
2159063d642aSBill Gumbrell 	fc_port_dev_t	*dev_list = NULL, *dlist;
2160063d642aSBill Gumbrell 	uint32_t	hba_port_top, state;
2161063d642aSBill Gumbrell 	uint_t		path_type;
2162063d642aSBill Gumbrell 	sf_al_map_t	sf_map;
2163063d642aSBill Gumbrell 	fc_port_dev_t	fp_hba_port;
2164063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
2165063d642aSBill Gumbrell 	int		p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd;
2166063d642aSBill Gumbrell 	fcio_t		fcio;
2167063d642aSBill Gumbrell 	struct lilpmap	limited_map;
2168063d642aSBill Gumbrell 	impl_map_dev_t	*impl_map, *impl_dev;
2169063d642aSBill Gumbrell 	impl_map_dev_t	*mdl_start = NULL, *mdl_end = NULL;
2170063d642aSBill Gumbrell 	struct stat	sbuf;
2171fcf3ce44SJohn Forte 
2172fcf3ce44SJohn Forte 	if (l_err == NULL) {
2173fcf3ce44SJohn Forte 		return (NULL);
2174fcf3ce44SJohn Forte 	}
2175fcf3ce44SJohn Forte 
2176fcf3ce44SJohn Forte 	if (path == NULL) {
2177fcf3ce44SJohn Forte 		*l_err = L_INVALID_PATH;
2178fcf3ce44SJohn Forte 		return (NULL);
2179fcf3ce44SJohn Forte 	}
2180fcf3ce44SJohn Forte 
2181fcf3ce44SJohn Forte 	*l_err = 0;
2182fcf3ce44SJohn Forte 
2183fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
2184fcf3ce44SJohn Forte 	/*
2185fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
2186fcf3ce44SJohn Forte 	 *
2187fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
2188fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
2189fcf3ce44SJohn Forte 	 * or
2190fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
2191fcf3ce44SJohn Forte 	 * or
2192fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
2193fcf3ce44SJohn Forte 	 * or
2194fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
2195fcf3ce44SJohn Forte 	 */
2196fcf3ce44SJohn Forte 	if (strstr(path, SCSI_VHCI)) {
2197fcf3ce44SJohn Forte 		(void) strcpy(drvr_path0, path);
2198fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path0, &pathlist)) {
2199fcf3ce44SJohn Forte 			*l_err = L_INVALID_PATH;
2200fcf3ce44SJohn Forte 			return (NULL);
2201fcf3ce44SJohn Forte 		}
2202fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
2203fcf3ce44SJohn Forte 		p_on = p_st = 0;
2204fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
2205fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
2206fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
2207063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_ONLINE) {
2208fcf3ce44SJohn Forte 					p_on = i;
2209fcf3ce44SJohn Forte 					break;
2210fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
2211063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_STANDBY) {
2212fcf3ce44SJohn Forte 					p_st = i;
2213fcf3ce44SJohn Forte 				}
2214fcf3ce44SJohn Forte 			}
2215fcf3ce44SJohn Forte 		}
2216fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
2217fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
2218fcf3ce44SJohn Forte 			/* on_line path */
2219fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
2220063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_hba);
2221fcf3ce44SJohn Forte 		} else {
2222fcf3ce44SJohn Forte 			/* standby or path0 */
2223fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
2224063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_hba);
2225fcf3ce44SJohn Forte 		}
2226fcf3ce44SJohn Forte 		free(pathlist.path_info);
2227fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
2228fcf3ce44SJohn Forte 	} else {
2229fcf3ce44SJohn Forte 		(void) strcpy(drvr_path, path);
2230fcf3ce44SJohn Forte 		if (strstr(drvr_path, DRV_NAME_SSD) ||
2231063d642aSBill Gumbrell 		    strstr(drvr_path, SES_NAME) ||
2232063d642aSBill Gumbrell 		    strstr(drvr_path, DRV_NAME_ST)) {
2233fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
2234fcf3ce44SJohn Forte 				*l_err = L_INVALID_PATH;
2235fcf3ce44SJohn Forte 				return (NULL);
2236fcf3ce44SJohn Forte 			}
2237fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate sting  */
2238fcf3ce44SJohn Forte 			/* append controller */
2239fcf3ce44SJohn Forte 			(void) strcat(drvr_path, FC_CTLR);
2240fcf3ce44SJohn Forte 		} else {
2241fcf3ce44SJohn Forte 			if (stat(drvr_path, &stbuf) < 0) {
2242fcf3ce44SJohn Forte 				*l_err = L_LSTAT_ERROR;
2243fcf3ce44SJohn Forte 				return (NULL);
2244fcf3ce44SJohn Forte 			}
2245fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
2246fcf3ce44SJohn Forte 				/* append controller */
2247fcf3ce44SJohn Forte 				(void) strcat(drvr_path, FC_CTLR);
2248fcf3ce44SJohn Forte 			}
2249fcf3ce44SJohn Forte 		}
2250fcf3ce44SJohn Forte 	}
2251fcf3ce44SJohn Forte 
2252fcf3ce44SJohn Forte 	P_DPRINTF("  g_dev_map_init: Geting drive map from:"
2253063d642aSBill Gumbrell 	    " %s\n", drvr_path);
2254fcf3ce44SJohn Forte 
2255fcf3ce44SJohn Forte 	path_type = g_get_path_type(drvr_path);
2256fcf3ce44SJohn Forte 	if ((path_type == 0) || !(path_type & XPORT_MASK)) {
2257fcf3ce44SJohn Forte 		*l_err = L_INVALID_PATH_TYPE;
2258fcf3ce44SJohn Forte 		return (NULL);
2259fcf3ce44SJohn Forte 	}
2260fcf3ce44SJohn Forte 
2261fcf3ce44SJohn Forte 	/* get fiber topology */
2262fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(drvr_path,
2263063d642aSBill Gumbrell 	    &hba_port_top, 0)) != 0) {
2264fcf3ce44SJohn Forte 		*l_err = err;
2265fcf3ce44SJohn Forte 		return (NULL);
2266fcf3ce44SJohn Forte 	}
2267fcf3ce44SJohn Forte 
2268fcf3ce44SJohn Forte 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) {
2269fcf3ce44SJohn Forte 		*l_err = errno;
2270fcf3ce44SJohn Forte 		return (NULL);
2271fcf3ce44SJohn Forte 	}
2272fcf3ce44SJohn Forte 
2273fcf3ce44SJohn Forte 	/* for FC devices. */
2274fcf3ce44SJohn Forte 	if (path_type & FC_FCA_MASK) {
2275fcf3ce44SJohn Forte 		/* get the number of device first. */
2276063d642aSBill Gumbrell 		fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
2277063d642aSBill Gumbrell 		fcio.fcio_olen = sizeof (num_devices);
2278fcf3ce44SJohn Forte 		fcio.fcio_xfer = FCIO_XFER_READ;
2279063d642aSBill Gumbrell 		fcio.fcio_obuf = (caddr_t)&num_devices;
2280063d642aSBill Gumbrell 		if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2281063d642aSBill Gumbrell 			I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
2282063d642aSBill Gumbrell 			(void) close(fd);
2283063d642aSBill Gumbrell 			*l_err = L_FCIO_GET_NUM_DEVS_FAIL;
2284063d642aSBill Gumbrell 			return (NULL);
2285063d642aSBill Gumbrell 		}
2286063d642aSBill Gumbrell 		if (num_devices != 0) {
2287fcf3ce44SJohn Forte 			if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
2288063d642aSBill Gumbrell 			    sizeof (fc_port_dev_t))) == NULL) {
2289063d642aSBill Gumbrell 				(void) close(fd);
2290063d642aSBill Gumbrell 				*l_err = L_MALLOC_FAILED;
2291063d642aSBill Gumbrell 				return (NULL);
2292fcf3ce44SJohn Forte 			}
2293063d642aSBill Gumbrell 
2294063d642aSBill Gumbrell 			bzero((caddr_t)&fcio, sizeof (fcio));
2295063d642aSBill Gumbrell 			/* Get the device list */
2296fcf3ce44SJohn Forte 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2297fcf3ce44SJohn Forte 			/* Information read operation */
2298fcf3ce44SJohn Forte 			fcio.fcio_xfer = FCIO_XFER_READ;
2299fcf3ce44SJohn Forte 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
2300063d642aSBill Gumbrell 			fcio.fcio_obuf = (caddr_t)dev_list;
2301fcf3ce44SJohn Forte 			/* new device count */
2302fcf3ce44SJohn Forte 			fcio.fcio_alen = sizeof (new_count);
2303fcf3ce44SJohn Forte 			fcio.fcio_abuf = (caddr_t)&new_count;
2304fcf3ce44SJohn Forte 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
2305063d642aSBill Gumbrell 				if (err == L_INVALID_DEVICE_COUNT) {
2306063d642aSBill Gumbrell 					/*
2307063d642aSBill Gumbrell 					 * original buffer was small so allocate
2308063d642aSBill Gumbrell 					 * buffer with a new count and retry.
2309063d642aSBill Gumbrell 					 */
2310063d642aSBill Gumbrell 					free(dev_list);
2311063d642aSBill Gumbrell 					num_devices = new_count;
2312063d642aSBill Gumbrell 					new_count = 0;
2313063d642aSBill Gumbrell 					if ((dev_list = (fc_port_dev_t *)
2314063d642aSBill Gumbrell 					    calloc(num_devices,
2315063d642aSBill Gumbrell 					    sizeof (fc_port_dev_t))) == NULL) {
2316063d642aSBill Gumbrell 						(void) close(fd);
2317063d642aSBill Gumbrell 						*l_err = L_MALLOC_FAILED;
2318063d642aSBill Gumbrell 						return (NULL);
2319063d642aSBill Gumbrell 					}
2320063d642aSBill Gumbrell 					fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2321063d642aSBill Gumbrell 					/* Information read operation */
2322063d642aSBill Gumbrell 					fcio.fcio_xfer = FCIO_XFER_READ;
2323063d642aSBill Gumbrell 					fcio.fcio_obuf = (caddr_t)dev_list;
2324063d642aSBill Gumbrell 					fcio.fcio_olen = num_devices *
2325063d642aSBill Gumbrell 					    sizeof (fc_port_dev_t);
2326063d642aSBill Gumbrell 					/* new device count */
2327063d642aSBill Gumbrell 					fcio.fcio_alen = sizeof (new_count);
2328063d642aSBill Gumbrell 					fcio.fcio_abuf = (caddr_t)&new_count;
2329063d642aSBill Gumbrell 					if ((err = g_issue_fcio_ioctl(fd, &fcio,
2330063d642aSBill Gumbrell 					    0)) != 0) {
2331063d642aSBill Gumbrell 						if (err ==
2332063d642aSBill Gumbrell 						    L_INVALID_DEVICE_COUNT) {
2333063d642aSBill Gumbrell 							/*
2334063d642aSBill Gumbrell 							 * No more retry. There
2335063d642aSBill Gumbrell 							 * may be severe
2336063d642aSBill Gumbrell 							 * hardware problem so
2337063d642aSBill Gumbrell 							 * return error here.
2338063d642aSBill Gumbrell 							 */
2339063d642aSBill Gumbrell 							I_DPRINTF(" Device"
2340063d642aSBill Gumbrell 							    " count was %d"
2341063d642aSBill Gumbrell 							    " should have been"
2342063d642aSBill Gumbrell 							    " %d\n",
2343063d642aSBill Gumbrell 							    num_devices,
2344063d642aSBill Gumbrell 							    new_count);
2345063d642aSBill Gumbrell 							free(dev_list);
2346063d642aSBill Gumbrell 							(void) close(fd);
2347063d642aSBill Gumbrell 
2348063d642aSBill Gumbrell 						*l_err = L_INVALID_DEVICE_COUNT;
2349063d642aSBill Gumbrell 
2350063d642aSBill Gumbrell 							return (NULL);
2351063d642aSBill Gumbrell 						} else {
2352063d642aSBill Gumbrell 
2353063d642aSBill Gumbrell 				/* Code refactorization is needed for C style */
2354fcf3ce44SJohn Forte 				I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
2355063d642aSBill Gumbrell 
2356063d642aSBill Gumbrell 							free(dev_list);
2357063d642aSBill Gumbrell 							(void) close(fd);
2358063d642aSBill Gumbrell 
2359063d642aSBill Gumbrell 					*l_err = L_FCIO_GET_DEV_LIST_FAIL;
2360063d642aSBill Gumbrell 
2361063d642aSBill Gumbrell 							return (NULL);
2362063d642aSBill Gumbrell 						}
2363063d642aSBill Gumbrell 					}
2364063d642aSBill Gumbrell 				}
2365fcf3ce44SJohn Forte 			}
2366fcf3ce44SJohn Forte 		}
2367fcf3ce44SJohn Forte 
2368fcf3ce44SJohn Forte 		/*
2369fcf3ce44SJohn Forte 		 * if new count is smaller than the original number from
2370fcf3ce44SJohn Forte 		 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
2371fcf3ce44SJohn Forte 		 * and continue.
2372fcf3ce44SJohn Forte 		 */
2373063d642aSBill Gumbrell 		if (new_count < num_devices) {
2374063d642aSBill Gumbrell 			num_devices = new_count;
2375063d642aSBill Gumbrell 			if (new_count > 0) {
2376063d642aSBill Gumbrell 				if ((dev_list = (fc_port_dev_t *)
2377063d642aSBill Gumbrell 				    realloc(dev_list,
2378063d642aSBill Gumbrell 				    (new_count * sizeof (fc_port_dev_t))))
2379063d642aSBill Gumbrell 				    == NULL) {
2380063d642aSBill Gumbrell 					S_FREE(dev_list);
2381063d642aSBill Gumbrell 					(void) close(fd);
2382063d642aSBill Gumbrell 					*l_err = L_MALLOC_FAILED;
2383063d642aSBill Gumbrell 					return (NULL);
2384063d642aSBill Gumbrell 				}
2385063d642aSBill Gumbrell 			}
2386fcf3ce44SJohn Forte 		}
2387fcf3ce44SJohn Forte 
2388fcf3ce44SJohn Forte 		/* get the host param info */
2389063d642aSBill Gumbrell 		(void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev));
2390063d642aSBill Gumbrell 		fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
2391063d642aSBill Gumbrell 		fcio.fcio_xfer = FCIO_XFER_READ;
2392063d642aSBill Gumbrell 		fcio.fcio_obuf = (caddr_t)&fp_hba_port;
2393063d642aSBill Gumbrell 		fcio.fcio_olen = sizeof (fc_port_dev_t);
2394fcf3ce44SJohn Forte 
2395063d642aSBill Gumbrell 		if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2396063d642aSBill Gumbrell 			I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
2397063d642aSBill Gumbrell 			(void) close(fd);
2398063d642aSBill Gumbrell 			if (num_devices == 0) {
2399063d642aSBill Gumbrell 				*l_err = L_NO_DEVICES_FOUND;
2400063d642aSBill Gumbrell 			} else {
2401063d642aSBill Gumbrell 				free(dev_list);
2402063d642aSBill Gumbrell 				*l_err = L_FCIO_GET_HOST_PARAMS_FAIL;
2403063d642aSBill Gumbrell 			}
2404063d642aSBill Gumbrell 			(void) close(fd);
2405063d642aSBill Gumbrell 			return (NULL);
2406fcf3ce44SJohn Forte 		}
2407fcf3ce44SJohn Forte 
2408fcf3ce44SJohn Forte 		/* If we want the lilp map then we need to do a little	*/
2409fcf3ce44SJohn Forte 		/* work here.  The lilp map contains the local hba in	*/
2410fcf3ce44SJohn Forte 		/* the dev_addr.  Once this has been added qsort the	*/
2411fcf3ce44SJohn Forte 		/* dev_addr array so it's in physical order.		*/
2412063d642aSBill Gumbrell 		if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) {
2413063d642aSBill Gumbrell 			/* First we need to allocate one additional	*/
2414*926d645fSToomas Soome 			/* device to the dev_addr structure, for the	*/
2415063d642aSBill Gumbrell 			/* local hba					*/
2416063d642aSBill Gumbrell 			if (num_devices > 0) {
2417063d642aSBill Gumbrell 				if ((dev_list = (fc_port_dev_t *)
2418063d642aSBill Gumbrell 				    realloc(dev_list,
2419063d642aSBill Gumbrell 				    (++num_devices *
2420063d642aSBill Gumbrell 				    sizeof (fc_port_dev_t)))) == NULL) {
2421063d642aSBill Gumbrell 					(void) close(fd);
2422063d642aSBill Gumbrell 					/*
2423063d642aSBill Gumbrell 					 * In case dev_list is not null free
2424063d642aSBill Gumbrell 					 * it.
2425063d642aSBill Gumbrell 					 */
2426063d642aSBill Gumbrell 					S_FREE(dev_list);
2427063d642aSBill Gumbrell 					*l_err =  L_MALLOC_FAILED;
2428063d642aSBill Gumbrell 					return (NULL);
2429063d642aSBill Gumbrell 				}
2430fcf3ce44SJohn Forte 
2431063d642aSBill Gumbrell 				/*
2432063d642aSBill Gumbrell 				 * Next, copy the local hba into this new
2433063d642aSBill Gumbrell 				 * loc.
2434063d642aSBill Gumbrell 				 */
2435063d642aSBill Gumbrell 				if (memcpy(dev_list+(num_devices-1),
2436063d642aSBill Gumbrell 				    &fp_hba_port,
2437063d642aSBill Gumbrell 				    sizeof (fc_port_dev_t)) == NULL) {
2438063d642aSBill Gumbrell 					(void) free(dev_list);
2439063d642aSBill Gumbrell 					(void) close(fd);
2440063d642aSBill Gumbrell 					*l_err =  L_MEMCPY_FAILED;
2441063d642aSBill Gumbrell 					return (NULL);
2442063d642aSBill Gumbrell 				}
2443fcf3ce44SJohn Forte 
2444063d642aSBill Gumbrell 				/* Now sort by physical location */
2445063d642aSBill Gumbrell 				qsort((void*)dev_list, num_devices,
2446063d642aSBill Gumbrell 				    sizeof (fc_port_dev_t), lilp_map_cmp);
2447063d642aSBill Gumbrell 			}
2448fcf3ce44SJohn Forte 		}
2449fcf3ce44SJohn Forte 
2450fcf3ce44SJohn Forte 
2451fcf3ce44SJohn Forte 		/* We have dev list info and host param info.	*/
2452fcf3ce44SJohn Forte 		/* Now constructs map tree with these info.	*/
2453fcf3ce44SJohn Forte 		/* First consturct the root of the map tree	*/
2454fcf3ce44SJohn Forte 		/* with host param.				*/
2455063d642aSBill Gumbrell 		if ((impl_map = (impl_map_dev_t *)calloc(
2456063d642aSBill Gumbrell 		    1, sizeof (impl_map_dev_t))) == NULL) {
2457063d642aSBill Gumbrell 			(void) free(dev_list);
2458063d642aSBill Gumbrell 			(void) close(fd);
2459063d642aSBill Gumbrell 			*l_err = L_MALLOC_FAILED;
2460063d642aSBill Gumbrell 			return (NULL);
2461063d642aSBill Gumbrell 		}
2462063d642aSBill Gumbrell 		impl_map->flag = flag;
2463063d642aSBill Gumbrell 		impl_map->topo = hba_port_top;
2464fcf3ce44SJohn Forte 
2465fcf3ce44SJohn Forte 		/* consturct hba property list.	*/
2466063d642aSBill Gumbrell 		if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2467fcf3ce44SJohn Forte 		    hba_port_top, fp_hba_port.dev_pwwn.raw_wwn,
2468fcf3ce44SJohn Forte 		    fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id,
2469fcf3ce44SJohn Forte 		    fp_hba_port.dev_hard_addr.hard_addr)) != 0) {
2470063d642aSBill Gumbrell 			(void) free(dev_list);
2471063d642aSBill Gumbrell 			(void) close(fd);
2472063d642aSBill Gumbrell 			g_dev_map_fini(impl_map);
2473063d642aSBill Gumbrell 			*l_err = err;
2474063d642aSBill Gumbrell 			return (NULL);
2475fcf3ce44SJohn Forte 		}
2476063d642aSBill Gumbrell 
2477fcf3ce44SJohn Forte 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2478063d642aSBill Gumbrell 			if (fstat(fd, &sbuf) == -1) {
2479063d642aSBill Gumbrell 				(void) free(dev_list);
2480063d642aSBill Gumbrell 				(void) close(fd);
2481063d642aSBill Gumbrell 				g_dev_map_fini(impl_map);
2482063d642aSBill Gumbrell 				*l_err = L_FSTAT_ERROR;
2483063d642aSBill Gumbrell 				return (NULL);
2484063d642aSBill Gumbrell 			}
2485063d642aSBill Gumbrell 			if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
2486063d642aSBill Gumbrell 			    fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) {
2487fcf3ce44SJohn Forte 				(void) free(dev_list);
2488fcf3ce44SJohn Forte 				(void) close(fd);
2489fcf3ce44SJohn Forte 				g_dev_map_fini(impl_map);
2490fcf3ce44SJohn Forte 				*l_err = err;
2491fcf3ce44SJohn Forte 				return (NULL);
2492fcf3ce44SJohn Forte 			}
2493063d642aSBill Gumbrell 		}
2494063d642aSBill Gumbrell 
2495063d642aSBill Gumbrell 		/* consturct child for each device and	*/
2496063d642aSBill Gumbrell 		/* set device property list.		*/
2497063d642aSBill Gumbrell 		dlist = dev_list;
2498063d642aSBill Gumbrell 		for (i = 0; i < num_devices; i++, dlist++) {
2499063d642aSBill Gumbrell 			if ((impl_dev = (impl_map_dev_t *)calloc(
2500063d642aSBill Gumbrell 			    1, sizeof (impl_map_dev_t))) == NULL) {
2501063d642aSBill Gumbrell 				(void) free(dev_list);
2502063d642aSBill Gumbrell 				(void) close(fd);
2503063d642aSBill Gumbrell 				g_dev_map_fini(impl_map);
2504063d642aSBill Gumbrell 				*l_err = L_MALLOC_FAILED;
2505063d642aSBill Gumbrell 				return (NULL);
2506063d642aSBill Gumbrell 			}
2507063d642aSBill Gumbrell 			/* set the map as parent */
2508063d642aSBill Gumbrell 			impl_dev->parent = impl_map;
2509063d642aSBill Gumbrell 			if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2510063d642aSBill Gumbrell 			    hba_port_top, dlist->dev_pwwn.raw_wwn,
2511063d642aSBill Gumbrell 			    dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id,
2512063d642aSBill Gumbrell 			    dlist->dev_hard_addr.hard_addr)) != 0) {
2513fcf3ce44SJohn Forte 				(void) free(dev_list);
2514063d642aSBill Gumbrell 				(void) close(fd);
2515fcf3ce44SJohn Forte 				g_dev_map_fini(impl_map);
2516063d642aSBill Gumbrell 				*l_err = err;
2517fcf3ce44SJohn Forte 				return (NULL);
2518063d642aSBill Gumbrell 			}
2519063d642aSBill Gumbrell 			if (i == 0) {
2520063d642aSBill Gumbrell 				mdl_start = mdl_end = impl_dev;
2521063d642aSBill Gumbrell 			} else {
2522063d642aSBill Gumbrell 				mdl_end->next = impl_dev;
2523063d642aSBill Gumbrell 				mdl_end = impl_dev;
2524063d642aSBill Gumbrell 			}
2525063d642aSBill Gumbrell 			if ((flag & MAP_XPORT_PROP_ONLY) !=
2526063d642aSBill Gumbrell 			    MAP_XPORT_PROP_ONLY) {
2527063d642aSBill Gumbrell 			if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
2528063d642aSBill Gumbrell 			    (hba_port_top == FC_TOP_FABRIC)) &&
2529063d642aSBill Gumbrell 			    (memcmp(fp_hba_port.dev_pwwn.raw_wwn,
2530063d642aSBill Gumbrell 			    dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) {
2531063d642aSBill Gumbrell 				(void) memset(&fcio, 0, sizeof (fcio_t));
2532063d642aSBill Gumbrell 				fcio.fcio_cmd = FCIO_GET_STATE;
2533063d642aSBill Gumbrell 				fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
2534063d642aSBill Gumbrell 				fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
2535063d642aSBill Gumbrell 				fcio.fcio_xfer = FCIO_XFER_READ |
2536063d642aSBill Gumbrell 				    FCIO_XFER_WRITE;
2537063d642aSBill Gumbrell 				fcio.fcio_olen = sizeof (uint32_t);
2538063d642aSBill Gumbrell 				fcio.fcio_obuf = (caddr_t)&state;
2539063d642aSBill Gumbrell 				fcio.fcio_alen = 0;
2540063d642aSBill Gumbrell 				fcio.fcio_abuf = NULL;
2541063d642aSBill Gumbrell 				if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2542063d642aSBill Gumbrell 					I_DPRINTF(
2543063d642aSBill Gumbrell 					    " FCIO_GET_STATE ioctl failed.\n");
2544063d642aSBill Gumbrell 					if ((err = update_map_dev_FCP_prop(
2545063d642aSBill Gumbrell 					    &impl_dev->prop_list, NULL,
2546063d642aSBill Gumbrell 					    L_FCIO_GET_STATE_FAIL,
2547063d642aSBill Gumbrell 					    PROP_NOEXIST)) != 0) {
2548063d642aSBill Gumbrell 						(void) free(dev_list);
2549063d642aSBill Gumbrell 						(void) close(fd);
2550063d642aSBill Gumbrell 						g_dev_map_fini(impl_map);
2551063d642aSBill Gumbrell 						*l_err = err;
2552063d642aSBill Gumbrell 						return (NULL);
2553063d642aSBill Gumbrell 					}
2554063d642aSBill Gumbrell 				}
2555063d642aSBill Gumbrell 				if (state != PORT_DEVICE_LOGGED_IN) {
2556063d642aSBill Gumbrell 					(void) close(fd);
2557063d642aSBill Gumbrell 					if ((fd = g_object_open(drvr_path,
2558063d642aSBill Gumbrell 					    O_NDELAY | O_RDONLY | O_EXCL)) ==
2559063d642aSBill Gumbrell 					    -1) {
2560063d642aSBill Gumbrell 						(void) free(dev_list);
2561063d642aSBill Gumbrell 						g_dev_map_fini(impl_map);
2562063d642aSBill Gumbrell 						*l_err = L_OPEN_PATH_FAIL;
2563063d642aSBill Gumbrell 						return (NULL);
2564063d642aSBill Gumbrell 					}
2565063d642aSBill Gumbrell 					(void) memset(&fcio, 0,
2566063d642aSBill Gumbrell 					    sizeof (fcio_t));
2567063d642aSBill Gumbrell 					fcio.fcio_cmd = FCIO_DEV_LOGIN;
2568063d642aSBill Gumbrell 					fcio.fcio_ilen =
2569063d642aSBill Gumbrell 					    sizeof (dlist->dev_pwwn);
2570063d642aSBill Gumbrell 					fcio.fcio_ibuf =
2571063d642aSBill Gumbrell 					    (caddr_t)&dlist->dev_pwwn;
2572063d642aSBill Gumbrell 					fcio.fcio_xfer = FCIO_XFER_WRITE;
2573063d642aSBill Gumbrell 					fcio.fcio_olen = fcio.fcio_alen = 0;
2574063d642aSBill Gumbrell 					fcio.fcio_obuf = fcio.fcio_abuf = NULL;
2575063d642aSBill Gumbrell 					if (g_issue_fcio_ioctl(fd, &fcio, 0) !=
2576063d642aSBill Gumbrell 					    0) {
2577063d642aSBill Gumbrell 
2578063d642aSBill Gumbrell 				/* Code refactorization is needed for C style */
2579fcf3ce44SJohn Forte 				I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
2580063d642aSBill Gumbrell 
2581fcf3ce44SJohn Forte 				if ((err = update_map_dev_FCP_prop(
2582fcf3ce44SJohn Forte 				    &impl_dev->prop_list, NULL,
2583fcf3ce44SJohn Forte 				    L_FCIO_DEV_LOGIN_FAIL,
2584fcf3ce44SJohn Forte 				    PROP_NOEXIST)) != 0) {
2585063d642aSBill Gumbrell 					(void) free(dev_list);
2586063d642aSBill Gumbrell 					(void) close(fd);
2587063d642aSBill Gumbrell 					g_dev_map_fini(impl_map);
2588063d642aSBill Gumbrell 					*l_err = err;
2589063d642aSBill Gumbrell 					return (NULL);
2590063d642aSBill Gumbrell 				}
2591063d642aSBill Gumbrell 
2592063d642aSBill Gumbrell 							/*
2593063d642aSBill Gumbrell 							 * plogi failed continue
2594063d642aSBill Gumbrell 							 * to next dev
2595063d642aSBill Gumbrell 							 */
2596063d642aSBill Gumbrell 							continue;
2597063d642aSBill Gumbrell 						}
2598063d642aSBill Gumbrell 					}
2599063d642aSBill Gumbrell 				}
2600063d642aSBill Gumbrell 				/* sbuf should be set from hba_port handling. */
2601063d642aSBill Gumbrell 				if ((err = handle_map_dev_FCP_prop(
2602063d642aSBill Gumbrell 				    minor(sbuf.st_rdev),
2603063d642aSBill Gumbrell 				    dlist->dev_pwwn, &impl_dev->prop_list)) !=
2604063d642aSBill Gumbrell 				    0) {
2605063d642aSBill Gumbrell 					(void) free(dev_list);
2606063d642aSBill Gumbrell 					(void) close(fd);
2607063d642aSBill Gumbrell 					g_dev_map_fini(impl_map);
2608063d642aSBill Gumbrell 					*l_err = err;
2609063d642aSBill Gumbrell 					return (NULL);
2610fcf3ce44SJohn Forte 				}
2611fcf3ce44SJohn Forte 			}
2612fcf3ce44SJohn Forte 		}
2613fcf3ce44SJohn Forte 		/* connect the children to to map.	*/
2614063d642aSBill Gumbrell 		impl_map->child = mdl_start;
2615063d642aSBill Gumbrell 		S_FREE(dev_list);
2616fcf3ce44SJohn Forte 
2617fcf3ce44SJohn Forte 	} else {	/* sf and fc4/pci devices */
2618063d642aSBill Gumbrell 		/* initialize map */
2619063d642aSBill Gumbrell 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
2620063d642aSBill Gumbrell 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
2621063d642aSBill Gumbrell 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
2622063d642aSBill Gumbrell 			(void) close(fd);
2623063d642aSBill Gumbrell 			*l_err = L_SFIOCGMAP_IOCTL_FAIL;
2624063d642aSBill Gumbrell 			return (NULL);
2625063d642aSBill Gumbrell 		}
2626fcf3ce44SJohn Forte 		/* Check for reasonableness. */
2627063d642aSBill Gumbrell 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
2628063d642aSBill Gumbrell 			(void) close(fd);
2629063d642aSBill Gumbrell 			*l_err = L_INVALID_LOOP_MAP;
2630063d642aSBill Gumbrell 			return (NULL);
2631063d642aSBill Gumbrell 		}
2632fcf3ce44SJohn Forte 
2633063d642aSBill Gumbrell 		if (sf_map.sf_count == 0) {
2634063d642aSBill Gumbrell 			(void) close(fd);
2635063d642aSBill Gumbrell 			*l_err = L_NO_DEVICES_FOUND;
2636063d642aSBill Gumbrell 			return (NULL);
2637063d642aSBill Gumbrell 		}
2638fcf3ce44SJohn Forte 
2639063d642aSBill Gumbrell 		if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) {
2640063d642aSBill Gumbrell 			(void) close(fd);
2641063d642aSBill Gumbrell 			*l_err = err;
2642063d642aSBill Gumbrell 			return (NULL);
2643063d642aSBill Gumbrell 		}
2644fcf3ce44SJohn Forte 
2645063d642aSBill Gumbrell 		if ((nexus_fd =
2646063d642aSBill Gumbrell 		    g_object_open(nexus_path, O_NDELAY | O_RDONLY)) == -1) {
2647063d642aSBill Gumbrell 			(void) close(fd);
2648063d642aSBill Gumbrell 			S_FREE(nexus_path);
2649063d642aSBill Gumbrell 			*l_err = errno;
2650063d642aSBill Gumbrell 			return (NULL);
2651063d642aSBill Gumbrell 		}
2652fcf3ce44SJohn Forte 
2653fcf3ce44SJohn Forte 		/* get limited map to get hba param info */
2654063d642aSBill Gumbrell 		if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) {
2655063d642aSBill Gumbrell 			I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
2656063d642aSBill Gumbrell 			(void) close(fd);
2657063d642aSBill Gumbrell 			(void) close(nexus_fd);
2658063d642aSBill Gumbrell 			S_FREE(nexus_path);
2659063d642aSBill Gumbrell 			*l_err = L_FCIO_GETMAP_IOCTL_FAIL;
2660063d642aSBill Gumbrell 			return (NULL);
2661063d642aSBill Gumbrell 		}
2662fcf3ce44SJohn Forte 		(void) close(nexus_fd);
2663fcf3ce44SJohn Forte 		S_FREE(nexus_path);
2664fcf3ce44SJohn Forte 
2665063d642aSBill Gumbrell 		for (i = 0; i < sf_map.sf_count; i++) {
2666063d642aSBill Gumbrell 			if (sf_map.sf_addr_pair[i].sf_al_pa ==
2667063d642aSBill Gumbrell 			    limited_map.lilp_myalpa) {
2668063d642aSBill Gumbrell 				sf_map.sf_hba_addr = sf_map.sf_addr_pair[i];
2669063d642aSBill Gumbrell 				hba_alpa_found = 1;
2670063d642aSBill Gumbrell 			}
2671fcf3ce44SJohn Forte 		}
2672fcf3ce44SJohn Forte 
2673063d642aSBill Gumbrell 		if (!(hba_alpa_found)) {
2674063d642aSBill Gumbrell 			(void) close(fd);
2675063d642aSBill Gumbrell 			*l_err = L_INVALID_LOOP_MAP;
2676063d642aSBill Gumbrell 			return (NULL);
2677063d642aSBill Gumbrell 		}
2678fcf3ce44SJohn Forte 
2679fcf3ce44SJohn Forte 		/* We have dev list info and host param info.	*/
2680fcf3ce44SJohn Forte 		/* Now constructs map tree with these info.	*/
2681fcf3ce44SJohn Forte 		/* First consturct the root of the map tree	*/
2682fcf3ce44SJohn Forte 		/* with host param.				*/
2683063d642aSBill Gumbrell 		if ((impl_map = (impl_map_dev_t *)calloc(
2684063d642aSBill Gumbrell 		    1, sizeof (impl_map_dev_t))) == NULL) {
2685063d642aSBill Gumbrell 			(void) close(fd);
2686063d642aSBill Gumbrell 			*l_err = L_MALLOC_FAILED;
2687063d642aSBill Gumbrell 			return (NULL);
2688063d642aSBill Gumbrell 		}
2689063d642aSBill Gumbrell 		impl_map->flag = flag;
2690063d642aSBill Gumbrell 		impl_map->topo = hba_port_top;
2691fcf3ce44SJohn Forte 
2692fcf3ce44SJohn Forte 		/* consturct hba property list.	*/
2693063d642aSBill Gumbrell 		if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2694fcf3ce44SJohn Forte 		    hba_port_top, sf_map.sf_hba_addr.sf_port_wwn,
2695fcf3ce44SJohn Forte 		    sf_map.sf_hba_addr.sf_node_wwn,
2696fcf3ce44SJohn Forte 		    (int)sf_map.sf_hba_addr.sf_al_pa,
2697fcf3ce44SJohn Forte 		    (int)sf_map.sf_hba_addr.sf_hard_address)) != 0) {
2698fcf3ce44SJohn Forte 			(void) close(fd);
2699fcf3ce44SJohn Forte 			g_dev_map_fini(impl_map);
2700fcf3ce44SJohn Forte 			*l_err = err;
2701fcf3ce44SJohn Forte 			return (NULL);
2702fcf3ce44SJohn Forte 		}
2703fcf3ce44SJohn Forte 
2704063d642aSBill Gumbrell 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2705063d642aSBill Gumbrell 			if ((err = update_map_dev_FCP_prop(&impl_map->prop_list,
2706063d642aSBill Gumbrell 			    &sf_map.sf_hba_addr.sf_inq_dtype, 0,
2707063d642aSBill Gumbrell 			    PROP_NOEXIST)) != 0) {
2708063d642aSBill Gumbrell 				(void) close(fd);
2709063d642aSBill Gumbrell 				g_dev_map_fini(impl_map);
2710063d642aSBill Gumbrell 				*l_err = err;
2711063d642aSBill Gumbrell 				return (NULL);
2712063d642aSBill Gumbrell 			}
2713063d642aSBill Gumbrell 		}
2714063d642aSBill Gumbrell 
2715063d642aSBill Gumbrell 		for (i = 0; i < sf_map.sf_count; i++) {
2716063d642aSBill Gumbrell 			if ((impl_dev = (impl_map_dev_t *)calloc(
2717063d642aSBill Gumbrell 			    1, sizeof (impl_map_dev_t))) == NULL) {
2718063d642aSBill Gumbrell 				(void) close(fd);
2719063d642aSBill Gumbrell 				g_dev_map_fini(impl_map);
2720063d642aSBill Gumbrell 				*l_err = L_MALLOC_FAILED;
2721063d642aSBill Gumbrell 				return (NULL);
2722063d642aSBill Gumbrell 			}
2723063d642aSBill Gumbrell 			/* set the map as parent */
2724063d642aSBill Gumbrell 			impl_dev->parent = impl_map;
2725063d642aSBill Gumbrell 			if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2726063d642aSBill Gumbrell 			    hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn,
2727063d642aSBill Gumbrell 			    sf_map.sf_addr_pair[i].sf_node_wwn,
2728063d642aSBill Gumbrell 			    (int)(sf_map.sf_addr_pair[i].sf_al_pa),
2729063d642aSBill Gumbrell 			    (int)(sf_map.sf_addr_pair[i].sf_hard_address))) !=
2730063d642aSBill Gumbrell 			    0) {
2731063d642aSBill Gumbrell 				(void) close(fd);
2732063d642aSBill Gumbrell 				g_dev_map_fini(impl_map);
2733063d642aSBill Gumbrell 				*l_err = err;
2734063d642aSBill Gumbrell 				return (NULL);
2735063d642aSBill Gumbrell 			}
2736063d642aSBill Gumbrell 			if (i == 0) {
2737063d642aSBill Gumbrell 				mdl_start = mdl_end = impl_dev;
2738063d642aSBill Gumbrell 			} else {
2739063d642aSBill Gumbrell 				mdl_end->next = impl_dev;
2740063d642aSBill Gumbrell 				mdl_end = impl_dev;
2741063d642aSBill Gumbrell 			}
2742063d642aSBill Gumbrell 			if ((flag & MAP_XPORT_PROP_ONLY) !=
2743063d642aSBill Gumbrell 			    MAP_XPORT_PROP_ONLY) {
2744063d642aSBill Gumbrell 				if ((err = update_map_dev_FCP_prop(
2745063d642aSBill Gumbrell 				    &impl_dev->prop_list,
2746063d642aSBill Gumbrell 				    &sf_map.sf_addr_pair[i].sf_inq_dtype, 0,
2747063d642aSBill Gumbrell 				    PROP_NOEXIST)) != 0) {
2748063d642aSBill Gumbrell 					(void) close(fd);
2749063d642aSBill Gumbrell 					g_dev_map_fini(impl_map);
2750063d642aSBill Gumbrell 					*l_err = err;
2751063d642aSBill Gumbrell 					return (NULL);
2752063d642aSBill Gumbrell 				}
2753063d642aSBill Gumbrell 			}
2754063d642aSBill Gumbrell 		} /* end of for loop */
2755063d642aSBill Gumbrell 
2756063d642aSBill Gumbrell 		impl_map->child = mdl_start;
2757fcf3ce44SJohn Forte 	} /* end of else */
2758fcf3ce44SJohn Forte 
2759fcf3ce44SJohn Forte 	close(fd);
2760fcf3ce44SJohn Forte 	return ((gfc_dev_t)(impl_map));
2761fcf3ce44SJohn Forte }
2762fcf3ce44SJohn Forte 
2763fcf3ce44SJohn Forte /*
2764fcf3ce44SJohn Forte  * This function deallocates memory for propery list.
2765fcf3ce44SJohn Forte  */
2766fcf3ce44SJohn Forte static void
free_prop_list(impl_map_dev_prop_t ** prop_list)2767fcf3ce44SJohn Forte free_prop_list(impl_map_dev_prop_t **prop_list)
2768fcf3ce44SJohn Forte {
2769fcf3ce44SJohn Forte 	impl_map_dev_prop_t *lp, *olp;
2770fcf3ce44SJohn Forte 
2771fcf3ce44SJohn Forte 	lp = *prop_list;
2772fcf3ce44SJohn Forte 	while (lp != NULL) {
2773fcf3ce44SJohn Forte 		switch (lp->prop_type) {
2774fcf3ce44SJohn Forte 		case GFC_PROP_TYPE_BYTES:
2775fcf3ce44SJohn Forte 			free((uchar_t *)(lp->prop_data));
2776fcf3ce44SJohn Forte 			break;
2777fcf3ce44SJohn Forte 		case GFC_PROP_TYPE_INT:
2778fcf3ce44SJohn Forte 			free((int *)(lp->prop_data));
2779fcf3ce44SJohn Forte 			break;
2780fcf3ce44SJohn Forte 		case GFC_PROP_TYPE_STRING:
2781fcf3ce44SJohn Forte 			free((char *)(lp->prop_data));
2782fcf3ce44SJohn Forte 			break;
2783fcf3ce44SJohn Forte 		default:
2784fcf3ce44SJohn Forte 			break;
2785fcf3ce44SJohn Forte 		}
2786fcf3ce44SJohn Forte 		lp->prop_data = NULL;
2787fcf3ce44SJohn Forte 		olp = lp;
2788fcf3ce44SJohn Forte 		lp = olp->next;
2789fcf3ce44SJohn Forte 		S_FREE(olp);
2790fcf3ce44SJohn Forte 	}
2791fcf3ce44SJohn Forte 
2792fcf3ce44SJohn Forte 	*prop_list = NULL;
2793fcf3ce44SJohn Forte }
2794fcf3ce44SJohn Forte 
2795fcf3ce44SJohn Forte /*
2796fcf3ce44SJohn Forte  * This function deallocates memory for children list.
2797fcf3ce44SJohn Forte  */
2798fcf3ce44SJohn Forte static void
free_child_list(impl_map_dev_t ** dev_list)2799fcf3ce44SJohn Forte free_child_list(impl_map_dev_t **dev_list)
2800fcf3ce44SJohn Forte {
2801fcf3ce44SJohn Forte 	impl_map_dev_t *lp, *olp;
2802fcf3ce44SJohn Forte 
2803fcf3ce44SJohn Forte 	lp = *dev_list;
2804fcf3ce44SJohn Forte 	while (lp != NULL) {
2805fcf3ce44SJohn Forte 		free_prop_list(&lp->prop_list);
2806fcf3ce44SJohn Forte 		olp = lp;
2807fcf3ce44SJohn Forte 		lp = olp->next;
2808fcf3ce44SJohn Forte 		S_FREE(olp);
2809fcf3ce44SJohn Forte 	}
2810fcf3ce44SJohn Forte 
2811fcf3ce44SJohn Forte 	*dev_list = NULL;
2812fcf3ce44SJohn Forte }
2813fcf3ce44SJohn Forte 
2814fcf3ce44SJohn Forte /*
2815fcf3ce44SJohn Forte  * This function deallocates memory for the whole map.
2816fcf3ce44SJohn Forte  */
2817fcf3ce44SJohn Forte void
g_dev_map_fini(gfc_dev_t map)2818fcf3ce44SJohn Forte g_dev_map_fini(gfc_dev_t map)
2819fcf3ce44SJohn Forte {
2820fcf3ce44SJohn Forte 	impl_map_dev_t *impl_map;
2821fcf3ce44SJohn Forte 
2822fcf3ce44SJohn Forte 	impl_map = (impl_map_dev_t *)map;
2823fcf3ce44SJohn Forte 
2824fcf3ce44SJohn Forte 	if (impl_map != NULL) {
2825063d642aSBill Gumbrell 		free_prop_list(&impl_map->prop_list);
2826063d642aSBill Gumbrell 		free_child_list(&impl_map->child);
2827063d642aSBill Gumbrell 		S_FREE(impl_map);
2828fcf3ce44SJohn Forte 	}
2829fcf3ce44SJohn Forte }
2830fcf3ce44SJohn Forte 
2831fcf3ce44SJohn Forte /*
2832fcf3ce44SJohn Forte  * This function passes back topology of the input map.
2833fcf3ce44SJohn Forte  * input should be a handle form g_dev_map_init().
2834fcf3ce44SJohn Forte  *
2835fcf3ce44SJohn Forte  * return 0 if OK.
2836fcf3ce44SJohn Forte  * return error code otherwise.
2837fcf3ce44SJohn Forte  */
2838fcf3ce44SJohn Forte int
g_get_map_topology(gfc_dev_t map,uint_t * topology)2839063d642aSBill Gumbrell g_get_map_topology(gfc_dev_t map, uint_t *topology)
2840fcf3ce44SJohn Forte {
2841fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_map;
2842fcf3ce44SJohn Forte 
2843fcf3ce44SJohn Forte 	if (map == NULL) {
2844fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2845fcf3ce44SJohn Forte 	}
2846fcf3ce44SJohn Forte 
2847fcf3ce44SJohn Forte 	if (topology == NULL) {
2848fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
2849fcf3ce44SJohn Forte 	}
2850fcf3ce44SJohn Forte 
2851fcf3ce44SJohn Forte 	impl_map = (impl_map_dev_t *)map;
2852fcf3ce44SJohn Forte 
2853fcf3ce44SJohn Forte 	*topology = impl_map->topo;
2854fcf3ce44SJohn Forte 
2855fcf3ce44SJohn Forte 	return (0);
2856fcf3ce44SJohn Forte }
2857fcf3ce44SJohn Forte 
2858fcf3ce44SJohn Forte /*
2859fcf3ce44SJohn Forte  * This function returns the first device handle of the input map.
2860fcf3ce44SJohn Forte  * map input should be a handle form g_dev_map_init().
2861fcf3ce44SJohn Forte  *
2862fcf3ce44SJohn Forte  * l_err set to 0 if OK.
2863fcf3ce44SJohn Forte  * l_err set to error code otherwise.
2864fcf3ce44SJohn Forte  */
2865fcf3ce44SJohn Forte gfc_dev_t
g_get_first_dev(gfc_dev_t map,int * l_err)2866063d642aSBill Gumbrell g_get_first_dev(gfc_dev_t map, int *l_err)
2867fcf3ce44SJohn Forte {
2868fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_map;
2869fcf3ce44SJohn Forte 
2870fcf3ce44SJohn Forte 	if (l_err == NULL) {
2871fcf3ce44SJohn Forte 		return (NULL);
2872fcf3ce44SJohn Forte 	}
2873fcf3ce44SJohn Forte 
2874fcf3ce44SJohn Forte 	*l_err = 0;
2875fcf3ce44SJohn Forte 
2876fcf3ce44SJohn Forte 	if (map == NULL) {
2877fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_ADDR;
2878fcf3ce44SJohn Forte 		return (NULL);
2879fcf3ce44SJohn Forte 	}
2880fcf3ce44SJohn Forte 
2881fcf3ce44SJohn Forte 	impl_map = (impl_map_dev_t *)map;
2882fcf3ce44SJohn Forte 
2883fcf3ce44SJohn Forte 	if (impl_map->child == NULL) {
2884fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_DEV_FOUND;
2885fcf3ce44SJohn Forte 	}
2886fcf3ce44SJohn Forte 
2887fcf3ce44SJohn Forte 	return ((gfc_dev_t)(impl_map->child));
2888fcf3ce44SJohn Forte }
2889fcf3ce44SJohn Forte 
2890fcf3ce44SJohn Forte /*
2891fcf3ce44SJohn Forte  * This function returns the next device handle of the input map.
2892fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2893fcf3ce44SJohn Forte  *
2894fcf3ce44SJohn Forte  * l_err set to 0 if OK.
2895fcf3ce44SJohn Forte  * l_err set to error code otherwise.
2896fcf3ce44SJohn Forte  */
2897fcf3ce44SJohn Forte gfc_dev_t
g_get_next_dev(gfc_dev_t map_dev,int * l_err)2898063d642aSBill Gumbrell g_get_next_dev(gfc_dev_t map_dev, int *l_err)
2899fcf3ce44SJohn Forte {
2900fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_dev;
2901fcf3ce44SJohn Forte 
2902fcf3ce44SJohn Forte 	if (l_err == NULL) {
2903fcf3ce44SJohn Forte 		return (NULL);
2904fcf3ce44SJohn Forte 	}
2905fcf3ce44SJohn Forte 
2906fcf3ce44SJohn Forte 	*l_err = 0;
2907fcf3ce44SJohn Forte 
2908fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2909fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_ADDR;
2910fcf3ce44SJohn Forte 		return (NULL);
2911fcf3ce44SJohn Forte 	}
2912fcf3ce44SJohn Forte 
2913fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
2914fcf3ce44SJohn Forte 
2915fcf3ce44SJohn Forte 	if (impl_dev->next == NULL) {
2916fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_DEV_FOUND;
2917fcf3ce44SJohn Forte 	}
2918fcf3ce44SJohn Forte 
2919fcf3ce44SJohn Forte 	return ((gfc_dev_t)(impl_dev->next));
2920fcf3ce44SJohn Forte }
2921fcf3ce44SJohn Forte 
2922fcf3ce44SJohn Forte /*
2923fcf3ce44SJohn Forte  * This function passes back uchar_t type property and its count.
2924fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2925fcf3ce44SJohn Forte  *
2926fcf3ce44SJohn Forte  * return 0 if OK.
2927fcf3ce44SJohn Forte  * return error code otherwise.
2928fcf3ce44SJohn Forte  */
2929fcf3ce44SJohn Forte int
g_dev_prop_lookup_bytes(gfc_dev_t map_dev,const char * prop_name,int * prop_data_count,uchar_t ** prop_data)2930063d642aSBill Gumbrell g_dev_prop_lookup_bytes(gfc_dev_t map_dev, const char *prop_name,
2931063d642aSBill Gumbrell     int *prop_data_count, uchar_t **prop_data)
2932fcf3ce44SJohn Forte {
2933fcf3ce44SJohn Forte 	impl_map_dev_t *impl_dev;
2934fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
2935fcf3ce44SJohn Forte 	int err;
2936fcf3ce44SJohn Forte 
2937fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2938fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2939fcf3ce44SJohn Forte 	}
2940fcf3ce44SJohn Forte 
2941fcf3ce44SJohn Forte 	if ((prop_name == NULL) || (prop_data == NULL) ||
2942063d642aSBill Gumbrell 	    (prop_data_count == NULL)) {
2943fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
2944fcf3ce44SJohn Forte 	}
2945fcf3ce44SJohn Forte 
2946fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
2947fcf3ce44SJohn Forte 	impl_prop = impl_dev->prop_list;
2948fcf3ce44SJohn Forte 
2949fcf3ce44SJohn Forte 	err = L_INVALID_MAP_DEV_PROP_NAME;
2950fcf3ce44SJohn Forte 
2951fcf3ce44SJohn Forte 	while (impl_prop) {
2952063d642aSBill Gumbrell 		if (strncmp(impl_prop->prop_name, prop_name,
2953063d642aSBill Gumbrell 		    strlen(prop_name)) == 0) {
2954063d642aSBill Gumbrell 			if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
2955063d642aSBill Gumbrell 				err = L_INVALID_MAP_DEV_PROP_TYPE;
2956063d642aSBill Gumbrell 				break;
2957063d642aSBill Gumbrell 			}
2958063d642aSBill Gumbrell 			if (impl_prop->prop_data) {
2959063d642aSBill Gumbrell 				*prop_data = (uchar_t *)(impl_prop->prop_data);
2960063d642aSBill Gumbrell 				*prop_data_count = impl_prop->prop_size;
2961063d642aSBill Gumbrell 				return (0);
2962063d642aSBill Gumbrell 			} else {
2963063d642aSBill Gumbrell 				err = impl_prop->prop_error;
2964063d642aSBill Gumbrell 			}
2965063d642aSBill Gumbrell 			break;
2966fcf3ce44SJohn Forte 		}
2967063d642aSBill Gumbrell 		impl_prop = impl_prop->next;
2968fcf3ce44SJohn Forte 	}
2969fcf3ce44SJohn Forte 
2970fcf3ce44SJohn Forte 	return (err);
2971fcf3ce44SJohn Forte }
2972fcf3ce44SJohn Forte 
2973fcf3ce44SJohn Forte /*
2974fcf3ce44SJohn Forte  * This function passes back int type property.
2975fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
2976fcf3ce44SJohn Forte  *
2977fcf3ce44SJohn Forte  * return 0 if OK.
2978fcf3ce44SJohn Forte  * return error code otherwise.
2979fcf3ce44SJohn Forte  */
2980fcf3ce44SJohn Forte int
g_dev_prop_lookup_ints(gfc_dev_t map_dev,const char * prop_name,int ** prop_data)2981063d642aSBill Gumbrell g_dev_prop_lookup_ints(gfc_dev_t map_dev, const char *prop_name,
2982063d642aSBill Gumbrell     int **prop_data)
2983fcf3ce44SJohn Forte {
2984fcf3ce44SJohn Forte 	impl_map_dev_t *impl_dev;
2985fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
2986fcf3ce44SJohn Forte 	int err;
2987fcf3ce44SJohn Forte 
2988fcf3ce44SJohn Forte 	if (map_dev == NULL) {
2989fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
2990fcf3ce44SJohn Forte 	}
2991fcf3ce44SJohn Forte 
2992fcf3ce44SJohn Forte 	if ((prop_name == NULL) || (prop_data == NULL)) {
2993fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
2994fcf3ce44SJohn Forte 	}
2995fcf3ce44SJohn Forte 
2996fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
2997fcf3ce44SJohn Forte 	impl_prop = impl_dev->prop_list;
2998fcf3ce44SJohn Forte 
2999fcf3ce44SJohn Forte 	err = L_INVALID_MAP_DEV_PROP_NAME;
3000fcf3ce44SJohn Forte 
3001fcf3ce44SJohn Forte 	while (impl_prop) {
3002063d642aSBill Gumbrell 		if (strncmp(impl_prop->prop_name, prop_name,
3003063d642aSBill Gumbrell 		    strlen(prop_name)) == 0) {
3004063d642aSBill Gumbrell 			if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3005063d642aSBill Gumbrell 			err = L_INVALID_MAP_DEV_PROP_TYPE;
3006063d642aSBill Gumbrell 			break;
3007063d642aSBill Gumbrell 			}
3008063d642aSBill Gumbrell 			if (impl_prop->prop_data) {
3009063d642aSBill Gumbrell 				*prop_data = (int *)(impl_prop->prop_data);
3010063d642aSBill Gumbrell 				return (0);
3011063d642aSBill Gumbrell 			} else {
3012063d642aSBill Gumbrell 				err = impl_prop->prop_error;
3013063d642aSBill Gumbrell 			}
3014063d642aSBill Gumbrell 			break;
3015fcf3ce44SJohn Forte 		}
3016063d642aSBill Gumbrell 		impl_prop = impl_prop->next;
3017fcf3ce44SJohn Forte 	}
3018fcf3ce44SJohn Forte 
3019fcf3ce44SJohn Forte 	return (err);
3020fcf3ce44SJohn Forte }
3021fcf3ce44SJohn Forte 
3022fcf3ce44SJohn Forte /*
3023fcf3ce44SJohn Forte  * This function passes back int type property.
3024fcf3ce44SJohn Forte  * map_dev input should be a handle for device.
3025fcf3ce44SJohn Forte  *
3026fcf3ce44SJohn Forte  * return 0 if OK.
3027fcf3ce44SJohn Forte  * return error code otherwise.
3028fcf3ce44SJohn Forte  */
3029fcf3ce44SJohn Forte int
g_dev_prop_lookup_strings(gfc_dev_t map_dev,const char * prop_name,char ** prop_data)3030063d642aSBill Gumbrell g_dev_prop_lookup_strings(gfc_dev_t map_dev, const char *prop_name,
3031063d642aSBill Gumbrell     char **prop_data)
3032fcf3ce44SJohn Forte {
3033fcf3ce44SJohn Forte 	impl_map_dev_t *impl_dev;
3034fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3035fcf3ce44SJohn Forte 	int err;
3036fcf3ce44SJohn Forte 
3037fcf3ce44SJohn Forte 	if (map_dev == NULL) {
3038fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3039fcf3ce44SJohn Forte 	}
3040fcf3ce44SJohn Forte 
3041fcf3ce44SJohn Forte 	if ((prop_name == NULL) || (prop_data == NULL)) {
3042fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3043fcf3ce44SJohn Forte 	}
3044fcf3ce44SJohn Forte 
3045fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
3046fcf3ce44SJohn Forte 	impl_prop = impl_dev->prop_list;
3047fcf3ce44SJohn Forte 
3048fcf3ce44SJohn Forte 	err = L_INVALID_MAP_DEV_PROP_NAME;
3049fcf3ce44SJohn Forte 
3050fcf3ce44SJohn Forte 	while (impl_prop) {
3051063d642aSBill Gumbrell 		if (strncmp(impl_prop->prop_name, prop_name,
3052063d642aSBill Gumbrell 		    strlen(prop_name)) == 0) {
3053063d642aSBill Gumbrell 			if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3054063d642aSBill Gumbrell 				err = L_INVALID_MAP_DEV_PROP_TYPE;
3055063d642aSBill Gumbrell 				break;
3056063d642aSBill Gumbrell 			}
3057063d642aSBill Gumbrell 			if (impl_prop->prop_data) {
3058063d642aSBill Gumbrell 				*prop_data = (char *)(impl_prop->prop_data);
3059063d642aSBill Gumbrell 				return (0);
3060063d642aSBill Gumbrell 			} else {
3061063d642aSBill Gumbrell 				err = impl_prop->prop_error;
3062063d642aSBill Gumbrell 			}
3063063d642aSBill Gumbrell 			break;
3064fcf3ce44SJohn Forte 		}
3065063d642aSBill Gumbrell 		impl_prop = impl_prop->next;
3066fcf3ce44SJohn Forte 	}
3067fcf3ce44SJohn Forte 
3068fcf3ce44SJohn Forte 	return (err);
3069fcf3ce44SJohn Forte }
3070fcf3ce44SJohn Forte 
3071fcf3ce44SJohn Forte /*
3072fcf3ce44SJohn Forte  * This function returns the handle for the first property of the input device.
3073fcf3ce44SJohn Forte  * map_dev input should be a handle form a device.
3074fcf3ce44SJohn Forte  *
3075fcf3ce44SJohn Forte  * l_err set to 0 if OK.
3076fcf3ce44SJohn Forte  * l_err set to error code otherwise.
3077fcf3ce44SJohn Forte  */
3078fcf3ce44SJohn Forte gfc_prop_t
g_get_first_dev_prop(gfc_dev_t map_dev,int * l_err)3079063d642aSBill Gumbrell g_get_first_dev_prop(gfc_dev_t map_dev, int *l_err)
3080fcf3ce44SJohn Forte {
3081fcf3ce44SJohn Forte 	impl_map_dev_t	*impl_dev;
3082fcf3ce44SJohn Forte 
3083fcf3ce44SJohn Forte 	if (l_err == NULL) {
3084fcf3ce44SJohn Forte 		return (NULL);
3085fcf3ce44SJohn Forte 	}
3086fcf3ce44SJohn Forte 
3087fcf3ce44SJohn Forte 	*l_err = 0;
3088fcf3ce44SJohn Forte 
3089fcf3ce44SJohn Forte 	if (map_dev == NULL) {
3090fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_ADDR;
3091fcf3ce44SJohn Forte 		return (NULL);
3092fcf3ce44SJohn Forte 	}
3093fcf3ce44SJohn Forte 
3094fcf3ce44SJohn Forte 	impl_dev = (impl_map_dev_t *)map_dev;
3095fcf3ce44SJohn Forte 
3096fcf3ce44SJohn Forte 	if (impl_dev->prop_list == NULL) {
3097fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_PROP_FOUND;
3098fcf3ce44SJohn Forte 	}
3099fcf3ce44SJohn Forte 
3100fcf3ce44SJohn Forte 	return ((gfc_prop_t)(impl_dev->prop_list));
3101fcf3ce44SJohn Forte }
3102fcf3ce44SJohn Forte 
3103fcf3ce44SJohn Forte /*
3104fcf3ce44SJohn Forte  * This function returns the handle for next property handle of the input prop.
3105fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3106fcf3ce44SJohn Forte  *
3107fcf3ce44SJohn Forte  * l_err set to 0 if OK.
3108fcf3ce44SJohn Forte  * l_err set to error code otherwise.
3109fcf3ce44SJohn Forte  */
3110fcf3ce44SJohn Forte gfc_prop_t
g_get_next_dev_prop(gfc_prop_t map_prop,int * l_err)3111063d642aSBill Gumbrell g_get_next_dev_prop(gfc_prop_t map_prop, int *l_err)
3112fcf3ce44SJohn Forte {
3113fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*impl_prop;
3114fcf3ce44SJohn Forte 
3115fcf3ce44SJohn Forte 	if (l_err == NULL) {
3116fcf3ce44SJohn Forte 		return (NULL);
3117fcf3ce44SJohn Forte 	}
3118fcf3ce44SJohn Forte 
3119fcf3ce44SJohn Forte 	*l_err = 0;
3120fcf3ce44SJohn Forte 
3121fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3122fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_PROP;
3123fcf3ce44SJohn Forte 		return (NULL);
3124fcf3ce44SJohn Forte 	}
3125fcf3ce44SJohn Forte 
3126fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3127fcf3ce44SJohn Forte 
3128fcf3ce44SJohn Forte 	if (impl_prop->next == NULL) {
3129fcf3ce44SJohn Forte 		*l_err = L_NO_SUCH_PROP_FOUND;
3130fcf3ce44SJohn Forte 	}
3131fcf3ce44SJohn Forte 
3132fcf3ce44SJohn Forte 	return ((gfc_prop_t)(impl_prop->next));
3133fcf3ce44SJohn Forte }
3134fcf3ce44SJohn Forte 
3135fcf3ce44SJohn Forte /*
3136fcf3ce44SJohn Forte  * This function returns the name of the property of the input prop.
3137fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3138fcf3ce44SJohn Forte  *
3139fcf3ce44SJohn Forte  * return name string if OK.
3140fcf3ce44SJohn Forte  * returns NULL and l_err set to error code otherwise.
3141fcf3ce44SJohn Forte  */
3142fcf3ce44SJohn Forte char *
g_get_dev_prop_name(gfc_prop_t map_prop,int * l_err)3143063d642aSBill Gumbrell g_get_dev_prop_name(gfc_prop_t map_prop, int *l_err)
3144fcf3ce44SJohn Forte {
3145fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*impl_prop;
3146fcf3ce44SJohn Forte 
3147fcf3ce44SJohn Forte 	if (l_err == NULL) {
3148fcf3ce44SJohn Forte 		return (NULL);
3149fcf3ce44SJohn Forte 	}
3150fcf3ce44SJohn Forte 
3151fcf3ce44SJohn Forte 	*l_err = 0;
3152fcf3ce44SJohn Forte 
3153fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3154fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_PROP;
3155fcf3ce44SJohn Forte 		return (NULL);
3156fcf3ce44SJohn Forte 	}
3157fcf3ce44SJohn Forte 
3158fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3159fcf3ce44SJohn Forte 
3160fcf3ce44SJohn Forte 	return (impl_prop->prop_name);
3161fcf3ce44SJohn Forte }
3162fcf3ce44SJohn Forte 
3163fcf3ce44SJohn Forte /*
3164fcf3ce44SJohn Forte  * This function returns the type of the property of the input prop.
3165fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3166fcf3ce44SJohn Forte  *
3167fcf3ce44SJohn Forte  * return type if OK.
3168fcf3ce44SJohn Forte  * returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise.
3169fcf3ce44SJohn Forte  */
3170fcf3ce44SJohn Forte int
g_get_dev_prop_type(gfc_prop_t map_prop,int * l_err)3171063d642aSBill Gumbrell g_get_dev_prop_type(gfc_prop_t map_prop, int *l_err)
3172fcf3ce44SJohn Forte {
3173fcf3ce44SJohn Forte 	impl_map_dev_prop_t	*impl_prop;
3174fcf3ce44SJohn Forte 
3175fcf3ce44SJohn Forte 	if (l_err != NULL) {
3176fcf3ce44SJohn Forte 		*l_err = 0;
3177fcf3ce44SJohn Forte 	} else {
3178fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3179fcf3ce44SJohn Forte 	}
3180fcf3ce44SJohn Forte 
3181fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3182fcf3ce44SJohn Forte 		*l_err = L_INVALID_MAP_DEV_PROP;
3183fcf3ce44SJohn Forte 		return (GFC_PROP_TYPE_UNKNOWN);
3184fcf3ce44SJohn Forte 	}
3185fcf3ce44SJohn Forte 
3186fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3187fcf3ce44SJohn Forte 
3188fcf3ce44SJohn Forte 	return (impl_prop->prop_type);
3189fcf3ce44SJohn Forte }
3190fcf3ce44SJohn Forte 
3191fcf3ce44SJohn Forte /*
3192fcf3ce44SJohn Forte  * This function passes back uchar_t type property and its count.
3193fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3194fcf3ce44SJohn Forte  *
3195fcf3ce44SJohn Forte  * return 0 if OK.
3196fcf3ce44SJohn Forte  * return error code otherwise.
3197fcf3ce44SJohn Forte  */
3198fcf3ce44SJohn Forte int
g_get_dev_prop_bytes(gfc_prop_t map_prop,int * prop_data_count,uchar_t ** prop_data)3199063d642aSBill Gumbrell g_get_dev_prop_bytes(gfc_prop_t map_prop, int *prop_data_count,
3200063d642aSBill Gumbrell     uchar_t **prop_data)
3201fcf3ce44SJohn Forte {
3202fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3203fcf3ce44SJohn Forte 
3204fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3205fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3206fcf3ce44SJohn Forte 	}
3207fcf3ce44SJohn Forte 
3208fcf3ce44SJohn Forte 	if ((prop_data == NULL) || (prop_data_count == NULL)) {
3209fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3210fcf3ce44SJohn Forte 	}
3211fcf3ce44SJohn Forte 
3212fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3213fcf3ce44SJohn Forte 
3214fcf3ce44SJohn Forte 	if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
3215063d642aSBill Gumbrell 		return (L_INVALID_MAP_DEV_PROP_TYPE);
3216fcf3ce44SJohn Forte 	}
3217fcf3ce44SJohn Forte 	if (impl_prop->prop_data) {
3218063d642aSBill Gumbrell 		*prop_data = (uchar_t *)(impl_prop->prop_data);
3219063d642aSBill Gumbrell 		*prop_data_count = impl_prop->prop_size;
3220fcf3ce44SJohn Forte 	} else {
3221063d642aSBill Gumbrell 		return (impl_prop->prop_error);
3222fcf3ce44SJohn Forte 	}
3223fcf3ce44SJohn Forte 
3224fcf3ce44SJohn Forte 	return (0);
3225fcf3ce44SJohn Forte }
3226fcf3ce44SJohn Forte 
3227fcf3ce44SJohn Forte /*
3228fcf3ce44SJohn Forte  * This function passes back int type property.
3229fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3230fcf3ce44SJohn Forte  *
3231fcf3ce44SJohn Forte  * return 0 if OK.
3232fcf3ce44SJohn Forte  * return error code otherwise.
3233fcf3ce44SJohn Forte  */
3234fcf3ce44SJohn Forte int
g_get_dev_prop_ints(gfc_prop_t map_prop,int ** prop_data)3235063d642aSBill Gumbrell g_get_dev_prop_ints(gfc_prop_t map_prop, int **prop_data)
3236fcf3ce44SJohn Forte {
3237fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3238fcf3ce44SJohn Forte 
3239fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3240fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3241fcf3ce44SJohn Forte 	}
3242fcf3ce44SJohn Forte 
3243fcf3ce44SJohn Forte 	if (prop_data == NULL) {
3244fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3245fcf3ce44SJohn Forte 	}
3246fcf3ce44SJohn Forte 
3247fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3248fcf3ce44SJohn Forte 
3249fcf3ce44SJohn Forte 	if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3250063d642aSBill Gumbrell 		return (L_INVALID_MAP_DEV_PROP_TYPE);
3251fcf3ce44SJohn Forte 	}
3252fcf3ce44SJohn Forte 	if (impl_prop->prop_data) {
3253063d642aSBill Gumbrell 		*prop_data = (int *)(impl_prop->prop_data);
3254fcf3ce44SJohn Forte 	} else {
3255063d642aSBill Gumbrell 		return (impl_prop->prop_error);
3256fcf3ce44SJohn Forte 	}
3257fcf3ce44SJohn Forte 
3258fcf3ce44SJohn Forte 	return (0);
3259fcf3ce44SJohn Forte }
3260fcf3ce44SJohn Forte 
3261fcf3ce44SJohn Forte /*
3262fcf3ce44SJohn Forte  * This function passes back string type property.
3263fcf3ce44SJohn Forte  * map_prop input should be a handle for property.
3264fcf3ce44SJohn Forte  *
3265fcf3ce44SJohn Forte  * return 0 if OK.
3266fcf3ce44SJohn Forte  * return error code otherwise.
3267fcf3ce44SJohn Forte  */
3268fcf3ce44SJohn Forte int
g_get_dev_prop_strings(gfc_prop_t map_prop,char ** prop_data)3269063d642aSBill Gumbrell g_get_dev_prop_strings(gfc_prop_t map_prop, char **prop_data)
3270fcf3ce44SJohn Forte {
3271fcf3ce44SJohn Forte 	impl_map_dev_prop_t *impl_prop;
3272fcf3ce44SJohn Forte 
3273fcf3ce44SJohn Forte 	if (map_prop == NULL) {
3274fcf3ce44SJohn Forte 		return (L_INVALID_MAP_DEV_ADDR);
3275fcf3ce44SJohn Forte 	}
3276fcf3ce44SJohn Forte 
3277fcf3ce44SJohn Forte 	if (prop_data == NULL) {
3278fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3279fcf3ce44SJohn Forte 	}
3280fcf3ce44SJohn Forte 
3281fcf3ce44SJohn Forte 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3282fcf3ce44SJohn Forte 
3283fcf3ce44SJohn Forte 	if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3284063d642aSBill Gumbrell 		return (L_INVALID_MAP_DEV_PROP_TYPE);
3285fcf3ce44SJohn Forte 	}
3286fcf3ce44SJohn Forte 	if (impl_prop->prop_data) {
3287063d642aSBill Gumbrell 		*prop_data = (char *)(impl_prop->prop_data);
3288fcf3ce44SJohn Forte 	} else {
3289063d642aSBill Gumbrell 		return (impl_prop->prop_error);
3290fcf3ce44SJohn Forte 	}
3291fcf3ce44SJohn Forte 
3292fcf3ce44SJohn Forte 	return (0);
3293fcf3ce44SJohn Forte }
3294fcf3ce44SJohn Forte 
3295fcf3ce44SJohn Forte /*
3296fcf3ce44SJohn Forte  * Free the linked list allocated by g_rdls()
3297fcf3ce44SJohn Forte  */
3298fcf3ce44SJohn Forte static void
g_free_rls(AL_rls * rlsptr)3299fcf3ce44SJohn Forte g_free_rls(AL_rls *rlsptr)
3300fcf3ce44SJohn Forte {
3301fcf3ce44SJohn Forte 	AL_rls *trlsptr;
3302fcf3ce44SJohn Forte 
3303fcf3ce44SJohn Forte 	while (rlsptr != NULL) {
3304fcf3ce44SJohn Forte 		trlsptr = rlsptr->next;
3305fcf3ce44SJohn Forte 		free(rlsptr);
3306fcf3ce44SJohn Forte 		rlsptr = trlsptr;
3307fcf3ce44SJohn Forte 	}
3308fcf3ce44SJohn Forte }
3309fcf3ce44SJohn Forte 
3310fcf3ce44SJohn Forte /*
3311fcf3ce44SJohn Forte  * Read the extended link error status block
3312fcf3ce44SJohn Forte  * from the specified device and Host Adapter.
3313fcf3ce44SJohn Forte  *
3314fcf3ce44SJohn Forte  * PARAMS:
3315fcf3ce44SJohn Forte  *	path_phys - physical path to an FC device
3316fcf3ce44SJohn Forte  *	rls_ptr   - pointer to read link state structure
3317fcf3ce44SJohn Forte  *
3318fcf3ce44SJohn Forte  * RETURNS:
3319fcf3ce44SJohn Forte  *	0	: if OK
3320fcf3ce44SJohn Forte  *	non-zero: otherwise
3321fcf3ce44SJohn Forte  */
3322fcf3ce44SJohn Forte int
g_rdls(char * path_phys,struct al_rls ** rls_ptr,int verbose)3323fcf3ce44SJohn Forte g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose)
3324fcf3ce44SJohn Forte {
3325063d642aSBill Gumbrell 	char		nexus_path[MAXPATHLEN], *nexus_path_ptr;
3326063d642aSBill Gumbrell 	int		fd, fp_fd, err, length, exp_map_flag = 0, *port_addr;
3327063d642aSBill Gumbrell 	struct lilpmap	map;
3328063d642aSBill Gumbrell 	AL_rls		*rls, *c1 = NULL, *c2 = NULL;
3329063d642aSBill Gumbrell 	uchar_t		i, *port_wwn_byte;
3330063d642aSBill Gumbrell 	la_wwn_t	port_wwn;
3331063d642aSBill Gumbrell 	sf_al_map_t	exp_map;
3332063d642aSBill Gumbrell 	char		*charPtr, fp_path[MAXPATHLEN];
3333063d642aSBill Gumbrell 	uint_t		dev_type;
3334063d642aSBill Gumbrell 	struct stat	stbuf;
3335063d642aSBill Gumbrell 	fcio_t		fcio;
3336063d642aSBill Gumbrell 	fc_portid_t	rls_req;
3337063d642aSBill Gumbrell 	fc_rls_acc_t	rls_payload;
3338063d642aSBill Gumbrell 	gfc_dev_t	map_root, map_dev;
3339063d642aSBill Gumbrell 	uint32_t	hba_port_top, state;
3340063d642aSBill Gumbrell 	int		pathcnt = 1, count;
3341063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
3342063d642aSBill Gumbrell 	int		p_on = 0, p_st = 0;
3343fcf3ce44SJohn Forte 
3344fcf3ce44SJohn Forte 	/* return invalid path if path_phys is NULL */
3345fcf3ce44SJohn Forte 	if (path_phys == NULL) {
3346fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3347fcf3ce44SJohn Forte 	}
3348fcf3ce44SJohn Forte 	/* return invalid arg if rls_ptr is NULL */
3349fcf3ce44SJohn Forte 	if (rls_ptr == NULL) {
3350fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3351fcf3ce44SJohn Forte 	}
3352fcf3ce44SJohn Forte 
3353fcf3ce44SJohn Forte 	*rls_ptr = rls = NULL;
3354fcf3ce44SJohn Forte 
3355fcf3ce44SJohn Forte 	if (strstr(path_phys, SCSI_VHCI) != NULL) {
3356fcf3ce44SJohn Forte 		(void) strcpy(fp_path, path_phys);
3357fcf3ce44SJohn Forte 		if (g_get_pathlist(fp_path, &pathlist)) {
3358fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
3359fcf3ce44SJohn Forte 		}
3360fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
3361fcf3ce44SJohn Forte 		p_on = p_st = 0;
3362fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
3363fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3364fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
3365063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_ONLINE) {
3366fcf3ce44SJohn Forte 					p_on = i;
3367fcf3ce44SJohn Forte 					break;
3368fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
3369063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_STANDBY) {
3370fcf3ce44SJohn Forte 					p_st = i;
3371fcf3ce44SJohn Forte 				}
3372fcf3ce44SJohn Forte 			}
3373fcf3ce44SJohn Forte 		}
3374fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
3375fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
3376fcf3ce44SJohn Forte 			/* on_line path */
3377fcf3ce44SJohn Forte 			(void) strcpy(fp_path,
3378063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_hba);
3379fcf3ce44SJohn Forte 		} else {
3380fcf3ce44SJohn Forte 			/* standby or path0 */
3381fcf3ce44SJohn Forte 			(void) strcpy(fp_path,
3382063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_hba);
3383fcf3ce44SJohn Forte 		}
3384fcf3ce44SJohn Forte 		free(pathlist.path_info);
3385fcf3ce44SJohn Forte 	} else {
3386fcf3ce44SJohn Forte 		(void) strcpy(fp_path, path_phys);
3387fcf3ce44SJohn Forte 	}
3388fcf3ce44SJohn Forte 
3389fcf3ce44SJohn Forte 	/* Get map of devices on this loop. */
3390fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(fp_path)) == 0) {
3391fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3392fcf3ce44SJohn Forte 	}
3393fcf3ce44SJohn Forte 	if (dev_type & FC_FCA_MASK) {
3394fcf3ce44SJohn Forte 		if (strstr(path_phys, SCSI_VHCI) != NULL) {
3395fcf3ce44SJohn Forte 			(void) strcat(fp_path, FC_CTLR);
3396fcf3ce44SJohn Forte 		} else if (strstr(fp_path, DRV_NAME_SSD) ||
3397fcf3ce44SJohn Forte 		    strstr(fp_path, DRV_NAME_ST) ||
3398063d642aSBill Gumbrell 		    strstr(fp_path, SES_NAME)) {
3399fcf3ce44SJohn Forte 			if ((charPtr = strrchr(fp_path, '/')) == NULL) {
3400fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
3401fcf3ce44SJohn Forte 			}
3402fcf3ce44SJohn Forte 			*charPtr = '\0';
3403fcf3ce44SJohn Forte 			/* append devctl to the path */
3404fcf3ce44SJohn Forte 			(void) strcat(fp_path, FC_CTLR);
3405fcf3ce44SJohn Forte 		} else {
3406fcf3ce44SJohn Forte 			if (stat(fp_path, &stbuf) < 0) {
3407fcf3ce44SJohn Forte 				return (L_LSTAT_ERROR);
3408fcf3ce44SJohn Forte 			}
3409fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
3410fcf3ce44SJohn Forte 				/* append devctl to the path */
3411fcf3ce44SJohn Forte 				(void) strcat(fp_path, FC_CTLR);
3412fcf3ce44SJohn Forte 			}
3413fcf3ce44SJohn Forte 		}
3414fcf3ce44SJohn Forte 
3415fcf3ce44SJohn Forte 		if ((map_root = g_dev_map_init(fp_path, &err,
3416063d642aSBill Gumbrell 		    MAP_XPORT_PROP_ONLY)) == NULL) {
3417fcf3ce44SJohn Forte 			return (err);
3418fcf3ce44SJohn Forte 		}
3419fcf3ce44SJohn Forte 
3420fcf3ce44SJohn Forte 	} else { /* FC4_FCA_MASK type path */
3421063d642aSBill Gumbrell 		(void) memset(&map, 0, sizeof (struct lilpmap));
3422fcf3ce44SJohn Forte 
3423063d642aSBill Gumbrell 		if ((err = g_get_nexus_path(path_phys,
3424fcf3ce44SJohn Forte 		    &nexus_path_ptr)) != 0) {
3425063d642aSBill Gumbrell 			return (err);
3426063d642aSBill Gumbrell 		}
3427063d642aSBill Gumbrell 		(void) strcpy(nexus_path, nexus_path_ptr);
3428063d642aSBill Gumbrell 		g_destroy_data(nexus_path_ptr);
3429fcf3ce44SJohn Forte 
3430fcf3ce44SJohn Forte 		/* open driver */
3431063d642aSBill Gumbrell 		if ((fd = g_object_open(nexus_path,
3432063d642aSBill Gumbrell 		    O_NDELAY | O_RDONLY)) == -1)
3433063d642aSBill Gumbrell 			return (errno);
3434fcf3ce44SJohn Forte 
3435fcf3ce44SJohn Forte 		/*
3436fcf3ce44SJohn Forte 		 * First try using the socal version of the map.
3437fcf3ce44SJohn Forte 		 * If that fails get the expanded vesion.
3438fcf3ce44SJohn Forte 		 */
3439063d642aSBill Gumbrell 		if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
3440063d642aSBill Gumbrell 			I_DPRINTF("  FCIO_GETMAP ioctl failed.\n");
3441063d642aSBill Gumbrell 			if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) {
3442063d642aSBill Gumbrell 				I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
3443063d642aSBill Gumbrell 				(void) close(fd);
3444063d642aSBill Gumbrell 				return (L_SFIOCGMAP_IOCTL_FAIL);
3445063d642aSBill Gumbrell 			}
3446063d642aSBill Gumbrell 			/* Check for reasonableness. */
3447063d642aSBill Gumbrell 			if ((exp_map.sf_count > 126) ||
3448063d642aSBill Gumbrell 			    (exp_map.sf_count < 0)) {
3449fcf3ce44SJohn Forte 				(void) close(fd);
3450fcf3ce44SJohn Forte 				return (L_INVALID_LOOP_MAP);
3451fcf3ce44SJohn Forte 			}
3452063d642aSBill Gumbrell 			for (i = 0; i < exp_map.sf_count; i++) {
3453063d642aSBill Gumbrell 				if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) {
3454063d642aSBill Gumbrell 					(void) close(fd);
3455063d642aSBill Gumbrell 					return (L_INVALID_LOOP_MAP);
3456063d642aSBill Gumbrell 				}
3457063d642aSBill Gumbrell 			}
3458063d642aSBill Gumbrell 			length = exp_map.sf_count;
3459063d642aSBill Gumbrell 			exp_map_flag++;
3460fcf3ce44SJohn Forte 		} else {
3461063d642aSBill Gumbrell 			I_DPRINTF("  g_rdls:"
3462063d642aSBill Gumbrell 			    " FCIO_GETMAP ioctl returned %d entries.\n",
3463063d642aSBill Gumbrell 			    map.lilp_length);
3464063d642aSBill Gumbrell 			/* Check for reasonableness. */
3465063d642aSBill Gumbrell 			if (map.lilp_length > sizeof (map.lilp_list)) {
3466063d642aSBill Gumbrell 				(void) close(fd);
3467063d642aSBill Gumbrell 				return (L_FCIOGETMAP_INVLD_LEN);
3468063d642aSBill Gumbrell 			}
3469063d642aSBill Gumbrell 			length = map.lilp_length;
3470fcf3ce44SJohn Forte 		}
3471063d642aSBill Gumbrell 		for (i = 0; i < length; i++) {
3472063d642aSBill Gumbrell 			if ((c2 = (struct al_rls *)
3473063d642aSBill Gumbrell 			    g_zalloc(sizeof (struct al_rls))) == NULL) {
3474063d642aSBill Gumbrell 				close(fd);
3475063d642aSBill Gumbrell 				return (L_MALLOC_FAILED);
3476063d642aSBill Gumbrell 			}
3477063d642aSBill Gumbrell 			if (rls == NULL) {
3478063d642aSBill Gumbrell 				c1 = rls = c2;
3479fcf3ce44SJohn Forte 			} else {
3480063d642aSBill Gumbrell 				for (c1 = rls; c1->next; c1 =  c1->next) {};
3481063d642aSBill Gumbrell 				c1 = c1->next = c2;
3482063d642aSBill Gumbrell 			}
3483063d642aSBill Gumbrell 			(void) strcpy(c1->driver_path, nexus_path);
3484063d642aSBill Gumbrell 			if (exp_map_flag) {
3485063d642aSBill Gumbrell 				c1->payload.rls_portno = c1->al_ha =
3486063d642aSBill Gumbrell 				    exp_map.sf_addr_pair[i].sf_al_pa;
3487063d642aSBill Gumbrell 			} else {
3488063d642aSBill Gumbrell 				c1->payload.rls_portno = c1->al_ha =
3489063d642aSBill Gumbrell 				    map.lilp_list[i];
3490063d642aSBill Gumbrell 			}
3491063d642aSBill Gumbrell 			c1->payload.rls_linkfail =
3492063d642aSBill Gumbrell 			    (uint_t)0xff000000; /* get LESB for this port */
3493063d642aSBill Gumbrell 			I_DPRINTF("  g_rdls:"
3494063d642aSBill Gumbrell 			    " al_pa 0x%x\n", c1->payload.rls_portno);
3495063d642aSBill Gumbrell 
3496063d642aSBill Gumbrell 			if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) {
3497063d642aSBill Gumbrell 				/*
3498063d642aSBill Gumbrell 				 * The ifp driver will return ENXIO when rls
3499063d642aSBill Gumbrell 				 * is issued for same initiator on loop when
3500063d642aSBill Gumbrell 				 * there is more than one on the loop.
3501063d642aSBill Gumbrell 				 * Rather than completely fail, continue on.
3502063d642aSBill Gumbrell 				 * Set values in the payload struct to -1 as
3503063d642aSBill Gumbrell 				 * this is what socal is currently doing for
3504063d642aSBill Gumbrell 				 * the case of same initiator rls.
3505063d642aSBill Gumbrell 				 */
3506063d642aSBill Gumbrell 				if ((dev_type & FC4_PCI_FCA) &&
3507063d642aSBill Gumbrell 				    (errno == ENXIO)) {
3508063d642aSBill Gumbrell 					c1->payload.rls_linkfail =
3509063d642aSBill Gumbrell 					    c1->payload.rls_syncfail =
3510063d642aSBill Gumbrell 					    c1->payload.rls_sigfail =
3511063d642aSBill Gumbrell 					    c1->payload.rls_primitiverr =
3512063d642aSBill Gumbrell 					    c1->payload.rls_invalidword =
3513063d642aSBill Gumbrell 					    c1->payload.rls_invalidcrc =
3514063d642aSBill Gumbrell 					    (uint_t)0xffffffff;
3515063d642aSBill Gumbrell 				} else {
3516063d642aSBill Gumbrell 					I_DPRINTF("  FCIO_LINKSTATUS ioctl"
3517063d642aSBill Gumbrell 					    " failed with errno %d.\n", errno);
3518063d642aSBill Gumbrell 					g_free_rls(rls);
3519063d642aSBill Gumbrell 					(void) close(fd);
3520063d642aSBill Gumbrell 					return (L_FCIO_LINKSTATUS_FAILED);
3521063d642aSBill Gumbrell 				}
3522fcf3ce44SJohn Forte 			}
3523063d642aSBill Gumbrell 			I_DPRINTF("  g_rdls: al_pa returned by ioctl 0x%x\n",
3524063d642aSBill Gumbrell 			    c1->payload.rls_portno);
3525fcf3ce44SJohn Forte 		}
3526063d642aSBill Gumbrell 		*rls_ptr = rls; /* Pass back pointer */
3527fcf3ce44SJohn Forte 
3528063d642aSBill Gumbrell 		(void) close(fd);
3529063d642aSBill Gumbrell 		return (0);
3530fcf3ce44SJohn Forte 	}
3531fcf3ce44SJohn Forte 
3532fcf3ce44SJohn Forte 	/* Now we need to take care of FC_FCA_MASK case.	*/
3533fcf3ce44SJohn Forte 	/* we have map created already via g_dev_map_init.	*/
3534fcf3ce44SJohn Forte 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3535fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3536fcf3ce44SJohn Forte 		return (err);
3537fcf3ce44SJohn Forte 	}
3538fcf3ce44SJohn Forte 
3539fcf3ce44SJohn Forte 	if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
3540fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3541fcf3ce44SJohn Forte 		if (err != L_NO_SUCH_DEV_FOUND) {
3542fcf3ce44SJohn Forte 			return (err);
3543fcf3ce44SJohn Forte 		} else {
3544fcf3ce44SJohn Forte 			return (L_NO_DEVICES_FOUND);
3545fcf3ce44SJohn Forte 		}
3546fcf3ce44SJohn Forte 	}
3547fcf3ce44SJohn Forte 
3548fcf3ce44SJohn Forte 	while (map_dev) {
3549063d642aSBill Gumbrell 		if ((err = g_dev_prop_lookup_ints(
3550063d642aSBill Gumbrell 		    map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3551063d642aSBill Gumbrell 			g_dev_map_fini(map_root);
3552063d642aSBill Gumbrell 			g_free_rls(rls);
3553063d642aSBill Gumbrell 			return (err);
3554063d642aSBill Gumbrell 		}
3555fcf3ce44SJohn Forte 
3556063d642aSBill Gumbrell 		if ((c2 = (struct al_rls *)
3557063d642aSBill Gumbrell 		    g_zalloc(sizeof (struct al_rls))) == NULL) {
3558063d642aSBill Gumbrell 			g_dev_map_fini(map_root);
3559063d642aSBill Gumbrell 			g_free_rls(rls);
3560063d642aSBill Gumbrell 			close(fd);
3561063d642aSBill Gumbrell 			return (L_MALLOC_FAILED);
3562063d642aSBill Gumbrell 		}
3563063d642aSBill Gumbrell 		if (rls == NULL) {
3564063d642aSBill Gumbrell 			c1 = rls = c2;
3565063d642aSBill Gumbrell 		} else {
3566063d642aSBill Gumbrell 			for (c1 = rls; c1->next; c1 =  c1->next) {};
3567063d642aSBill Gumbrell 			c1 = c1->next = c2;
3568063d642aSBill Gumbrell 		}
3569063d642aSBill Gumbrell 		/* Set the al_ha here */
3570063d642aSBill Gumbrell 		c1->al_ha = rls_req.port_id = *port_addr;
3571fcf3ce44SJohn Forte 
3572fcf3ce44SJohn Forte 		/*
3573fcf3ce44SJohn Forte 		 * fp uses different input/output structures for
3574fcf3ce44SJohn Forte 		 * rls. Load the values returned for the fp ioctl
3575fcf3ce44SJohn Forte 		 * into the structure passed back to the caller
3576fcf3ce44SJohn Forte 		 * Note: There is no reason for the path
3577fcf3ce44SJohn Forte 		 * to be loaded into AL_rls as is done for socal/ifp
3578fcf3ce44SJohn Forte 		 * above.
3579fcf3ce44SJohn Forte 		 */
3580063d642aSBill Gumbrell 		if ((hba_port_top == FC_TOP_FABRIC) ||
3581063d642aSBill Gumbrell 		    (hba_port_top == FC_TOP_PUBLIC_LOOP)) {
3582063d642aSBill Gumbrell 			if ((err = g_dev_prop_lookup_bytes(
3583063d642aSBill Gumbrell 			    map_dev, PORT_WWN_PROP, &count,
3584063d642aSBill Gumbrell 			    &port_wwn_byte)) != 0) {
3585063d642aSBill Gumbrell 				g_dev_map_fini(map_root);
3586063d642aSBill Gumbrell 				g_free_rls(rls);
3587063d642aSBill Gumbrell 				return (err);
3588063d642aSBill Gumbrell 			}
3589063d642aSBill Gumbrell 			memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE);
3590063d642aSBill Gumbrell 			if ((err = g_get_dev_port_state(
3591063d642aSBill Gumbrell 			    fp_path, port_wwn, &state)) == 0) {
3592063d642aSBill Gumbrell 				if (state != PORT_DEVICE_LOGGED_IN) {
3593063d642aSBill Gumbrell 					if ((err = g_dev_login(fp_path,
3594063d642aSBill Gumbrell 					    port_wwn)) != 0) {
3595063d642aSBill Gumbrell 
3596063d642aSBill Gumbrell 					c1->payload.rls_linkfail =
3597063d642aSBill Gumbrell 					    c1->payload.rls_syncfail =
3598063d642aSBill Gumbrell 					    c1->payload.rls_sigfail =
3599063d642aSBill Gumbrell 					    c1->payload.rls_primitiverr =
3600063d642aSBill Gumbrell 					    c1->payload.rls_invalidword =
3601063d642aSBill Gumbrell 					    c1->payload.rls_invalidcrc =
3602063d642aSBill Gumbrell 					    (uint_t)0xffffffff;
3603063d642aSBill Gumbrell 						if (((map_dev =
3604063d642aSBill Gumbrell 						    g_get_next_dev(map_dev,
3605063d642aSBill Gumbrell 						    &err))
3606063d642aSBill Gumbrell 						    == NULL) &&
3607063d642aSBill Gumbrell 						    (err !=
3608063d642aSBill Gumbrell 						    L_NO_SUCH_DEV_FOUND)) {
3609063d642aSBill Gumbrell 							g_dev_map_fini(
3610063d642aSBill Gumbrell 							    map_root);
3611063d642aSBill Gumbrell 							g_free_rls(rls);
3612063d642aSBill Gumbrell 							return (err);
3613063d642aSBill Gumbrell 						}
3614063d642aSBill Gumbrell 						continue;
3615063d642aSBill Gumbrell 					}
3616063d642aSBill Gumbrell 				}
3617063d642aSBill Gumbrell 			} /* if g_get_dev_port_state fails proceed. */
3618063d642aSBill Gumbrell 		}
3619063d642aSBill Gumbrell 
3620063d642aSBill Gumbrell 		fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3621063d642aSBill Gumbrell 		if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3622fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3623fcf3ce44SJohn Forte 			g_free_rls(rls);
3624063d642aSBill Gumbrell 			return (L_OPEN_PATH_FAIL);
3625063d642aSBill Gumbrell 		}
3626063d642aSBill Gumbrell 		fcio.fcio_cmd = FCIO_LINK_STATUS;
3627063d642aSBill Gumbrell 		fcio.fcio_ibuf = (caddr_t)&rls_req;
3628063d642aSBill Gumbrell 		fcio.fcio_ilen = sizeof (rls_req);
3629063d642aSBill Gumbrell 		fcio.fcio_xfer = FCIO_XFER_RW;
3630063d642aSBill Gumbrell 		fcio.fcio_flags = 0;
3631063d642aSBill Gumbrell 		fcio.fcio_obuf = (caddr_t)&rls_payload;
3632063d642aSBill Gumbrell 		fcio.fcio_olen = sizeof (rls_payload);
3633063d642aSBill Gumbrell 		if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3634063d642aSBill Gumbrell 			c1->payload.rls_linkfail =
3635063d642aSBill Gumbrell 			    c1->payload.rls_syncfail =
3636063d642aSBill Gumbrell 			    c1->payload.rls_sigfail =
3637063d642aSBill Gumbrell 			    c1->payload.rls_primitiverr =
3638063d642aSBill Gumbrell 			    c1->payload.rls_invalidword =
3639063d642aSBill Gumbrell 			    c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3640063d642aSBill Gumbrell 		} else {
3641063d642aSBill Gumbrell 			/*
3642063d642aSBill Gumbrell 			 * Load the values into the struct passed
3643063d642aSBill Gumbrell 			 * back to the caller
3644063d642aSBill Gumbrell 			 */
3645063d642aSBill Gumbrell 			c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3646063d642aSBill Gumbrell 			c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3647063d642aSBill Gumbrell 			c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3648063d642aSBill Gumbrell 			c1->payload.rls_primitiverr =
3649063d642aSBill Gumbrell 			    rls_payload.rls_prim_seq_err;
3650063d642aSBill Gumbrell 			c1->payload.rls_invalidword =
3651063d642aSBill Gumbrell 			    rls_payload.rls_invalid_word;
3652063d642aSBill Gumbrell 			c1->payload.rls_invalidcrc =
3653063d642aSBill Gumbrell 			    rls_payload.rls_invalid_crc;
3654fcf3ce44SJohn Forte 		}
3655063d642aSBill Gumbrell 		(void) close(fp_fd);
3656fcf3ce44SJohn Forte 
3657063d642aSBill Gumbrell 		if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3658063d642aSBill Gumbrell 		    (err != L_NO_SUCH_DEV_FOUND)) {
3659063d642aSBill Gumbrell 			g_dev_map_fini(map_root);
3660063d642aSBill Gumbrell 			g_free_rls(rls);
3661063d642aSBill Gumbrell 			return (err);
3662063d642aSBill Gumbrell 		}
3663fcf3ce44SJohn Forte 	}
3664fcf3ce44SJohn Forte 
3665fcf3ce44SJohn Forte 	/* for Leadville issue a final call for the initiator */
3666fcf3ce44SJohn Forte 
3667fcf3ce44SJohn Forte 	if ((err = g_dev_prop_lookup_ints(
3668063d642aSBill Gumbrell 	    map_root, PORT_ADDR_PROP, &port_addr)) != 0) {
3669fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3670fcf3ce44SJohn Forte 		g_free_rls(rls);
3671fcf3ce44SJohn Forte 		return (err);
3672fcf3ce44SJohn Forte 	}
3673fcf3ce44SJohn Forte 
3674fcf3ce44SJohn Forte 	if ((c2 = (struct al_rls *)
3675fcf3ce44SJohn Forte 		g_zalloc(sizeof (struct al_rls))) == NULL) {
3676fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3677fcf3ce44SJohn Forte 		g_free_rls(rls);
3678fcf3ce44SJohn Forte 		return (L_MALLOC_FAILED);
3679fcf3ce44SJohn Forte 	}
3680fcf3ce44SJohn Forte 	if (rls == NULL) {
3681fcf3ce44SJohn Forte 		c1 = rls = c2;
3682fcf3ce44SJohn Forte 	} else {
3683fcf3ce44SJohn Forte 		for (c1 = rls; c1->next; c1 =  c1->next) {};
3684fcf3ce44SJohn Forte 		c1 = c1->next = c2;
3685fcf3ce44SJohn Forte 	}
3686fcf3ce44SJohn Forte 
3687fcf3ce44SJohn Forte 	c1->al_ha = rls_req.port_id = *port_addr;
3688fcf3ce44SJohn Forte 
3689fcf3ce44SJohn Forte 	if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3690fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3691fcf3ce44SJohn Forte 		g_free_rls(rls);
3692fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
3693fcf3ce44SJohn Forte 	}
3694fcf3ce44SJohn Forte 
3695fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_LINK_STATUS;
3696fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)&rls_req;
3697fcf3ce44SJohn Forte 	fcio.fcio_ilen = sizeof (rls_req);
3698fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_RW;
3699fcf3ce44SJohn Forte 	fcio.fcio_flags = 0;
3700fcf3ce44SJohn Forte 	fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3701fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)&rls_payload;
3702fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (rls_payload);
3703fcf3ce44SJohn Forte 
3704fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3705fcf3ce44SJohn Forte 		c1->payload.rls_linkfail =
3706063d642aSBill Gumbrell 		    c1->payload.rls_syncfail =
3707063d642aSBill Gumbrell 		    c1->payload.rls_sigfail =
3708063d642aSBill Gumbrell 		    c1->payload.rls_primitiverr =
3709063d642aSBill Gumbrell 		    c1->payload.rls_invalidword =
3710063d642aSBill Gumbrell 		    c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3711fcf3ce44SJohn Forte 	} else {
3712fcf3ce44SJohn Forte 		/*
3713fcf3ce44SJohn Forte 		 * Load the values into the struct passed
3714fcf3ce44SJohn Forte 		 * back to the caller
3715fcf3ce44SJohn Forte 		 */
3716fcf3ce44SJohn Forte 		c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3717fcf3ce44SJohn Forte 		c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3718fcf3ce44SJohn Forte 		c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3719fcf3ce44SJohn Forte 		c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err;
3720fcf3ce44SJohn Forte 		c1->payload.rls_invalidword = rls_payload.rls_invalid_word;
3721fcf3ce44SJohn Forte 		c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc;
3722fcf3ce44SJohn Forte 		(void) close(fp_fd);
3723fcf3ce44SJohn Forte 	}
3724fcf3ce44SJohn Forte 	(void) close(fp_fd);
3725fcf3ce44SJohn Forte 
3726fcf3ce44SJohn Forte 	*rls_ptr = rls;	/* Pass back pointer */
3727fcf3ce44SJohn Forte 
3728fcf3ce44SJohn Forte 	g_dev_map_fini(map_root);
3729fcf3ce44SJohn Forte 	return (0);
3730fcf3ce44SJohn Forte }
3731fcf3ce44SJohn Forte 
wwnConversion(uchar_t * wwn)3732fcf3ce44SJohn Forte static u_longlong_t wwnConversion(uchar_t *wwn)
3733fcf3ce44SJohn Forte {
3734fcf3ce44SJohn Forte 	u_longlong_t tmp;
3735fcf3ce44SJohn Forte 	memcpy(&tmp, wwn, sizeof (u_longlong_t));
3736fcf3ce44SJohn Forte 	return (tmp);
3737fcf3ce44SJohn Forte }
3738fcf3ce44SJohn Forte 
3739fcf3ce44SJohn Forte /*
3740fcf3ce44SJohn Forte  * Get device World Wide Name (port and node) for device at path
3741fcf3ce44SJohn Forte  * and add all WWNs to the wwn_list_found list.
3742fcf3ce44SJohn Forte  *
3743fcf3ce44SJohn Forte  * RETURN: 0 O.K.
3744fcf3ce44SJohn Forte  *
3745fcf3ce44SJohn Forte  * INPUTS:
3746fcf3ce44SJohn Forte  *	- path_phys must be of a device, either an IB or disk.
3747fcf3ce44SJohn Forte  */
3748fcf3ce44SJohn Forte static int
get_wwns(char * path_phys,uchar_t port_wwn[],uchar_t node_wwn[],int * al_pa,struct wwn_list_found_struct ** wwn_list_found)3749fcf3ce44SJohn Forte get_wwns(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], int *al_pa,
3750063d642aSBill Gumbrell     struct wwn_list_found_struct **wwn_list_found)
3751fcf3ce44SJohn Forte {
3752063d642aSBill Gumbrell 	uint32_t	hba_port_top;
3753063d642aSBill Gumbrell 	int		i, err, count;
3754063d642aSBill Gumbrell 	char		*char_ptr, *ptr;
3755063d642aSBill Gumbrell 	int		found = 0, pathcnt, *port_addr;
3756*926d645fSToomas Soome 	unsigned long long	pwwn;
3757063d642aSBill Gumbrell 	uchar_t			*port_wwn_byte, *node_wwn_byte;
3758063d642aSBill Gumbrell 	char		drvr_path[MAXPATHLEN];
3759063d642aSBill Gumbrell 	int		p_on = 0, p_st = 0;
3760063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
3761063d642aSBill Gumbrell 	char		pwwn1[WWN_S_LEN];
3762063d642aSBill Gumbrell 	gfc_dev_t	map_root, map_dev;
3763063d642aSBill Gumbrell 	hrtime_t	start_time, end_time;
3764063d642aSBill Gumbrell 	char *env = NULL;
3765fcf3ce44SJohn Forte 
3766fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_wwn: Getting device WWN"
3767063d642aSBill Gumbrell 	    " and al_pa for device: %s\n",
3768063d642aSBill Gumbrell 	    path_phys);
3769fcf3ce44SJohn Forte 
3770fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
3771fcf3ce44SJohn Forte 		start_time = gethrtime();
3772fcf3ce44SJohn Forte 	}
3773fcf3ce44SJohn Forte 
3774fcf3ce44SJohn Forte 	/*
3775fcf3ce44SJohn Forte 	 * Get the loop identifier (switch setting) from the path.
3776fcf3ce44SJohn Forte 	 *
3777fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
3778fcf3ce44SJohn Forte 	 * /devices/.../SUNW,socal@3,0/SUNW,sf@0,0/SUNW,ssd@x,0
3779fcf3ce44SJohn Forte 	 * or
3780fcf3ce44SJohn Forte 	 * /devices/.../SUNW,qlc@5/SUNW,fp@0,0/SUNW,ssd@x,0
3781fcf3ce44SJohn Forte 	 */
3782fcf3ce44SJohn Forte 	if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
3783fcf3ce44SJohn Forte 		return (L_INVLD_PATH_NO_ATSIGN_FND);
3784fcf3ce44SJohn Forte 	}
3785fcf3ce44SJohn Forte 	char_ptr++;	/* point to the loop identifier or WWN */
3786fcf3ce44SJohn Forte 
3787fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path_phys);
3788fcf3ce44SJohn Forte 	/* This function allocs mem for map.dev_addr on success */
3789fcf3ce44SJohn Forte 	if (strstr(drvr_path, SCSI_VHCI)) {
3790fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path, &pathlist)) {
3791fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
3792fcf3ce44SJohn Forte 		}
3793fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
3794fcf3ce44SJohn Forte 		p_on = p_st = 0;
3795fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
3796fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3797fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
3798063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_ONLINE) {
3799fcf3ce44SJohn Forte 					p_on = i;
3800fcf3ce44SJohn Forte 					break;
3801fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
3802063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_STANDBY) {
3803fcf3ce44SJohn Forte 					p_st = i;
3804fcf3ce44SJohn Forte 				}
3805fcf3ce44SJohn Forte 			}
3806fcf3ce44SJohn Forte 		}
3807fcf3ce44SJohn Forte 		if (p_on == i) {
3808fcf3ce44SJohn Forte 			/* on_line path */
3809fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
3810063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_hba);
3811fcf3ce44SJohn Forte 			(void) strncpy(pwwn1,
3812063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_addr,
3813063d642aSBill Gumbrell 			    WWN_S_LEN - 1);
3814fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
3815fcf3ce44SJohn Forte 		} else {
3816fcf3ce44SJohn Forte 			/* standby or path0 */
3817fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
3818063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_hba);
3819fcf3ce44SJohn Forte 			(void) strncpy(pwwn1,
3820063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_addr,
3821063d642aSBill Gumbrell 			    WWN_S_LEN - 1);
3822fcf3ce44SJohn Forte 			pwwn1[WWN_S_LEN - 1] = '\0';
3823fcf3ce44SJohn Forte 		}
3824fcf3ce44SJohn Forte 		free(pathlist.path_info);
3825fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
3826fcf3ce44SJohn Forte 	}
3827fcf3ce44SJohn Forte 	if ((map_root = g_dev_map_init(drvr_path, &err,
3828063d642aSBill Gumbrell 	    MAP_XPORT_PROP_ONLY)) == NULL) {
3829fcf3ce44SJohn Forte 		return (err);
3830fcf3ce44SJohn Forte 	}
3831fcf3ce44SJohn Forte 
3832fcf3ce44SJohn Forte 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3833fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3834fcf3ce44SJohn Forte 		return (err);
3835fcf3ce44SJohn Forte 	}
3836fcf3ce44SJohn Forte 
3837fcf3ce44SJohn Forte 	if (strstr(path_phys, SCSI_VHCI)) {
3838fcf3ce44SJohn Forte 		char_ptr = pwwn1;
3839fcf3ce44SJohn Forte 	} else {
3840fcf3ce44SJohn Forte 		/*
3841fcf3ce44SJohn Forte 		 * Format of WWN is
3842fcf3ce44SJohn Forte 		 * ssd@w2200002037000f96,0:a,raw
3843fcf3ce44SJohn Forte 		 */
3844fcf3ce44SJohn Forte 		if (*char_ptr != 'w') {
3845fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3846fcf3ce44SJohn Forte 			return (L_INVLD_WWN_FORMAT);
3847fcf3ce44SJohn Forte 		}
3848fcf3ce44SJohn Forte 		char_ptr++;
3849fcf3ce44SJohn Forte 	}
3850fcf3ce44SJohn Forte 	pwwn = strtoull(char_ptr, &ptr, 16);
3851fcf3ce44SJohn Forte 	if (ptr == char_ptr) {
3852fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3853fcf3ce44SJohn Forte 		return (L_NO_WWN_FOUND_IN_PATH);
3854fcf3ce44SJohn Forte 	}
3855fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_wwn:  Looking for WWN "
3856fcf3ce44SJohn Forte 	    "0x%llx\n", pwwn);
3857fcf3ce44SJohn Forte 
3858fcf3ce44SJohn Forte 	if (((map_dev = g_get_first_dev(map_root, &err)) == NULL) &&
3859fcf3ce44SJohn Forte 	    (err != L_NO_SUCH_DEV_FOUND)) {
3860fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3861fcf3ce44SJohn Forte 		return (err);
3862fcf3ce44SJohn Forte 	}
3863fcf3ce44SJohn Forte 
3864fcf3ce44SJohn Forte 	while (map_dev) {
3865fcf3ce44SJohn Forte 		if ((err = g_dev_prop_lookup_bytes(map_dev,
3866063d642aSBill Gumbrell 		    PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) {
3867fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3868fcf3ce44SJohn Forte 			return (err);
3869fcf3ce44SJohn Forte 		}
3870fcf3ce44SJohn Forte 		if ((err = g_dev_prop_lookup_bytes(map_dev,
3871063d642aSBill Gumbrell 		    NODE_WWN_PROP, &count, &node_wwn_byte)) != 0) {
3872fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3873fcf3ce44SJohn Forte 			return (err);
3874fcf3ce44SJohn Forte 		}
3875fcf3ce44SJohn Forte 
3876fcf3ce44SJohn Forte 		if (pwwn == wwnConversion(port_wwn_byte) && found != 1) {
3877fcf3ce44SJohn Forte 			found = 1;
3878fcf3ce44SJohn Forte 			memcpy(port_wwn, port_wwn_byte, FC_WWN_SIZE);
3879fcf3ce44SJohn Forte 			memcpy(node_wwn, node_wwn_byte, FC_WWN_SIZE);
3880fcf3ce44SJohn Forte 			if ((err = g_dev_prop_lookup_ints(
3881063d642aSBill Gumbrell 			    map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3882fcf3ce44SJohn Forte 				g_dev_map_fini(map_root);
3883fcf3ce44SJohn Forte 				return (err);
3884fcf3ce44SJohn Forte 			}
3885fcf3ce44SJohn Forte 			*al_pa = *port_addr;
3886fcf3ce44SJohn Forte 		}
3887fcf3ce44SJohn Forte 		add_wwn_entry(wwn_list_found, port_wwn_byte,
3888fcf3ce44SJohn Forte 		    node_wwn_byte);
3889fcf3ce44SJohn Forte 
3890fcf3ce44SJohn Forte 		if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3891fcf3ce44SJohn Forte 		    (err != L_NO_SUCH_DEV_FOUND)) {
3892fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
3893fcf3ce44SJohn Forte 			return (err);
3894fcf3ce44SJohn Forte 		}
3895fcf3ce44SJohn Forte 	}
3896fcf3ce44SJohn Forte 	if (!found) {
3897fcf3ce44SJohn Forte 		g_dev_map_fini(map_root);
3898fcf3ce44SJohn Forte 		return (L_NO_LOOP_ADDRS_FOUND);
3899fcf3ce44SJohn Forte 	}
3900fcf3ce44SJohn Forte 
3901fcf3ce44SJohn Forte 	g_dev_map_fini(map_root);
3902fcf3ce44SJohn Forte 	if (env != NULL) {
3903fcf3ce44SJohn Forte 		end_time = gethrtime();
3904fcf3ce44SJohn Forte 		fprintf(stdout, "      get_wwns: "
3905063d642aSBill Gumbrell 		    "\t\tTime = %lld millisec\n",
3906063d642aSBill Gumbrell 		    (end_time - start_time)/1000000);
3907fcf3ce44SJohn Forte 	}
3908fcf3ce44SJohn Forte 	return (0);
3909fcf3ce44SJohn Forte }
3910fcf3ce44SJohn Forte 
3911fcf3ce44SJohn Forte /*
3912fcf3ce44SJohn Forte  * Get device World Wide Name and AL_PA for device at path
3913fcf3ce44SJohn Forte  *
3914fcf3ce44SJohn Forte  * RETURN: 0 O.K.
3915fcf3ce44SJohn Forte  *
3916fcf3ce44SJohn Forte  * INPUTS:
3917fcf3ce44SJohn Forte  *	- path_phys must be of a device, either an IB or disk.
3918fcf3ce44SJohn Forte  */
3919fcf3ce44SJohn Forte int
g_get_wwn(char * path_phys,uchar_t port_wwn[],uchar_t node_wwn[],int * al_pa,int verbose)3920fcf3ce44SJohn Forte g_get_wwn(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[],
3921063d642aSBill Gumbrell     int *al_pa, int verbose)
3922fcf3ce44SJohn Forte {
3923fcf3ce44SJohn Forte 	struct wwn_list_found_struct *wwn_list_found = NULL;
3924fcf3ce44SJohn Forte 	int ret;
3925fcf3ce44SJohn Forte 
3926fcf3ce44SJohn Forte 	/* return invalid path if the argument is NULL */
3927fcf3ce44SJohn Forte 	if (path_phys == NULL) {
3928fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3929fcf3ce44SJohn Forte 	}
3930fcf3ce44SJohn Forte 	/* return invalid arg if the argument is NULL */
3931063d642aSBill Gumbrell 	if ((port_wwn == NULL) || (node_wwn == NULL) || (al_pa == NULL)) {
3932fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3933fcf3ce44SJohn Forte 	}
3934fcf3ce44SJohn Forte 
3935fcf3ce44SJohn Forte 	ret = get_wwns(path_phys, port_wwn, node_wwn, al_pa, &wwn_list_found);
3936fcf3ce44SJohn Forte 	g_free_wwn_list_found(&wwn_list_found);
3937fcf3ce44SJohn Forte 	return (ret);
3938fcf3ce44SJohn Forte }
3939fcf3ce44SJohn Forte 
3940fcf3ce44SJohn Forte int
g_get_serial_number(char * path,uchar_t * serial_number,size_t * serial_number_len)3941fcf3ce44SJohn Forte g_get_serial_number(char *path, uchar_t *serial_number,
3942fcf3ce44SJohn Forte     size_t *serial_number_len)
3943fcf3ce44SJohn Forte {
3944063d642aSBill Gumbrell 	int	    fd, status = 0;
3945063d642aSBill Gumbrell 	L_inquiry80 inq80;
3946fcf3ce44SJohn Forte 
3947fcf3ce44SJohn Forte 	/* return invalid path if path is NULL */
3948fcf3ce44SJohn Forte 	if (path == NULL) {
3949fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
3950fcf3ce44SJohn Forte 	}
3951fcf3ce44SJohn Forte 	/* return invalid arg if serial_number is NULL */
3952fcf3ce44SJohn Forte 	if (serial_number == NULL) {
3953fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
3954fcf3ce44SJohn Forte 	}
3955fcf3ce44SJohn Forte 
3956fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_serial_number: path: %s\n", path);
3957fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) {
3958fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
3959fcf3ce44SJohn Forte 	}
3960fcf3ce44SJohn Forte 	/*
3961fcf3ce44SJohn Forte 	 * Call the inquiry cmd on page 0x80 only if the vendor
3962fcf3ce44SJohn Forte 	 * supports page 0x80.
3963fcf3ce44SJohn Forte 	 */
3964fcf3ce44SJohn Forte 	if ((g_find_supported_inq_page(fd, 0x80))) {
3965fcf3ce44SJohn Forte 		/*
3966fcf3ce44SJohn Forte 		 * Let's retrieve the serial number from page 0x80
3967fcf3ce44SJohn Forte 		 * and store it in the inquiry structure
3968fcf3ce44SJohn Forte 		 */
3969fcf3ce44SJohn Forte 		status = g_scsi_inquiry_cmd80(fd,
3970fcf3ce44SJohn Forte 		    (uchar_t *)&inq80,
3971fcf3ce44SJohn Forte 		    sizeof (struct l_inquiry80_struct));
3972fcf3ce44SJohn Forte 		if (status == 0) {
3973fcf3ce44SJohn Forte 			if (*serial_number_len > inq80.inq_page_len)
3974fcf3ce44SJohn Forte 				*serial_number_len = inq80.inq_page_len;
3975fcf3ce44SJohn Forte 			strncpy((char *)serial_number, (char *)inq80.inq_serial,
3976fcf3ce44SJohn Forte 			    *serial_number_len);
3977fcf3ce44SJohn Forte 		} else {
3978fcf3ce44SJohn Forte 			char unavail[] = "Unavailable";
3979fcf3ce44SJohn Forte 			status = 0;
3980fcf3ce44SJohn Forte 			if (*serial_number_len > strlen(unavail))
3981fcf3ce44SJohn Forte 				*serial_number_len = strlen(unavail);
3982fcf3ce44SJohn Forte 			strncpy((char *)serial_number, unavail,
3983fcf3ce44SJohn Forte 			    *serial_number_len);
3984fcf3ce44SJohn Forte 		}
3985fcf3ce44SJohn Forte 	} else {
3986fcf3ce44SJohn Forte 		/*
3987fcf3ce44SJohn Forte 		 * page 0x80 is not supported, so print the
3988fcf3ce44SJohn Forte 		 * appropriate message.
3989fcf3ce44SJohn Forte 		 */
3990fcf3ce44SJohn Forte 		char unsupp[] = "Unsupported";
3991fcf3ce44SJohn Forte 		if (*serial_number_len > strlen(unsupp))
3992fcf3ce44SJohn Forte 			*serial_number_len = strlen(unsupp);
3993fcf3ce44SJohn Forte 		strncpy((char *)serial_number, unsupp,
3994fcf3ce44SJohn Forte 		    *serial_number_len);
3995fcf3ce44SJohn Forte 	}
3996fcf3ce44SJohn Forte 	(void) close(fd);
3997fcf3ce44SJohn Forte 	return (status);
3998fcf3ce44SJohn Forte }
3999fcf3ce44SJohn Forte 
4000fcf3ce44SJohn Forte int
g_get_inquiry(char * path,L_inquiry * l_inquiry)4001fcf3ce44SJohn Forte g_get_inquiry(char *path, L_inquiry *l_inquiry)
4002fcf3ce44SJohn Forte {
4003063d642aSBill Gumbrell 	int	    fd, status;
4004fcf3ce44SJohn Forte 
4005fcf3ce44SJohn Forte 	/* return invalid path if path is NULL */
4006fcf3ce44SJohn Forte 	if (path == NULL) {
4007fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4008fcf3ce44SJohn Forte 	}
4009fcf3ce44SJohn Forte 	/* return invalid arg if l_inquiry is NULL */
4010fcf3ce44SJohn Forte 	if (l_inquiry == NULL) {
4011fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
4012fcf3ce44SJohn Forte 	}
4013fcf3ce44SJohn Forte 
4014fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_inquiry: path: %s\n", path);
4015fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4016fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4017fcf3ce44SJohn Forte 	status = g_scsi_inquiry_cmd(fd,
4018063d642aSBill Gumbrell 	    (uchar_t *)l_inquiry, sizeof (struct l_inquiry_struct));
4019fcf3ce44SJohn Forte 
4020fcf3ce44SJohn Forte 	(void) close(fd);
4021fcf3ce44SJohn Forte 	return (status);
4022fcf3ce44SJohn Forte }
4023fcf3ce44SJohn Forte 
4024fcf3ce44SJohn Forte /*
4025fcf3ce44SJohn Forte  * Function to retrieve inquiry page 0x80 from the device
4026fcf3ce44SJohn Forte  */
4027fcf3ce44SJohn Forte static int
g_scsi_inquiry_cmd80(int fd,uchar_t * buf_ptr,int buf_len)4028fcf3ce44SJohn Forte g_scsi_inquiry_cmd80(int fd, uchar_t *buf_ptr, int buf_len)
4029fcf3ce44SJohn Forte {
4030063d642aSBill Gumbrell 	struct uscsi_cmd	ucmd;
4031063d642aSBill Gumbrell 	my_cdb_g0		cdb = {SCMD_INQUIRY, 0x1, 0x80, 0, 0x10, 0};
4032063d642aSBill Gumbrell 	struct scsi_extended_sense	sense;
4033fcf3ce44SJohn Forte 
4034fcf3ce44SJohn Forte 	(void) memset(buf_ptr, 0, buf_len);
4035fcf3ce44SJohn Forte 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
4036fcf3ce44SJohn Forte 	cdb.count = (uchar_t)buf_len;
4037fcf3ce44SJohn Forte 	ucmd.uscsi_cdb = (caddr_t)&cdb;
4038fcf3ce44SJohn Forte 	ucmd.uscsi_cdblen = CDB_GROUP0;
4039fcf3ce44SJohn Forte 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
4040fcf3ce44SJohn Forte 	ucmd.uscsi_buflen = buf_len;
4041fcf3ce44SJohn Forte 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
4042fcf3ce44SJohn Forte 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
4043fcf3ce44SJohn Forte 	ucmd.uscsi_timeout = 60;
4044fcf3ce44SJohn Forte 	return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT));
4045fcf3ce44SJohn Forte }
4046fcf3ce44SJohn Forte 
4047fcf3ce44SJohn Forte /*
4048fcf3ce44SJohn Forte  * Function to determine if the given page is supported by vendor.
4049fcf3ce44SJohn Forte  */
4050fcf3ce44SJohn Forte static int
g_find_supported_inq_page(int fd,int page_num)4051fcf3ce44SJohn Forte g_find_supported_inq_page(int fd, int page_num)
4052fcf3ce44SJohn Forte {
4053063d642aSBill Gumbrell 	struct	uscsi_cmd	ucmd;
4054063d642aSBill Gumbrell 	my_cdb_g0	cdb = {SCMD_INQUIRY, 0x1, 0, 0, 0xff, 0};
4055063d642aSBill Gumbrell 	struct	scsi_extended_sense	sense;
4056063d642aSBill Gumbrell 	L_inquiry00			inq00;
4057063d642aSBill Gumbrell 	uchar_t				*data;
4058063d642aSBill Gumbrell 	int				status = 0;
4059063d642aSBill Gumbrell 	int				index;
4060fcf3ce44SJohn Forte 
4061fcf3ce44SJohn Forte 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
4062fcf3ce44SJohn Forte 	cdb.count = (uchar_t)(sizeof (L_inquiry00));
4063fcf3ce44SJohn Forte 	ucmd.uscsi_cdb = (caddr_t)&cdb;
4064fcf3ce44SJohn Forte 	ucmd.uscsi_cdblen = CDB_GROUP0;
4065fcf3ce44SJohn Forte 	ucmd.uscsi_bufaddr = (caddr_t)&inq00;
4066fcf3ce44SJohn Forte 	ucmd.uscsi_buflen = sizeof (inq00);
4067fcf3ce44SJohn Forte 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
4068fcf3ce44SJohn Forte 	ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
4069fcf3ce44SJohn Forte 	ucmd.uscsi_timeout = 60;
4070fcf3ce44SJohn Forte 	status = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT);
4071fcf3ce44SJohn Forte 	if (status) {
4072fcf3ce44SJohn Forte 		return (0);
4073fcf3ce44SJohn Forte 	}
4074fcf3ce44SJohn Forte 	data = (uchar_t *)&inq00;
4075fcf3ce44SJohn Forte 	for (index = 4; (index <= inq00.len+3)&&
4076fcf3ce44SJohn Forte 	    (data[index] <= page_num); index ++) {
4077fcf3ce44SJohn Forte 		if (data[index] == page_num) {
4078fcf3ce44SJohn Forte 			return (1);
4079fcf3ce44SJohn Forte 		}
4080fcf3ce44SJohn Forte 	}
4081fcf3ce44SJohn Forte 	return (0);
4082fcf3ce44SJohn Forte }
4083fcf3ce44SJohn Forte 
4084fcf3ce44SJohn Forte int
g_get_perf_statistics(char * path,uchar_t * perf_ptr)4085fcf3ce44SJohn Forte g_get_perf_statistics(char *path, uchar_t *perf_ptr)
4086fcf3ce44SJohn Forte {
4087063d642aSBill Gumbrell 	int	fd;
4088fcf3ce44SJohn Forte 
4089fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_perf_statistics: Get Performance Statistics:"
4090063d642aSBill Gumbrell 	    "\n  Path:%s\n",
4091063d642aSBill Gumbrell 	    path);
4092fcf3ce44SJohn Forte 
4093fcf3ce44SJohn Forte 	/* initialize tables */
4094fcf3ce44SJohn Forte 	(void) memset(perf_ptr, 0, sizeof (int));
4095fcf3ce44SJohn Forte 
4096fcf3ce44SJohn Forte 	/* open controller */
4097fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4098fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4099fcf3ce44SJohn Forte 
4100fcf3ce44SJohn Forte 
4101fcf3ce44SJohn Forte 	/* update parameters in the performance table */
4102fcf3ce44SJohn Forte 
4103fcf3ce44SJohn Forte 	/* get the period in seconds */
4104fcf3ce44SJohn Forte 
4105fcf3ce44SJohn Forte 
4106fcf3ce44SJohn Forte 	(void) close(fd);
4107fcf3ce44SJohn Forte 
4108fcf3ce44SJohn Forte 	return (0);
4109fcf3ce44SJohn Forte }
4110fcf3ce44SJohn Forte 
4111fcf3ce44SJohn Forte 
4112fcf3ce44SJohn Forte int
g_start(char * path)4113fcf3ce44SJohn Forte g_start(char *path)
4114fcf3ce44SJohn Forte {
4115063d642aSBill Gumbrell 	int	status;
4116063d642aSBill Gumbrell 	int	fd;
4117fcf3ce44SJohn Forte 
4118fcf3ce44SJohn Forte 	P_DPRINTF("  g_start: Start: Path %s\n", path);
4119fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4120fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4121fcf3ce44SJohn Forte 	status = g_scsi_start_cmd(fd);
4122fcf3ce44SJohn Forte 	(void) close(fd);
4123fcf3ce44SJohn Forte 	return (status);
4124fcf3ce44SJohn Forte }
4125fcf3ce44SJohn Forte 
4126fcf3ce44SJohn Forte int
g_stop(char * path,int immediate_flag)4127fcf3ce44SJohn Forte g_stop(char *path, int immediate_flag)
4128fcf3ce44SJohn Forte {
4129063d642aSBill Gumbrell 	int	status, fd;
4130fcf3ce44SJohn Forte 
4131fcf3ce44SJohn Forte 	P_DPRINTF("  g_stop: Stop: Path %s\n", path);
4132fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4133fcf3ce44SJohn Forte 		return (errno);
4134fcf3ce44SJohn Forte 	status = g_scsi_stop_cmd(fd, immediate_flag);
4135fcf3ce44SJohn Forte 	(void) close(fd);
4136fcf3ce44SJohn Forte 	return (status);
4137fcf3ce44SJohn Forte }
4138fcf3ce44SJohn Forte 
4139fcf3ce44SJohn Forte int
g_reserve(char * path)4140fcf3ce44SJohn Forte g_reserve(char *path)
4141fcf3ce44SJohn Forte {
4142*926d645fSToomas Soome 	int	fd, status;
4143fcf3ce44SJohn Forte 
4144fcf3ce44SJohn Forte 	P_DPRINTF("  g_reserve: Reserve: Path %s\n", path);
4145fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4146fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4147fcf3ce44SJohn Forte 	status = g_scsi_reserve_cmd(fd);
4148fcf3ce44SJohn Forte 	(void) close(fd);
4149fcf3ce44SJohn Forte 	return (status);
4150fcf3ce44SJohn Forte }
4151fcf3ce44SJohn Forte 
4152fcf3ce44SJohn Forte int
g_release(char * path)4153fcf3ce44SJohn Forte g_release(char *path)
4154fcf3ce44SJohn Forte {
4155*926d645fSToomas Soome 	int	fd, status;
4156fcf3ce44SJohn Forte 
4157fcf3ce44SJohn Forte 	P_DPRINTF("  g_release: Release: Path %s\n", path);
4158fcf3ce44SJohn Forte 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
4159fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4160fcf3ce44SJohn Forte 	status = g_scsi_release_cmd(fd);
4161fcf3ce44SJohn Forte 	(void) close(fd);
4162fcf3ce44SJohn Forte 	return (status);
4163fcf3ce44SJohn Forte }
4164fcf3ce44SJohn Forte 
4165fcf3ce44SJohn Forte static char
ctoi(char c)4166fcf3ce44SJohn Forte ctoi(char c)
4167fcf3ce44SJohn Forte {
4168fcf3ce44SJohn Forte 	if ((c >= '0') && (c <= '9'))
4169fcf3ce44SJohn Forte 		c -= '0';
4170fcf3ce44SJohn Forte 	else if ((c >= 'A') && (c <= 'F'))
4171fcf3ce44SJohn Forte 		c = c - 'A' + 10;
4172fcf3ce44SJohn Forte 	else if ((c >= 'a') && (c <= 'f'))
4173fcf3ce44SJohn Forte 		c = c - 'a' + 10;
4174fcf3ce44SJohn Forte 	else
4175fcf3ce44SJohn Forte 		c = -1;
4176fcf3ce44SJohn Forte 	return (c);
4177fcf3ce44SJohn Forte }
4178fcf3ce44SJohn Forte 
4179fcf3ce44SJohn Forte int
g_string_to_wwn(uchar_t * wwn,uchar_t * wwnp)4180fcf3ce44SJohn Forte g_string_to_wwn(uchar_t *wwn, uchar_t *wwnp)
4181fcf3ce44SJohn Forte {
4182fcf3ce44SJohn Forte 	int	i;
4183fcf3ce44SJohn Forte 	char	c, c1;
4184fcf3ce44SJohn Forte 
4185fcf3ce44SJohn Forte 	*wwnp++ = 0;
4186fcf3ce44SJohn Forte 	*wwnp++ = 0;
4187fcf3ce44SJohn Forte 	for (i = 0; i < WWN_SIZE - 2; i++, wwnp++) {
4188fcf3ce44SJohn Forte 		c = ctoi(*wwn++);
4189fcf3ce44SJohn Forte 		c1 = ctoi(*wwn++);
4190fcf3ce44SJohn Forte 		if (c == -1 || c1 == -1)
4191fcf3ce44SJohn Forte 			return (-1);
4192fcf3ce44SJohn Forte 		*wwnp = ((c << 4) + c1);
4193fcf3ce44SJohn Forte 	}
4194fcf3ce44SJohn Forte 
4195fcf3ce44SJohn Forte 	return (0);
4196fcf3ce44SJohn Forte 
4197fcf3ce44SJohn Forte }
4198fcf3ce44SJohn Forte 
4199fcf3ce44SJohn Forte /*
4200fcf3ce44SJohn Forte  * Converts a string of WWN ASCII characters to a
4201fcf3ce44SJohn Forte  * binary representation.
4202fcf3ce44SJohn Forte  *
4203fcf3ce44SJohn Forte  * Input: string - pointer to uchar_t array
4204fcf3ce44SJohn Forte  *		WWN in ASCII
4205fcf3ce44SJohn Forte  *		length: 16 bytes
4206fcf3ce44SJohn Forte  * Output: wwn - pointer to uchar_t array
4207fcf3ce44SJohn Forte  *		containing WWN result
4208fcf3ce44SJohn Forte  *		length: 8 bytes
4209fcf3ce44SJohn Forte  * Returns:
4210fcf3ce44SJohn Forte  *	non-zero on error
4211fcf3ce44SJohn Forte  *	zero on success
4212fcf3ce44SJohn Forte  */
4213fcf3ce44SJohn Forte int
string_to_wwn(uchar_t * string,uchar_t * wwn)4214fcf3ce44SJohn Forte string_to_wwn(uchar_t *string, uchar_t *wwn)
4215fcf3ce44SJohn Forte {
4216fcf3ce44SJohn Forte 	int	i;
4217fcf3ce44SJohn Forte 	char	c, c1;
4218fcf3ce44SJohn Forte 	uchar_t *wwnp;
4219fcf3ce44SJohn Forte 
4220fcf3ce44SJohn Forte 	wwnp = wwn;
4221fcf3ce44SJohn Forte 
4222fcf3ce44SJohn Forte 	for (i = 0; i < WWN_SIZE; i++, wwnp++) {
4223fcf3ce44SJohn Forte 
4224fcf3ce44SJohn Forte 		c = ctoi(*string++);
4225fcf3ce44SJohn Forte 		c1 = ctoi(*string++);
4226fcf3ce44SJohn Forte 		if (c == -1 || c1 == -1)
4227fcf3ce44SJohn Forte 			return (-1);
4228fcf3ce44SJohn Forte 		*wwnp = ((c << 4) + c1);
4229fcf3ce44SJohn Forte 	}
4230fcf3ce44SJohn Forte 
4231fcf3ce44SJohn Forte 	return (0);
4232fcf3ce44SJohn Forte 
4233fcf3ce44SJohn Forte }
4234fcf3ce44SJohn Forte 
4235fcf3ce44SJohn Forte 
4236fcf3ce44SJohn Forte /*
4237fcf3ce44SJohn Forte  * Get multiple paths to a given device port.
4238fcf3ce44SJohn Forte  * INPUTS:
4239fcf3ce44SJohn Forte  *	port WWN string.
4240fcf3ce44SJohn Forte  */
4241fcf3ce44SJohn Forte int
g_get_port_multipath(char * port_wwn_s,struct dlist ** dlh,int verbose)4242fcf3ce44SJohn Forte g_get_port_multipath(char *port_wwn_s, struct dlist **dlh, int verbose)
4243fcf3ce44SJohn Forte {
4244063d642aSBill Gumbrell 	int		err;
4245063d642aSBill Gumbrell 	WWN_list	*wwn_list, *wwn_list_ptr;
4246063d642aSBill Gumbrell 	struct dlist	*dlt, *dl;
4247fcf3ce44SJohn Forte 
4248fcf3ce44SJohn Forte 
4249fcf3ce44SJohn Forte 	/* Initialize list structures. */
4250fcf3ce44SJohn Forte 	dl = *dlh  = dlt = (struct dlist *)NULL;
4251fcf3ce44SJohn Forte 	wwn_list = wwn_list_ptr = NULL;
4252fcf3ce44SJohn Forte 
4253fcf3ce44SJohn Forte 	H_DPRINTF("  g_get_port_multipath: Looking for multiple paths for"
4254063d642aSBill Gumbrell 	    " device with\n    port WWW:"
4255063d642aSBill Gumbrell 	    "%s\n", port_wwn_s);
4256fcf3ce44SJohn Forte 
4257fcf3ce44SJohn Forte 	if (err = g_get_wwn_list(&wwn_list, verbose)) {
4258fcf3ce44SJohn Forte 		return (err);
4259fcf3ce44SJohn Forte 	}
4260fcf3ce44SJohn Forte 
4261fcf3ce44SJohn Forte 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4262063d642aSBill Gumbrell 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
4263fcf3ce44SJohn Forte 		if (strcmp(port_wwn_s, wwn_list_ptr->port_wwn_s) == 0) {
4264fcf3ce44SJohn Forte 			if ((dl = (struct dlist *)
4265063d642aSBill Gumbrell 			    g_zalloc(sizeof (struct dlist))) == NULL) {
4266fcf3ce44SJohn Forte 				while (*dlh != NULL) {
4267fcf3ce44SJohn Forte 					dl = (*dlh)->next;
4268fcf3ce44SJohn Forte 					(void) g_destroy_data(*dlh);
4269fcf3ce44SJohn Forte 					*dlh = dl;
4270fcf3ce44SJohn Forte 				}
4271fcf3ce44SJohn Forte 				(void) g_free_wwn_list(&wwn_list);
4272fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
4273fcf3ce44SJohn Forte 			}
4274fcf3ce44SJohn Forte 			H_DPRINTF("  g_get_port_multipath:"
4275063d642aSBill Gumbrell 			    " Found multipath:\n    %s\n",
4276063d642aSBill Gumbrell 			    wwn_list_ptr->physical_path);
4277fcf3ce44SJohn Forte 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
4278fcf3ce44SJohn Forte 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
4279fcf3ce44SJohn Forte 			if (*dlh == NULL) {
4280fcf3ce44SJohn Forte 				*dlh = dlt = dl;
4281fcf3ce44SJohn Forte 			} else {
4282fcf3ce44SJohn Forte 				dlt->next = dl;
4283fcf3ce44SJohn Forte 				dl->prev = dlt;
4284fcf3ce44SJohn Forte 				dlt = dl;
4285fcf3ce44SJohn Forte 			}
4286fcf3ce44SJohn Forte 		}
4287fcf3ce44SJohn Forte 	}
4288fcf3ce44SJohn Forte 	(void) g_free_wwn_list(&wwn_list);
4289fcf3ce44SJohn Forte 	return (0);
4290fcf3ce44SJohn Forte }
4291fcf3ce44SJohn Forte 
4292fcf3ce44SJohn Forte 
4293fcf3ce44SJohn Forte 
4294fcf3ce44SJohn Forte /*
4295fcf3ce44SJohn Forte  * Get multiple paths to a given disk/tape device.
4296fcf3ce44SJohn Forte  * The arg: devpath should be the physical path to device.
4297fcf3ce44SJohn Forte  *
4298fcf3ce44SJohn Forte  * OUTPUT:
4299fcf3ce44SJohn Forte  *	multipath_list	points to a list of multiple paths to the device.
4300fcf3ce44SJohn Forte  *	NOTE: The caller must free the allocated list (dlist).
4301fcf3ce44SJohn Forte  *
4302fcf3ce44SJohn Forte  * RETURNS:
4303fcf3ce44SJohn Forte  *	0	 if O.K.
4304fcf3ce44SJohn Forte  *	non-zero otherwise
4305fcf3ce44SJohn Forte  */
4306fcf3ce44SJohn Forte int
g_get_multipath(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list,int verbose)4307fcf3ce44SJohn Forte g_get_multipath(char *devpath, struct dlist **multipath_list,
4308063d642aSBill Gumbrell     struct wwn_list_struct *wwn_list, int verbose)
4309fcf3ce44SJohn Forte {
4310063d642aSBill Gumbrell 	int	err;
4311fcf3ce44SJohn Forte 
4312fcf3ce44SJohn Forte 	H_DPRINTF("  g_get_multipath: Looking for multiple paths for"
4313063d642aSBill Gumbrell 	    " device at path: %s\n", devpath);
4314fcf3ce44SJohn Forte 
4315fcf3ce44SJohn Forte 	/* return invalid path if devpath is NULL */
4316fcf3ce44SJohn Forte 	if (devpath == NULL) {
4317fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4318fcf3ce44SJohn Forte 	}
4319fcf3ce44SJohn Forte 	/* return invalid arg if argument is NULL */
4320fcf3ce44SJohn Forte 	if ((multipath_list == NULL) || (wwn_list == NULL)) {
4321fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
4322fcf3ce44SJohn Forte 	}
4323fcf3ce44SJohn Forte 
4324fcf3ce44SJohn Forte 	if (strstr(devpath, DRV_NAME_SSD) != NULL) {
4325fcf3ce44SJohn Forte 		err = get_multipath_disk(devpath, multipath_list, wwn_list);
4326fcf3ce44SJohn Forte 	} else {
4327fcf3ce44SJohn Forte 		err = get_multipath(devpath, multipath_list, wwn_list);
4328fcf3ce44SJohn Forte 	}
4329fcf3ce44SJohn Forte 
4330fcf3ce44SJohn Forte 	return (err);
4331fcf3ce44SJohn Forte }
4332fcf3ce44SJohn Forte 
4333fcf3ce44SJohn Forte 
4334fcf3ce44SJohn Forte /*
4335fcf3ce44SJohn Forte  * Returns multipath information for a ssd device.
4336fcf3ce44SJohn Forte  * Inputs:
4337fcf3ce44SJohn Forte  *	devpath: device path to for requested multipath info
4338fcf3ce44SJohn Forte  *	wwn_list: returned from g_get_wwn_list or devices_get_all
4339fcf3ce44SJohn Forte  * Output:
4340fcf3ce44SJohn Forte  *	multipath_list: dlist list of paths
4341fcf3ce44SJohn Forte  * Returns:
4342fcf3ce44SJohn Forte  *	0 on success
4343fcf3ce44SJohn Forte  *	non-zero on failure
4344fcf3ce44SJohn Forte  */
4345fcf3ce44SJohn Forte int
get_multipath_disk(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list)4346fcf3ce44SJohn Forte get_multipath_disk(char *devpath, struct dlist **multipath_list,
4347063d642aSBill Gumbrell     struct wwn_list_struct *wwn_list)
4348fcf3ce44SJohn Forte {
4349063d642aSBill Gumbrell 	WWN_list	*wwn_list_ptr;
4350063d642aSBill Gumbrell 	struct dlist	*dl = NULL, *dlt = NULL;
4351063d642aSBill Gumbrell 	ddi_devid_t	devid = NULL;
4352063d642aSBill Gumbrell 	int		err;
4353063d642aSBill Gumbrell 	di_node_t	root;
4354063d642aSBill Gumbrell 	struct mplist_struct	*mplistp = NULL, *mplisth = NULL;
4355fcf3ce44SJohn Forte 
4356fcf3ce44SJohn Forte 	if (wwn_list == NULL || multipath_list == NULL || devpath == NULL) {
4357fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
4358fcf3ce44SJohn Forte 	}
4359fcf3ce44SJohn Forte 
4360fcf3ce44SJohn Forte 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
4361fcf3ce44SJohn Forte 		return (L_DEV_SNAPSHOT_FAILED);
4362fcf3ce44SJohn Forte 	}
4363fcf3ce44SJohn Forte 
4364fcf3ce44SJohn Forte 	if ((err = g_devid_get(devpath, &devid, root, SSD_DRVR_NAME)) != 0) {
4365fcf3ce44SJohn Forte 		di_fini(root);
4366fcf3ce44SJohn Forte 		return (err);
4367fcf3ce44SJohn Forte 	}
4368fcf3ce44SJohn Forte 
4369fcf3ce44SJohn Forte 	*multipath_list = (struct dlist *)NULL;
4370fcf3ce44SJohn Forte 	if ((err = devid_get_all(devid, root, SSD_DRVR_NAME, &mplisth)) != 0) {
4371fcf3ce44SJohn Forte 		di_fini(root);
4372fcf3ce44SJohn Forte 		return (err);
4373fcf3ce44SJohn Forte 	}
4374fcf3ce44SJohn Forte 
4375fcf3ce44SJohn Forte 	if (mplisth == NULL) {
4376fcf3ce44SJohn Forte 		di_fini(root);
4377fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
4378fcf3ce44SJohn Forte 	}
4379fcf3ce44SJohn Forte 
4380fcf3ce44SJohn Forte 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4381063d642aSBill Gumbrell 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
4382fcf3ce44SJohn Forte 		/*
4383fcf3ce44SJohn Forte 		 * When a path is found from the list, load the logical
4384fcf3ce44SJohn Forte 		 * and physical dev path
4385fcf3ce44SJohn Forte 		 */
4386fcf3ce44SJohn Forte 		for (mplistp = mplisth; mplistp != NULL;
4387063d642aSBill Gumbrell 		    mplistp = mplistp->next) {
4388063d642aSBill Gumbrell 			if (strncmp(mplistp->devpath,
4389063d642aSBill Gumbrell 			    wwn_list_ptr->physical_path,
4390063d642aSBill Gumbrell 			    strlen(mplistp->devpath)) == 0) {
4391063d642aSBill Gumbrell 
4392063d642aSBill Gumbrell 				/* Load multipath list */
4393063d642aSBill Gumbrell 				if ((dl = (struct dlist *)
4394063d642aSBill Gumbrell 				    calloc(1, sizeof (struct dlist))) == NULL) {
4395063d642aSBill Gumbrell 					while (*multipath_list != NULL) {
4396063d642aSBill Gumbrell 						dl = dlt->next;
4397063d642aSBill Gumbrell 						g_destroy_data(dlt);
4398063d642aSBill Gumbrell 						dlt = dl;
4399063d642aSBill Gumbrell 					}
4400063d642aSBill Gumbrell 					di_fini(root);
4401063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
4402063d642aSBill Gumbrell 				}
4403063d642aSBill Gumbrell 				H_DPRINTF(
4404063d642aSBill Gumbrell 				    "  g_get_multipath: Found multipath=%s\n",
4405063d642aSBill Gumbrell 				    wwn_list_ptr->physical_path);
4406063d642aSBill Gumbrell 				dl->logical_path =
4407063d642aSBill Gumbrell 				    strdup(wwn_list_ptr->logical_path);
4408063d642aSBill Gumbrell 				dl->dev_path =
4409063d642aSBill Gumbrell 				    strdup(wwn_list_ptr->physical_path);
4410063d642aSBill Gumbrell 				if (*multipath_list == NULL) {
4411063d642aSBill Gumbrell 					*multipath_list = dlt = dl;
4412063d642aSBill Gumbrell 				} else {
4413063d642aSBill Gumbrell 					dlt->next = dl;
4414063d642aSBill Gumbrell 					dl->prev = dlt;
4415fcf3ce44SJohn Forte 					dlt = dl;
4416fcf3ce44SJohn Forte 				}
4417fcf3ce44SJohn Forte 			}
4418fcf3ce44SJohn Forte 		}
4419fcf3ce44SJohn Forte 	}
4420fcf3ce44SJohn Forte 	di_fini(root);
4421fcf3ce44SJohn Forte 	mplist_free(mplisth);
4422fcf3ce44SJohn Forte 	return (0);
4423fcf3ce44SJohn Forte }
4424fcf3ce44SJohn Forte 
4425fcf3ce44SJohn Forte int
get_multipath(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list)4426fcf3ce44SJohn Forte get_multipath(char *devpath, struct dlist **multipath_list,
4427*926d645fSToomas Soome     struct wwn_list_struct *wwn_list)
4428fcf3ce44SJohn Forte {
4429063d642aSBill Gumbrell 	WWN_list	*wwn_list_ptr;
4430063d642aSBill Gumbrell 	struct dlist	*dl, *dlt;
4431063d642aSBill Gumbrell 	char		path[MAXPATHLEN], m_phys_path[MAXPATHLEN], *ptr;
4432063d642aSBill Gumbrell 	int		len;
4433063d642aSBill Gumbrell 	int		lun_a = -1;
4434063d642aSBill Gumbrell 	char		node_wwn_s[WWN_S_LEN];
4435fcf3ce44SJohn Forte 
4436fcf3ce44SJohn Forte 	if (devpath == NULL) {
4437fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4438fcf3ce44SJohn Forte 	}
4439fcf3ce44SJohn Forte 
4440fcf3ce44SJohn Forte 	/* Strip partition information. */
4441fcf3ce44SJohn Forte 	if ((ptr = strrchr(devpath, ':')) != NULL) {
4442fcf3ce44SJohn Forte 		len = strlen(devpath) - strlen(ptr);
4443fcf3ce44SJohn Forte 		(void) strncpy(path, devpath, len);
4444fcf3ce44SJohn Forte 		path[len] = '\0';
4445fcf3ce44SJohn Forte 	} else {
4446fcf3ce44SJohn Forte 		(void) strcpy(path, devpath);
4447fcf3ce44SJohn Forte 	}
4448fcf3ce44SJohn Forte 
4449fcf3ce44SJohn Forte 	*multipath_list = dl = dlt = (struct dlist *)NULL;
4450fcf3ce44SJohn Forte 
4451fcf3ce44SJohn Forte 
4452fcf3ce44SJohn Forte 	if (wwn_list == NULL) {
4453fcf3ce44SJohn Forte 		return (L_NULL_WWN_LIST);
4454fcf3ce44SJohn Forte 	}
4455fcf3ce44SJohn Forte 
4456*926d645fSToomas Soome 	*node_wwn_s = '\0';
4457*926d645fSToomas Soome 	for (wwn_list_ptr = wwn_list;
4458063d642aSBill Gumbrell 	    wwn_list_ptr != NULL;
4459063d642aSBill Gumbrell 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
4460fcf3ce44SJohn Forte 
4461fcf3ce44SJohn Forte 		if ((ptr = strrchr(wwn_list_ptr->physical_path, ':')) != NULL) {
4462fcf3ce44SJohn Forte 			len = strlen(wwn_list_ptr->physical_path) - strlen(ptr);
4463fcf3ce44SJohn Forte 			(void) strncpy(m_phys_path, wwn_list_ptr->physical_path,
4464063d642aSBill Gumbrell 			    len);
4465fcf3ce44SJohn Forte 			m_phys_path[len] = '\0';
4466fcf3ce44SJohn Forte 		} else {
4467fcf3ce44SJohn Forte 			(void) strcpy(m_phys_path, wwn_list_ptr->physical_path);
4468fcf3ce44SJohn Forte 		}
4469fcf3ce44SJohn Forte 
4470fcf3ce44SJohn Forte 		if (strcasecmp(m_phys_path, path) == 0) {
4471fcf3ce44SJohn Forte 			(void) strcpy(node_wwn_s, wwn_list_ptr->node_wwn_s);
4472fcf3ce44SJohn Forte 			break;
4473fcf3ce44SJohn Forte 		}
4474fcf3ce44SJohn Forte 	}
4475fcf3ce44SJohn Forte 
4476*926d645fSToomas Soome 	if (*node_wwn_s == '\0') {
4477*926d645fSToomas Soome 		H_DPRINTF("node_wwn_s is not found!\n");
4478fcf3ce44SJohn Forte 		return (L_NO_NODE_WWN_IN_WWNLIST);
4479fcf3ce44SJohn Forte 	}
4480fcf3ce44SJohn Forte 
4481fcf3ce44SJohn Forte 	lun_a = g_get_lun_number(wwn_list_ptr->physical_path);
4482fcf3ce44SJohn Forte 
4483fcf3ce44SJohn Forte 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4484063d642aSBill Gumbrell 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
4485fcf3ce44SJohn Forte 		if ((strcmp(node_wwn_s, wwn_list_ptr->node_wwn_s) == 0) &&
4486063d642aSBill Gumbrell 		    ((lun_a < 0) || (lun_a ==
4487063d642aSBill Gumbrell 		    g_get_lun_number(wwn_list_ptr->physical_path)))) {
4488fcf3ce44SJohn Forte 
4489fcf3ce44SJohn Forte 			if ((dl = (struct dlist *)
4490063d642aSBill Gumbrell 			    g_zalloc(sizeof (struct dlist))) == NULL) {
4491fcf3ce44SJohn Forte 				while (*multipath_list != NULL) {
4492fcf3ce44SJohn Forte 					dl = dlt->next;
4493fcf3ce44SJohn Forte 					(void) g_destroy_data(dlt);
4494fcf3ce44SJohn Forte 					dlt = dl;
4495fcf3ce44SJohn Forte 				}
4496fcf3ce44SJohn Forte 				return (L_MALLOC_FAILED);
4497fcf3ce44SJohn Forte 			}
4498fcf3ce44SJohn Forte 			H_DPRINTF("  g_get_multipath: Found multipath=%s\n",
4499063d642aSBill Gumbrell 			    wwn_list_ptr->physical_path);
4500fcf3ce44SJohn Forte 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
4501fcf3ce44SJohn Forte 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
4502fcf3ce44SJohn Forte 			if (*multipath_list == NULL) {
4503fcf3ce44SJohn Forte 				*multipath_list = dlt = dl;
4504fcf3ce44SJohn Forte 			} else {
4505fcf3ce44SJohn Forte 				dlt->next = dl;
4506fcf3ce44SJohn Forte 				dl->prev = dlt;
4507fcf3ce44SJohn Forte 				dlt = dl;
4508fcf3ce44SJohn Forte 			}
4509fcf3ce44SJohn Forte 		}
4510fcf3ce44SJohn Forte 	}
4511fcf3ce44SJohn Forte 	return (0);
4512fcf3ce44SJohn Forte }
4513fcf3ce44SJohn Forte 
4514fcf3ce44SJohn Forte /*
4515fcf3ce44SJohn Forte  * Free a multipath list
4516fcf3ce44SJohn Forte  *
4517fcf3ce44SJohn Forte  */
4518fcf3ce44SJohn Forte void
g_free_multipath(struct dlist * dlh)4519fcf3ce44SJohn Forte g_free_multipath(struct dlist *dlh)
4520fcf3ce44SJohn Forte {
4521063d642aSBill Gumbrell 	struct dlist	*dl;
4522fcf3ce44SJohn Forte 
4523fcf3ce44SJohn Forte 	while (dlh != NULL) {
4524fcf3ce44SJohn Forte 		dl = dlh->next;
4525fcf3ce44SJohn Forte 		if (dlh->dev_path != NULL)
4526fcf3ce44SJohn Forte 			(void) g_destroy_data(dlh->dev_path);
4527fcf3ce44SJohn Forte 		if (dlh->logical_path != NULL)
4528fcf3ce44SJohn Forte 			(void) g_destroy_data(dlh->logical_path);
4529fcf3ce44SJohn Forte 		(void) g_destroy_data(dlh);
4530fcf3ce44SJohn Forte 		dlh = dl;
4531fcf3ce44SJohn Forte 	}
4532fcf3ce44SJohn Forte }
4533fcf3ce44SJohn Forte 
4534fcf3ce44SJohn Forte 
4535fcf3ce44SJohn Forte 
4536fcf3ce44SJohn Forte /*
4537fcf3ce44SJohn Forte  * Get the path to the nexus (HBA) driver.
4538fcf3ce44SJohn Forte  * This assumes the path looks something like this:
4539fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4540fcf3ce44SJohn Forte  * or maybe this
4541fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
4542fcf3ce44SJohn Forte  * or
4543fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0
4544fcf3ce44SJohn Forte  * or
4545fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0:1
4546fcf3ce44SJohn Forte  * or
4547fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4548fcf3ce44SJohn Forte  * (or "qlc" instead of "socal" and "fp" for "sf")
4549fcf3ce44SJohn Forte  *
4550fcf3ce44SJohn Forte  * Which should resolve to a path like this:
4551fcf3ce44SJohn Forte  * /devices/sbus@1f,0/SUNW,socal@1,0:1
4552fcf3ce44SJohn Forte  * or
4553fcf3ce44SJohn Forte  * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4554fcf3ce44SJohn Forte  *
4555fcf3ce44SJohn Forte  * or
4556fcf3ce44SJohn Forte  * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
4557fcf3ce44SJohn Forte  * which should resolve to
4558fcf3ce44SJohn Forte  * /devices/pci@4,2000/scsi@1:devctl
4559fcf3ce44SJohn Forte  */
4560fcf3ce44SJohn Forte int
g_get_nexus_path(char * path_phys,char ** nexus_path)4561fcf3ce44SJohn Forte g_get_nexus_path(char *path_phys, char **nexus_path)
4562fcf3ce44SJohn Forte {
4563063d642aSBill Gumbrell 	uchar_t		port = 0;
4564063d642aSBill Gumbrell 	int		port_flag = 0, i = 0, pathcnt = 1;
4565063d642aSBill Gumbrell 	char		*char_ptr;
4566063d642aSBill Gumbrell 	char		drvr_path[MAXPATHLEN];
4567063d642aSBill Gumbrell 	char		buf[MAXPATHLEN];
4568063d642aSBill Gumbrell 	char		temp_buf[MAXPATHLEN];
4569063d642aSBill Gumbrell 	struct stat	stbuf;
4570063d642aSBill Gumbrell 	uint_t		path_type;
4571063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
4572063d642aSBill Gumbrell 	int		p_on = 0, p_st = 0;
4573fcf3ce44SJohn Forte 
4574fcf3ce44SJohn Forte 	/* return invalid path if the path_phys is NULL */
4575fcf3ce44SJohn Forte 	if (path_phys == NULL) {
4576fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4577fcf3ce44SJohn Forte 	}
4578fcf3ce44SJohn Forte 
4579fcf3ce44SJohn Forte 	*nexus_path = NULL;
4580fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path_phys);
4581fcf3ce44SJohn Forte 
4582fcf3ce44SJohn Forte 	if (strstr(path_phys, SCSI_VHCI)) {
4583fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path, &pathlist)) {
4584fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4585fcf3ce44SJohn Forte 		}
4586fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
4587fcf3ce44SJohn Forte 		p_on = p_st = 0;
4588fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
4589fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
4590fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
4591063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_ONLINE) {
4592fcf3ce44SJohn Forte 					p_on = i;
4593fcf3ce44SJohn Forte 					break;
4594fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
4595063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_STANDBY) {
4596fcf3ce44SJohn Forte 					p_st = i;
4597fcf3ce44SJohn Forte 				}
4598fcf3ce44SJohn Forte 			}
4599fcf3ce44SJohn Forte 		}
4600fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
4601fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
4602fcf3ce44SJohn Forte 			/* on_line path */
4603fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4604063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_hba);
4605fcf3ce44SJohn Forte 		} else {
4606fcf3ce44SJohn Forte 			/* standby or path0 */
4607fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4608063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_hba);
4609fcf3ce44SJohn Forte 		}
4610fcf3ce44SJohn Forte 		free(pathlist.path_info);
4611fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
4612fcf3ce44SJohn Forte 	} else {
4613fcf3ce44SJohn Forte 		if (strstr(drvr_path, DRV_NAME_SSD) || strstr(drvr_path,
4614063d642aSBill Gumbrell 		    DRV_NAME_ST) || strstr(drvr_path, SES_NAME)) {
4615fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4616fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
4617fcf3ce44SJohn Forte 			}
4618fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate string  */
4619fcf3ce44SJohn Forte 		}
4620fcf3ce44SJohn Forte 
4621fcf3ce44SJohn Forte 	path_type = g_get_path_type(drvr_path);
4622fcf3ce44SJohn Forte 
4623fcf3ce44SJohn Forte 	if (path_type & FC4_SF_XPORT) {
4624fcf3ce44SJohn Forte 
4625fcf3ce44SJohn Forte 		/* sf driver in path so capture the port # */
4626fcf3ce44SJohn Forte 		if ((char_ptr = strstr(drvr_path, "sf@")) == NULL) {
4627fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
4628fcf3ce44SJohn Forte 		}
4629fcf3ce44SJohn Forte 		port = atoi(char_ptr + 3);
4630fcf3ce44SJohn Forte 		if (port > 1) {
4631fcf3ce44SJohn Forte 			return (L_INVLD_PORT_IN_PATH);
4632fcf3ce44SJohn Forte 		}
4633fcf3ce44SJohn Forte 
4634fcf3ce44SJohn Forte 		if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4635fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4636fcf3ce44SJohn Forte 		}
4637fcf3ce44SJohn Forte 		*char_ptr = '\0';   /* Terminate string  */
4638fcf3ce44SJohn Forte 		port_flag++;
4639fcf3ce44SJohn Forte 
4640fcf3ce44SJohn Forte 		L_DPRINTF("  g_get_nexus_path:"
4641063d642aSBill Gumbrell 		    " sf driver in path so use port #%d.\n",
4642063d642aSBill Gumbrell 		    port);
4643fcf3ce44SJohn Forte 	} else if (path_type & FC_GEN_XPORT) {
4644fcf3ce44SJohn Forte 		/*
4645fcf3ce44SJohn Forte 		 * check to see if it 3rd party vendor FCA.
4646fcf3ce44SJohn Forte 		 * if it is return error for this operation since
4647fcf3ce44SJohn Forte 		 * we don't know how they creates FCA port related minor node.
4648fcf3ce44SJohn Forte 		 *
4649fcf3ce44SJohn Forte 		 * As of now there is no supported operation on FCA node so
4650fcf3ce44SJohn Forte 		 * this should be okay.
4651fcf3ce44SJohn Forte 		 */
4652fcf3ce44SJohn Forte 		if ((path_type & FC_FCA_MASK) == FC_FCA_MASK) {
4653fcf3ce44SJohn Forte 			return (L_INVALID_PATH_TYPE);
4654fcf3ce44SJohn Forte 		}
4655fcf3ce44SJohn Forte 		/*
4656fcf3ce44SJohn Forte 		 * For current Sun FCA driver, appending
4657fcf3ce44SJohn Forte 		 * port # doesn't work. Just remove transport layer from
4658fcf3ce44SJohn Forte 		 * input path.
4659fcf3ce44SJohn Forte 		 */
4660fcf3ce44SJohn Forte 		if ((char_ptr = strstr(drvr_path, "/fp@")) == NULL) {
4661fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4662fcf3ce44SJohn Forte 		}
4663fcf3ce44SJohn Forte 		*char_ptr = '\0';   /* Terminate string  */
4664fcf3ce44SJohn Forte 	}
4665fcf3ce44SJohn Forte 
4666fcf3ce44SJohn Forte 	if (stat(drvr_path, &stbuf) != 0) {
4667fcf3ce44SJohn Forte 		return (L_LSTAT_ERROR);
4668fcf3ce44SJohn Forte 	}
4669fcf3ce44SJohn Forte 
4670fcf3ce44SJohn Forte 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
4671fcf3ce44SJohn Forte 		/*
4672fcf3ce44SJohn Forte 		 * Found a directory.
4673fcf3ce44SJohn Forte 		 * Now append a port number or devctl to the path.
4674fcf3ce44SJohn Forte 		 */
4675fcf3ce44SJohn Forte 		if (port_flag) {
4676fcf3ce44SJohn Forte 			/* append port */
4677fcf3ce44SJohn Forte 			(void) sprintf(buf, ":%d", port);
4678fcf3ce44SJohn Forte 		} else {
4679fcf3ce44SJohn Forte 			/* Try adding port 0 and see if node exists. */
4680fcf3ce44SJohn Forte 			(void) sprintf(temp_buf, "%s:0", drvr_path);
4681fcf3ce44SJohn Forte 			if (stat(temp_buf, &stbuf) != 0) {
4682fcf3ce44SJohn Forte 				/*
4683fcf3ce44SJohn Forte 				 * Path we guessed at does not
4684fcf3ce44SJohn Forte 				 * exist so it may be a driver
4685fcf3ce44SJohn Forte 				 * that ends in :devctl.
4686fcf3ce44SJohn Forte 				 */
4687fcf3ce44SJohn Forte 				(void) sprintf(buf, ":devctl");
4688fcf3ce44SJohn Forte 			} else {
4689fcf3ce44SJohn Forte 				/*
4690fcf3ce44SJohn Forte 				 * The path that was entered
4691fcf3ce44SJohn Forte 				 * did not include a port number
4692fcf3ce44SJohn Forte 				 * so the port was set to zero, and
4693fcf3ce44SJohn Forte 				 * then checked. The default path
4694fcf3ce44SJohn Forte 				 * did exist.
4695fcf3ce44SJohn Forte 				 */
4696fcf3ce44SJohn Forte 				ER_DPRINTF("Since a complete path"
4697063d642aSBill Gumbrell 				    " was not supplied "
4698063d642aSBill Gumbrell 				    "a default path is being"
4699063d642aSBill Gumbrell 				    " used:\n  %s\n",
4700063d642aSBill Gumbrell 				    temp_buf);
4701fcf3ce44SJohn Forte 				(void) sprintf(buf, ":0");
4702fcf3ce44SJohn Forte 			}
4703fcf3ce44SJohn Forte 		}
4704fcf3ce44SJohn Forte 
4705fcf3ce44SJohn Forte 		(void) strcat(drvr_path, buf);
4706fcf3ce44SJohn Forte 	}
4707fcf3ce44SJohn Forte 
4708fcf3ce44SJohn Forte 	}
4709fcf3ce44SJohn Forte 	*nexus_path = g_alloc_string(drvr_path);
4710fcf3ce44SJohn Forte 	L_DPRINTF("  g_get_nexus_path: Nexus path = %s\n", drvr_path);
4711fcf3ce44SJohn Forte 	return (0);
4712fcf3ce44SJohn Forte }
4713fcf3ce44SJohn Forte 
4714fcf3ce44SJohn Forte 
4715fcf3ce44SJohn Forte /*
4716fcf3ce44SJohn Forte  * Get the FC topology for the input device or nexus(HBA) path.
4717fcf3ce44SJohn Forte  *
4718fcf3ce44SJohn Forte  * The routine calls g_get_path_type to determine the stack of
4719fcf3ce44SJohn Forte  * the input path.
4720fcf3ce44SJohn Forte  *
4721*926d645fSToomas Soome  *	If it a socal path
4722fcf3ce44SJohn Forte  *		it returns FC_TOP_PRIVATE_LOOP
4723fcf3ce44SJohn Forte  *	else
4724fcf3ce44SJohn Forte  *		calls fc_get_topology ioctl to
4725fcf3ce44SJohn Forte  *		get the fp topolgy from the driver.
4726fcf3ce44SJohn Forte  *
4727fcf3ce44SJohn Forte  * INPUTS:
4728fcf3ce44SJohn Forte  *	path - a string of device path, transport path.
4729fcf3ce44SJohn Forte  *		NOTE:  "path" SHOULD NOT BE OPEN BEFORE CALLING
4730fcf3ce44SJohn Forte  *			THIS FUNCTION BECAUSE THIS FUNCTION DOES
4731fcf3ce44SJohn Forte  *			AN "O_EXCL" OPEN.
4732fcf3ce44SJohn Forte  *	port_top - a pointer to the toplogy type.
4733fcf3ce44SJohn Forte  *
4734fcf3ce44SJohn Forte  * RETURNS:
4735fcf3ce44SJohn Forte  *	0 if there is no error.
4736fcf3ce44SJohn Forte  *	error code.
4737fcf3ce44SJohn Forte  *
4738fcf3ce44SJohn Forte  * The input path is expected to be something like below:
4739*926d645fSToomas Soome  *	1)
4740*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4741*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@..
4742*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
4743*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0
4744*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0:1
4745*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4746*926d645fSToomas Soome  *	(or "qlc" instead of "socal" and "fp" for "sf")
4747fcf3ce44SJohn Forte  *
4748*926d645fSToomas Soome  *	Which should resolve to a path like this:
4749*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0:1
4750*926d645fSToomas Soome  *	/devices/pci@6,2000/pci@2/SUNW,qlc@5
4751fcf3ce44SJohn Forte  *
4752*926d645fSToomas Soome  *	2)
4753*926d645fSToomas Soome  *	/devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
4754*926d645fSToomas Soome  *	which should resolve to
4755*926d645fSToomas Soome  *	/devices/pci@4,2000/scsi@1:devctl
4756fcf3ce44SJohn Forte  *
4757*926d645fSToomas Soome  *	3) The nexus(hba or nexus) path will get an error only for qlc
4758fcf3ce44SJohn Forte  *	since the routine need to open fp :devctl node for fcio ioctl.
4759*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0
4760*926d645fSToomas Soome  *	/devices/sbus@1f,0/SUNW,socal@1,0:1
4761*926d645fSToomas Soome  *	/devices/pci@6,2000/pci@2/SUNW,qlc@5 => error
4762fcf3ce44SJohn Forte  */
4763fcf3ce44SJohn Forte int
g_get_fca_port_topology(char * path,uint32_t * port_top,int verbose)4764fcf3ce44SJohn Forte g_get_fca_port_topology(char *path, uint32_t *port_top, int verbose)
4765fcf3ce44SJohn Forte {
4766063d642aSBill Gumbrell 	fcio_t		fcio;
4767063d642aSBill Gumbrell 	int		fd, i = 0, pathcnt = 1;
4768063d642aSBill Gumbrell 	char		drvr_path[MAXPATHLEN];
4769063d642aSBill Gumbrell 	char		*char_ptr;
4770063d642aSBill Gumbrell 	struct stat	stbuf;
4771063d642aSBill Gumbrell 	uint_t		dev_type;
4772063d642aSBill Gumbrell 	mp_pathlist_t	pathlist;
4773063d642aSBill Gumbrell 	int		p_on = 0, p_st = 0;
4774fcf3ce44SJohn Forte 
4775fcf3ce44SJohn Forte 	/* return invalid path if the path is NULL */
4776fcf3ce44SJohn Forte 	if (path == NULL) {
4777fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4778fcf3ce44SJohn Forte 	}
4779fcf3ce44SJohn Forte 	/* return invalid arg if the argument is NULL */
4780fcf3ce44SJohn Forte 	if (port_top == NULL) {
4781fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
4782fcf3ce44SJohn Forte 	}
4783fcf3ce44SJohn Forte 
4784fcf3ce44SJohn Forte 	(void) strcpy(drvr_path, path);
4785fcf3ce44SJohn Forte 	if (strstr(path, SCSI_VHCI)) {
4786fcf3ce44SJohn Forte 		if (g_get_pathlist(drvr_path, &pathlist)) {
4787fcf3ce44SJohn Forte 			return (L_INVALID_PATH);
4788fcf3ce44SJohn Forte 		}
4789fcf3ce44SJohn Forte 		pathcnt = pathlist.path_count;
4790fcf3ce44SJohn Forte 		p_on = p_st = 0;
4791fcf3ce44SJohn Forte 		for (i = 0; i < pathcnt; i++) {
4792fcf3ce44SJohn Forte 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
4793fcf3ce44SJohn Forte 				if (pathlist.path_info[i].path_state ==
4794063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_ONLINE) {
4795fcf3ce44SJohn Forte 					p_on = i;
4796fcf3ce44SJohn Forte 					break;
4797fcf3ce44SJohn Forte 				} else if (pathlist.path_info[i].path_state ==
4798063d642aSBill Gumbrell 				    MDI_PATHINFO_STATE_STANDBY) {
4799fcf3ce44SJohn Forte 					p_st = i;
4800fcf3ce44SJohn Forte 				}
4801fcf3ce44SJohn Forte 			}
4802fcf3ce44SJohn Forte 		}
4803fcf3ce44SJohn Forte 		if (pathlist.path_info[p_on].path_state ==
4804fcf3ce44SJohn Forte 		    MDI_PATHINFO_STATE_ONLINE) {
4805fcf3ce44SJohn Forte 			/* on_line path */
4806fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4807063d642aSBill Gumbrell 			    pathlist.path_info[p_on].path_hba);
4808fcf3ce44SJohn Forte 		} else {
4809fcf3ce44SJohn Forte 			/* standby or path0 */
4810fcf3ce44SJohn Forte 			(void) strcpy(drvr_path,
4811063d642aSBill Gumbrell 			    pathlist.path_info[p_st].path_hba);
4812fcf3ce44SJohn Forte 		}
4813fcf3ce44SJohn Forte 		free(pathlist.path_info);
4814fcf3ce44SJohn Forte 		(void) strcat(drvr_path, FC_CTLR);
4815fcf3ce44SJohn Forte 	} else {
4816fcf3ce44SJohn Forte 	/*
4817fcf3ce44SJohn Forte 	 * Get the path to the :devctl driver
4818fcf3ce44SJohn Forte 	 *
4819fcf3ce44SJohn Forte 	 * This assumes the path looks something like this:
4820fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
4821fcf3ce44SJohn Forte 	 * or
4822fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
4823fcf3ce44SJohn Forte 	 * or
4824fcf3ce44SJohn Forte 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
4825fcf3ce44SJohn Forte 	 * or
4826fcf3ce44SJohn Forte 	 * a 1 level PCI type driver but still :devctl
4827fcf3ce44SJohn Forte 	 * (or "qlc" in the place of "socal" and "fp" for "sf")
4828fcf3ce44SJohn Forte 	 *
4829fcf3ce44SJohn Forte 	 * The dir below doesn't have corresponding :devctl node.
4830fcf3ce44SJohn Forte 	 * /devices/pci@6,2000/pci@2/SUNW,qlc@5
4831fcf3ce44SJohn Forte 	 * /devices/sbus@2,0/SUNW,socal@1,0
4832fcf3ce44SJohn Forte 	 *
4833fcf3ce44SJohn Forte 	 */
4834fcf3ce44SJohn Forte 		if ((strstr(drvr_path, DRV_NAME_SSD) ||
4835063d642aSBill Gumbrell 		    strstr(drvr_path, SES_NAME)) ||
4836063d642aSBill Gumbrell 		    strstr(drvr_path, DRV_NAME_ST)) {
4837fcf3ce44SJohn Forte 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
4838fcf3ce44SJohn Forte 				return (L_INVALID_PATH);
4839fcf3ce44SJohn Forte 			}
4840fcf3ce44SJohn Forte 			*char_ptr = '\0';   /* Terminate sting  */
4841fcf3ce44SJohn Forte 			/* append controller */
4842fcf3ce44SJohn Forte 			(void) strcat(drvr_path, FC_CTLR);
4843fcf3ce44SJohn Forte 		} else {
4844fcf3ce44SJohn Forte 			if (stat(drvr_path, &stbuf) < 0) {
4845fcf3ce44SJohn Forte 				return (L_LSTAT_ERROR);
4846fcf3ce44SJohn Forte 			}
4847fcf3ce44SJohn Forte 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
4848fcf3ce44SJohn Forte 				/* append controller */
4849fcf3ce44SJohn Forte 				(void) strcat(drvr_path, FC_CTLR);
4850fcf3ce44SJohn Forte 			}
4851fcf3ce44SJohn Forte 		}
4852fcf3ce44SJohn Forte 	}
4853fcf3ce44SJohn Forte 
4854fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(drvr_path)) == 0) {
4855fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4856fcf3ce44SJohn Forte 	}
4857fcf3ce44SJohn Forte 
4858fcf3ce44SJohn Forte 	if ((dev_type & FC4_XPORT_MASK) || (dev_type & FC4_FCA_MASK)) {
4859fcf3ce44SJohn Forte 		*port_top = FC_TOP_PRIVATE_LOOP;
4860fcf3ce44SJohn Forte 		return (0);
4861fcf3ce44SJohn Forte 	}
4862fcf3ce44SJohn Forte 
4863fcf3ce44SJohn Forte 	/* To contiue the path type should be fp :devctl node */
4864fcf3ce44SJohn Forte 	if (!(dev_type & FC_XPORT_MASK)) {
4865fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4866fcf3ce44SJohn Forte 	}
4867fcf3ce44SJohn Forte 
4868fcf3ce44SJohn Forte 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
4869fcf3ce44SJohn Forte 		return (errno);
4870fcf3ce44SJohn Forte 
4871fcf3ce44SJohn Forte 	P_DPRINTF("  g_get_fca_port_topology: Geting topology from:"
4872063d642aSBill Gumbrell 	    " %s\n", drvr_path);
4873fcf3ce44SJohn Forte 
4874fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_TOPOLOGY;
4875fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (uint32_t);
4876fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ;
4877fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)port_top;
4878fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
4879fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n");
4880fcf3ce44SJohn Forte 		close(fd);
4881fcf3ce44SJohn Forte 		return (L_FCIO_GET_TOPOLOGY_FAIL);
4882fcf3ce44SJohn Forte 	}
4883fcf3ce44SJohn Forte 	close(fd);
4884fcf3ce44SJohn Forte 	return (0);
4885fcf3ce44SJohn Forte }
4886fcf3ce44SJohn Forte 
4887fcf3ce44SJohn Forte 
4888fcf3ce44SJohn Forte /*
4889fcf3ce44SJohn Forte  * This functions enables or disables a FCA port depending on the
4890fcf3ce44SJohn Forte  * argument, cmd, passed to it. If cmd is PORT_OFFLINE, the function
4891fcf3ce44SJohn Forte  * tries to disable the port specified by the argument 'phys_path'. If
4892fcf3ce44SJohn Forte  * cmd is PORT_ONLINE, the function tries to enable the port specified
4893fcf3ce44SJohn Forte  * by the argument 'phys_path'.
4894fcf3ce44SJohn Forte  * INPUTS :
4895fcf3ce44SJohn Forte  *	nexus_port_ptr - Pointer to the nexus path of the FCA port to
4896fcf3ce44SJohn Forte  *			operate on
4897fcf3ce44SJohn Forte  *	cmd       - PORT_OFFLINE or PORT_ONLINE
4898fcf3ce44SJohn Forte  * RETURNS :
4899fcf3ce44SJohn Forte  *	0 on success and non-zero otherwise
4900fcf3ce44SJohn Forte  */
4901fcf3ce44SJohn Forte static int
g_set_port_state(char * nexus_port_ptr,int cmd)4902fcf3ce44SJohn Forte g_set_port_state(char *nexus_port_ptr, int cmd)
4903fcf3ce44SJohn Forte {
4904fcf3ce44SJohn Forte 	int	path_type, fd;
4905fcf3ce44SJohn Forte 
4906fcf3ce44SJohn Forte 	if ((path_type = g_get_path_type(nexus_port_ptr)) == 0) {
4907fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
4908fcf3ce44SJohn Forte 	}
4909fcf3ce44SJohn Forte 
4910fcf3ce44SJohn Forte 	if ((fd = g_object_open(nexus_port_ptr, O_NDELAY|O_RDONLY)) == -1) {
4911fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
4912fcf3ce44SJohn Forte 	}
4913fcf3ce44SJohn Forte 
4914fcf3ce44SJohn Forte 	switch (cmd) {
4915fcf3ce44SJohn Forte 		case PORT_OFFLINE:
4916fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
4917fcf3ce44SJohn Forte 				/*
4918fcf3ce44SJohn Forte 				 * Socal/sf drivers -
4919fcf3ce44SJohn Forte 				 * The socal driver currently returns EFAULT
4920fcf3ce44SJohn Forte 				 * even if the ioctl has completed successfully.
4921fcf3ce44SJohn Forte 				 */
4922fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
4923063d642aSBill Gumbrell 				    NULL) == -1) {
4924fcf3ce44SJohn Forte 					close(fd);
4925fcf3ce44SJohn Forte 					return (L_PORT_OFFLINE_FAIL);
4926fcf3ce44SJohn Forte 				}
4927fcf3ce44SJohn Forte 			} else {
4928fcf3ce44SJohn Forte 				/*
4929fcf3ce44SJohn Forte 				 * QLogic card -
4930fcf3ce44SJohn Forte 				 * Can't do much here since the driver currently
4931fcf3ce44SJohn Forte 				 * doesn't support this feature. We'll just fail
4932fcf3ce44SJohn Forte 				 * for now. Support can be added when the driver
4933fcf3ce44SJohn Forte 				 * is enabled with the feature at a later date.
4934fcf3ce44SJohn Forte 				 */
4935fcf3ce44SJohn Forte 				close(fd);
4936fcf3ce44SJohn Forte 				return (L_PORT_OFFLINE_UNSUPPORTED);
4937fcf3ce44SJohn Forte 			}
4938fcf3ce44SJohn Forte 			break;
4939fcf3ce44SJohn Forte 		case PORT_ONLINE:
4940fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
4941fcf3ce44SJohn Forte 				/*
4942fcf3ce44SJohn Forte 				 * Socal/sf drivers
4943fcf3ce44SJohn Forte 				 * The socal driver currently returns EFAULT
4944fcf3ce44SJohn Forte 				 * even if the ioctl has completed successfully.
4945fcf3ce44SJohn Forte 				 */
4946fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
4947fcf3ce44SJohn Forte 					close(fd);
4948fcf3ce44SJohn Forte 					return (L_PORT_ONLINE_FAIL);
4949fcf3ce44SJohn Forte 				}
4950fcf3ce44SJohn Forte 			} else {
4951fcf3ce44SJohn Forte 				/*
4952fcf3ce44SJohn Forte 				 * QLogic card -
4953fcf3ce44SJohn Forte 				 * Can't do much here since the driver currently
4954fcf3ce44SJohn Forte 				 * doesn't support this feature. We'll just fail
4955fcf3ce44SJohn Forte 				 * for now. Support can be added when the driver
4956fcf3ce44SJohn Forte 				 * is enabled with the feature at a later date.
4957fcf3ce44SJohn Forte 				 */
4958fcf3ce44SJohn Forte 				close(fd);
4959fcf3ce44SJohn Forte 				return (L_PORT_ONLINE_UNSUPPORTED);
4960fcf3ce44SJohn Forte 			}
4961fcf3ce44SJohn Forte 			break;
4962fcf3ce44SJohn Forte 		default:
4963fcf3ce44SJohn Forte 			close(fd);
4964fcf3ce44SJohn Forte 			return (-1);
4965fcf3ce44SJohn Forte 	}
4966fcf3ce44SJohn Forte 	close(fd);
4967fcf3ce44SJohn Forte 	return (0);
4968fcf3ce44SJohn Forte }
4969fcf3ce44SJohn Forte 
4970fcf3ce44SJohn Forte /*
4971fcf3ce44SJohn Forte  * The interfaces defined below (g_port_offline() and g_port_online())
4972fcf3ce44SJohn Forte  * are what will be exposed to applications. We will hide g_set_port_state().
4973fcf3ce44SJohn Forte  * They have to be functions (as against macros) because making them
4974fcf3ce44SJohn Forte  * macros will mean exposing g_set_port_state() and we dont want to do that
4975fcf3ce44SJohn Forte  */
4976fcf3ce44SJohn Forte 
4977fcf3ce44SJohn Forte int
g_port_offline(char * path)4978fcf3ce44SJohn Forte g_port_offline(char *path)
4979fcf3ce44SJohn Forte {
4980fcf3ce44SJohn Forte 	return (g_set_port_state(path, PORT_OFFLINE));
4981fcf3ce44SJohn Forte }
4982fcf3ce44SJohn Forte 
4983fcf3ce44SJohn Forte int
g_port_online(char * path)4984fcf3ce44SJohn Forte g_port_online(char *path)
4985fcf3ce44SJohn Forte {
4986fcf3ce44SJohn Forte 	return (g_set_port_state(path, PORT_ONLINE));
4987fcf3ce44SJohn Forte }
4988fcf3ce44SJohn Forte 
4989fcf3ce44SJohn Forte /*
4990fcf3ce44SJohn Forte  * This function sets the loopback mode for a port on a HBA
4991fcf3ce44SJohn Forte  * INPUTS :
4992fcf3ce44SJohn Forte  *	portpath	- Pointer to the path of the FCA port on which to
4993fcf3ce44SJohn Forte  *			set the loopback mode
4994*926d645fSToomas Soome  *	cmd		- EXT_LPBACK
4995fcf3ce44SJohn Forte  *			  INT_LPBACK
4996fcf3ce44SJohn Forte  *			  NO_LPBACK
4997fcf3ce44SJohn Forte  * RETURNS :
4998fcf3ce44SJohn Forte  *	0 on success and non-zero otherwise
4999fcf3ce44SJohn Forte  */
5000fcf3ce44SJohn Forte int
g_loopback_mode(char * portpath,int cmd)5001fcf3ce44SJohn Forte g_loopback_mode(char *portpath, int cmd)
5002fcf3ce44SJohn Forte {
5003fcf3ce44SJohn Forte 	int	path_type, fd;
5004fcf3ce44SJohn Forte 
5005fcf3ce44SJohn Forte 	if ((path_type = g_get_path_type(portpath)) == 0) {
5006fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5007fcf3ce44SJohn Forte 	}
5008fcf3ce44SJohn Forte 
5009fcf3ce44SJohn Forte 	if ((fd = g_object_open(portpath, O_NDELAY|O_RDONLY|O_EXCL)) == -1) {
5010fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
5011fcf3ce44SJohn Forte 	}
5012fcf3ce44SJohn Forte 
5013fcf3ce44SJohn Forte 	/*
5014fcf3ce44SJohn Forte 	 * The loopback calls are currently not fully supported
5015fcf3ce44SJohn Forte 	 * via fp.
5016fcf3ce44SJohn Forte 	 *
5017fcf3ce44SJohn Forte 	 * A fp based general solution is required to support Leadville FCAs
5018fcf3ce44SJohn Forte 	 * including Qlgc and 3rd party FCA. As of now qlgc provides
5019fcf3ce44SJohn Forte 	 * some diag functions like echo through qlc private ioctl
5020fcf3ce44SJohn Forte 	 * which is not supproted by luxadm and libraries.
5021fcf3ce44SJohn Forte 	 */
5022fcf3ce44SJohn Forte 	switch (cmd) {
5023fcf3ce44SJohn Forte 		case EXT_LPBACK:
5024fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
5025fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_LOOPBACK_MANUAL,
5026063d642aSBill Gumbrell 				    NULL) == -1) {
5027fcf3ce44SJohn Forte 					/* Check for previous mode set */
5028fcf3ce44SJohn Forte 					if (errno != EALREADY) {
5029fcf3ce44SJohn Forte 						close(fd);
5030fcf3ce44SJohn Forte 						return (L_LOOPBACK_FAILED);
5031fcf3ce44SJohn Forte 					}
5032fcf3ce44SJohn Forte 				}
5033fcf3ce44SJohn Forte 			} else {
5034fcf3ce44SJohn Forte 				/*
5035fcf3ce44SJohn Forte 				 * Well, it wasn't one of the above cards so..
5036fcf3ce44SJohn Forte 				 */
5037fcf3ce44SJohn Forte 				close(fd);
5038fcf3ce44SJohn Forte 				return (L_LOOPBACK_UNSUPPORTED);
5039fcf3ce44SJohn Forte 			}
5040fcf3ce44SJohn Forte 			break;
5041fcf3ce44SJohn Forte 		case NO_LPBACK:
5042fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
5043fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
5044fcf3ce44SJohn Forte 					close(fd);
5045fcf3ce44SJohn Forte 					return (L_LOOPBACK_FAILED);
5046fcf3ce44SJohn Forte 				}
5047fcf3ce44SJohn Forte 			} else {
5048fcf3ce44SJohn Forte 				/*
5049fcf3ce44SJohn Forte 				 * Well, it wasn't one of the above cards so..
5050fcf3ce44SJohn Forte 				 */
5051fcf3ce44SJohn Forte 				close(fd);
5052fcf3ce44SJohn Forte 				return (L_LOOPBACK_UNSUPPORTED);
5053fcf3ce44SJohn Forte 			}
5054fcf3ce44SJohn Forte 			break;
5055fcf3ce44SJohn Forte 		case INT_LPBACK:
5056fcf3ce44SJohn Forte 			if (path_type & FC4_SOCAL_FCA) {
5057fcf3ce44SJohn Forte 				if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
5058063d642aSBill Gumbrell 				    NULL) == -1) {
5059fcf3ce44SJohn Forte 					/* Check for previous mode set */
5060fcf3ce44SJohn Forte 					if (errno != EALREADY) {
5061fcf3ce44SJohn Forte 						close(fd);
5062fcf3ce44SJohn Forte 						return (L_LOOPBACK_FAILED);
5063fcf3ce44SJohn Forte 					}
5064fcf3ce44SJohn Forte 				}
5065fcf3ce44SJohn Forte 			} else {
5066fcf3ce44SJohn Forte 				/*
5067fcf3ce44SJohn Forte 				 * Well, it wasn't one of the above cards so..
5068fcf3ce44SJohn Forte 				 */
5069fcf3ce44SJohn Forte 				close(fd);
5070fcf3ce44SJohn Forte 				return (L_LOOPBACK_UNSUPPORTED);
5071fcf3ce44SJohn Forte 			}
5072fcf3ce44SJohn Forte 			break;
5073fcf3ce44SJohn Forte 		default:
5074fcf3ce44SJohn Forte 			close(fd);
5075fcf3ce44SJohn Forte 			return (L_LOOPBACK_UNSUPPORTED);
5076fcf3ce44SJohn Forte 	}
5077fcf3ce44SJohn Forte 	close(fd);
5078fcf3ce44SJohn Forte 	return (0);
5079fcf3ce44SJohn Forte }
5080fcf3ce44SJohn Forte 
5081fcf3ce44SJohn Forte /*
5082fcf3ce44SJohn Forte  * g_get_port_state(char *portpath, int port_state)
5083fcf3ce44SJohn Forte  * Purpose: Get port state for a path
5084fcf3ce44SJohn Forte  * Input:   portpath
5085fcf3ce44SJohn Forte  *		set to path of port
5086fcf3ce44SJohn Forte  * Output:  port_state
5087fcf3ce44SJohn Forte  *	Set to one of the following:
5088fcf3ce44SJohn Forte  *		PORT_CONNECTED
5089fcf3ce44SJohn Forte  *		PORT_NOTCONNECTED
5090fcf3ce44SJohn Forte  * Returns: 0 on success
5091fcf3ce44SJohn Forte  *	    non-zero on failure
5092fcf3ce44SJohn Forte  */
5093fcf3ce44SJohn Forte int
g_get_port_state(char * portpath,int * portstate,int verbose)5094fcf3ce44SJohn Forte g_get_port_state(char *portpath, int *portstate, int verbose)
5095fcf3ce44SJohn Forte {
5096fcf3ce44SJohn Forte 	int	fd, err, num_devices = 0;
5097fcf3ce44SJohn Forte 	struct lilpmap	map;
5098fcf3ce44SJohn Forte 	uint_t	dev_type;
5099fcf3ce44SJohn Forte 	gfc_dev_t	map_root;
5100fcf3ce44SJohn Forte 
5101fcf3ce44SJohn Forte 
5102fcf3ce44SJohn Forte 	(void) memset(&map, 0, sizeof (struct lilpmap));
5103fcf3ce44SJohn Forte 
5104fcf3ce44SJohn Forte 	/* return invalid path if portpath is NULL */
5105fcf3ce44SJohn Forte 	if (portpath == NULL) {
5106fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5107fcf3ce44SJohn Forte 	}
5108fcf3ce44SJohn Forte 	/* return invalid arg if argument is NULL */
5109fcf3ce44SJohn Forte 	if ((portpath == NULL) || (portstate == NULL)) {
5110fcf3ce44SJohn Forte 		return (L_INVALID_ARG);
5111fcf3ce44SJohn Forte 	}
5112fcf3ce44SJohn Forte 
5113fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(portpath)) == 0) {
5114fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5115fcf3ce44SJohn Forte 	}
5116fcf3ce44SJohn Forte 
5117fcf3ce44SJohn Forte 	/*
5118fcf3ce44SJohn Forte 	 * FCIO_GETMAP returns error when there are * no devices attached.
5119fcf3ce44SJohn Forte 	 * ENOMEM is returned when no devices are attached.
5120fcf3ce44SJohn Forte 	 * g_get_first_dev returns NULL without error when there is no
5121fcf3ce44SJohn Forte 	 * devices are attached.
5122fcf3ce44SJohn Forte 	 */
5123fcf3ce44SJohn Forte 	if (dev_type & FC_FCA_MASK) {
5124fcf3ce44SJohn Forte 		if ((map_root = g_dev_map_init(portpath, &err,
5125063d642aSBill Gumbrell 		    MAP_XPORT_PROP_ONLY)) == NULL) {
5126fcf3ce44SJohn Forte 			return (err);
5127fcf3ce44SJohn Forte 		}
5128fcf3ce44SJohn Forte 
5129fcf3ce44SJohn Forte 		if (g_get_first_dev(map_root, &err) == NULL) {
5130fcf3ce44SJohn Forte 			/* no device is found if err == 0 */
5131fcf3ce44SJohn Forte 			if (err == L_NO_SUCH_DEV_FOUND) {
5132fcf3ce44SJohn Forte 				*portstate = PORT_NOTCONNECTED;
5133fcf3ce44SJohn Forte 			}
5134fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
5135fcf3ce44SJohn Forte 			return (0);
5136fcf3ce44SJohn Forte 		} else {
5137fcf3ce44SJohn Forte 			/* Device found okay */
5138fcf3ce44SJohn Forte 			*portstate = PORT_CONNECTED;
5139fcf3ce44SJohn Forte 			g_dev_map_fini(map_root);
5140fcf3ce44SJohn Forte 		}
5141fcf3ce44SJohn Forte 
5142fcf3ce44SJohn Forte 	} else {
5143fcf3ce44SJohn Forte 		/* open controller */
5144fcf3ce44SJohn Forte 		if ((fd = g_object_open(portpath, O_NDELAY | O_RDONLY)) == -1) {
5145fcf3ce44SJohn Forte 			return (errno);
5146fcf3ce44SJohn Forte 		}
5147fcf3ce44SJohn Forte 
5148fcf3ce44SJohn Forte 		/*
5149fcf3ce44SJohn Forte 		 * Note: There is only one error returned by this ioctl. ENOMEM.
5150fcf3ce44SJohn Forte 		 * Hence the lack of return on error.
5151fcf3ce44SJohn Forte 		 */
5152fcf3ce44SJohn Forte 		if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
5153fcf3ce44SJohn Forte 			map.lilp_length = 0;
5154fcf3ce44SJohn Forte 		}
5155fcf3ce44SJohn Forte 		num_devices = map.lilp_length;
5156fcf3ce44SJohn Forte 
5157fcf3ce44SJohn Forte 		/* Non-Leadville stacks report the FCA in the count */
5158fcf3ce44SJohn Forte 		*portstate = (num_devices > 1) ? PORT_CONNECTED :
5159063d642aSBill Gumbrell 		    PORT_NOTCONNECTED;
5160fcf3ce44SJohn Forte 		(void) close(fd);
5161fcf3ce44SJohn Forte 	}
5162fcf3ce44SJohn Forte 	return (0);
5163fcf3ce44SJohn Forte }
5164fcf3ce44SJohn Forte 
5165fcf3ce44SJohn Forte /*
5166fcf3ce44SJohn Forte  * g_dev_login(char *port_path, la_wwn_t port_wwn)
5167fcf3ce44SJohn Forte  * Purpose: port login via g_dev_log_in_out()
5168fcf3ce44SJohn Forte  * Input:   port_path
5169fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5170fcf3ce44SJohn Forte  *	    port_wwn
5171fcf3ce44SJohn Forte  *		port wwn of device node to login
5172fcf3ce44SJohn Forte  *
5173fcf3ce44SJohn Forte  * Returns: return code from g_dev_log_in_out()
5174fcf3ce44SJohn Forte  */
5175fcf3ce44SJohn Forte int
g_dev_login(char * port_path,la_wwn_t port_wwn)5176fcf3ce44SJohn Forte g_dev_login(char *port_path, la_wwn_t port_wwn)
5177fcf3ce44SJohn Forte {
5178fcf3ce44SJohn Forte 	return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGIN));
5179fcf3ce44SJohn Forte }
5180fcf3ce44SJohn Forte 
5181fcf3ce44SJohn Forte 
5182fcf3ce44SJohn Forte /*
5183fcf3ce44SJohn Forte  * g_dev_logout(char *port_path, la_wwn_t port_wwn)
5184fcf3ce44SJohn Forte  * Purpose: port login via g_dev_log_in_out()
5185fcf3ce44SJohn Forte  * Input:   port_path
5186fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5187fcf3ce44SJohn Forte  *	    port_wwn
5188fcf3ce44SJohn Forte  *		port wwn of device node to logout
5189fcf3ce44SJohn Forte  *
5190fcf3ce44SJohn Forte  * Returns: return code from g_dev_log_in_out()
5191fcf3ce44SJohn Forte  */
5192fcf3ce44SJohn Forte int
g_dev_logout(char * port_path,la_wwn_t port_wwn)5193fcf3ce44SJohn Forte g_dev_logout(char *port_path, la_wwn_t port_wwn)
5194fcf3ce44SJohn Forte {
5195fcf3ce44SJohn Forte 	return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGOUT));
5196fcf3ce44SJohn Forte }
5197fcf3ce44SJohn Forte 
5198fcf3ce44SJohn Forte 
5199fcf3ce44SJohn Forte /*
5200fcf3ce44SJohn Forte  * g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
5201fcf3ce44SJohn Forte  * Purpose: port login via FCIO_DEV_LOGOUT and port logout via FCIO_DEV_LOGOUT
5202fcf3ce44SJohn Forte  *	    IOCTL requires EXCLUSIVE open.
5203fcf3ce44SJohn Forte  * Input:   port_path
5204fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5205fcf3ce44SJohn Forte  *	    port_wwn
5206fcf3ce44SJohn Forte  *		port wwn of device node to logout
5207fcf3ce44SJohn Forte  *	    cmd
5208fcf3ce44SJohn Forte  *		FCIO_DEV_LOGON or FCIO_DEV_LOGOUT
5209fcf3ce44SJohn Forte  *
5210fcf3ce44SJohn Forte  * Returns: 0 on success
5211fcf3ce44SJohn Forte  *	    non-zero on failure
5212fcf3ce44SJohn Forte  */
5213fcf3ce44SJohn Forte static int
g_dev_log_in_out(char * port_path,la_wwn_t port_wwn,uint16_t cmd)5214fcf3ce44SJohn Forte g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
5215fcf3ce44SJohn Forte {
5216063d642aSBill Gumbrell 	int		fd, err;
5217063d642aSBill Gumbrell 	uint32_t	hba_port_top;
5218063d642aSBill Gumbrell 	fcio_t		fcio;
5219063d642aSBill Gumbrell 	int		verbose = 0;
5220fcf3ce44SJohn Forte 
5221fcf3ce44SJohn Forte 	if ((err = g_get_fca_port_topology(port_path,
5222063d642aSBill Gumbrell 	    &hba_port_top, verbose)) != 0) {
5223fcf3ce44SJohn Forte 		return (err);
5224fcf3ce44SJohn Forte 	}
5225fcf3ce44SJohn Forte 
5226fcf3ce44SJohn Forte 	if (!((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
5227063d642aSBill Gumbrell 	    (hba_port_top == FC_TOP_FABRIC))) {
5228fcf3ce44SJohn Forte 		return (L_OPNOSUPP_ON_TOPOLOGY);
5229fcf3ce44SJohn Forte 	}
5230fcf3ce44SJohn Forte 
5231fcf3ce44SJohn Forte 	/* open controller */
5232fcf3ce44SJohn Forte 	if ((fd = g_object_open(port_path, O_NDELAY | O_RDONLY | O_EXCL)) == -1)
5233fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
5234fcf3ce44SJohn Forte 
5235fcf3ce44SJohn Forte 	/*
5236fcf3ce44SJohn Forte 	 * stores port_wwn to la_wwn_t raw_wwn field
5237fcf3ce44SJohn Forte 	 * and construct fcio structures for FCIO_DEV_LOGIN.
5238fcf3ce44SJohn Forte 	 */
5239fcf3ce44SJohn Forte 	fcio.fcio_cmd = cmd;
5240fcf3ce44SJohn Forte 	fcio.fcio_ilen = sizeof (port_wwn);
5241fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)&port_wwn;
5242fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_WRITE;
5243fcf3ce44SJohn Forte 	fcio.fcio_olen = fcio.fcio_alen = 0;
5244fcf3ce44SJohn Forte 	fcio.fcio_obuf = fcio.fcio_abuf = NULL;
5245fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
5246fcf3ce44SJohn Forte 		I_DPRINTF((cmd == FCIO_DEV_LOGIN) ?
5247063d642aSBill Gumbrell 		    " FCIO_DEV_LOGIN ioctl failed.\n"
5248063d642aSBill Gumbrell 		    : " FCIO_DEV_LOGOUT ioctl failed.\n");
5249fcf3ce44SJohn Forte 		(void) close(fd);
5250fcf3ce44SJohn Forte 		return ((cmd == FCIO_DEV_LOGIN) ?
5251063d642aSBill Gumbrell 		    L_FCIO_DEV_LOGIN_FAIL
5252063d642aSBill Gumbrell 		    : L_FCIO_DEV_LOGOUT_FAIL);
5253fcf3ce44SJohn Forte 	} else {
5254fcf3ce44SJohn Forte 		(void) close(fd);
5255fcf3ce44SJohn Forte 		return (0);
5256fcf3ce44SJohn Forte 	}
5257fcf3ce44SJohn Forte }
5258fcf3ce44SJohn Forte 
5259fcf3ce44SJohn Forte /*
5260fcf3ce44SJohn Forte  * This function will verify if a FC device (represented by input WWN
5261fcf3ce44SJohn Forte  * is connected on a FCA port by searching the device list from
5262fcf3ce44SJohn Forte  * g_get_dev_list() for a WWN match.
5263fcf3ce44SJohn Forte  *
5264fcf3ce44SJohn Forte  * input:
5265fcf3ce44SJohn Forte  *   fca_path: pointer to the physical path string, path to a fp node.
5266fcf3ce44SJohn Forte  *             possible forms are
5267fcf3ce44SJohn Forte  *		/devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl
5268fcf3ce44SJohn Forte  *   dev_wwn: WWN string
5269fcf3ce44SJohn Forte  *   flag: indicate that the input WWN is node or port
5270fcf3ce44SJohn Forte  *
5271fcf3ce44SJohn Forte  * returned values
5272fcf3ce44SJohn Forte  *   0: if a match is found.
5273fcf3ce44SJohn Forte  *   L_WWN_NOT_FOUND_IN_DEV_LIST: if no match found
5274fcf3ce44SJohn Forte  *   L_UNEXPECTED_FC_TOPOLOGY: existing error code for an error
5275fcf3ce44SJohn Forte  *	from the topology checking of the input fca path.
5276fcf3ce44SJohn Forte  *   L_MALLOC_FAILED: existing error code for allocation eror from the
5277fcf3ce44SJohn Forte  *	g_get_dev_list().
5278fcf3ce44SJohn Forte  *   L_FCIO_GETMAP_IOCTL_FAIL: existing error code for an error from the
5279fcf3ce44SJohn Forte  *	FCIO ioctl called by the g_get_dev_list()
5280fcf3ce44SJohn Forte  *   -1: other failure
5281fcf3ce44SJohn Forte  *
5282fcf3ce44SJohn Forte  */
5283fcf3ce44SJohn Forte int
g_wwn_in_dev_list(char * fca_path,la_wwn_t dev_wwn,int flag)5284fcf3ce44SJohn Forte g_wwn_in_dev_list(char *fca_path, la_wwn_t dev_wwn, int flag)
5285fcf3ce44SJohn Forte {
5286063d642aSBill Gumbrell 	uint_t		dev_type;
5287063d642aSBill Gumbrell 	int		i, err;
5288063d642aSBill Gumbrell 	fc_port_dev_t	*dev_list;
5289063d642aSBill Gumbrell 	fc_port_dev_t	*dev_list_save;
5290063d642aSBill Gumbrell 	int		num_devices = 0;
5291fcf3ce44SJohn Forte 
5292fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(fca_path)) == 0) {
5293fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5294fcf3ce44SJohn Forte 	}
5295fcf3ce44SJohn Forte 
5296fcf3ce44SJohn Forte 	if (!(dev_type & FC_XPORT_MASK)) {
5297fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
5298fcf3ce44SJohn Forte 	}
5299fcf3ce44SJohn Forte 
5300fcf3ce44SJohn Forte 	if (((err = g_get_dev_list(fca_path, &dev_list, &num_devices))
5301063d642aSBill Gumbrell 	    != 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) {
5302fcf3ce44SJohn Forte 		return (err);
5303fcf3ce44SJohn Forte 	}
5304fcf3ce44SJohn Forte 
5305fcf3ce44SJohn Forte 	dev_list_save = dev_list;
5306fcf3ce44SJohn Forte 
5307fcf3ce44SJohn Forte 	switch (flag) {
5308fcf3ce44SJohn Forte 	case MATCH_NODE_WWN:
5309fcf3ce44SJohn Forte 		for (i = 0; i < num_devices; i++, dev_list++) {
5310fcf3ce44SJohn Forte 			if (memcmp(dev_list->dev_nwwn.raw_wwn,
5311063d642aSBill Gumbrell 			    dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
5312fcf3ce44SJohn Forte 				(void) free(dev_list_save);
5313fcf3ce44SJohn Forte 				return (0);
5314fcf3ce44SJohn Forte 			}
5315fcf3ce44SJohn Forte 		}
5316fcf3ce44SJohn Forte 		(void) free(dev_list_save);
5317fcf3ce44SJohn Forte 		/* consider a new error code for not found. */
5318fcf3ce44SJohn Forte 		return (L_WWN_NOT_FOUND_IN_DEV_LIST);
5319fcf3ce44SJohn Forte 
5320fcf3ce44SJohn Forte 	case MATCH_PORT_WWN:
5321fcf3ce44SJohn Forte 		for (i = 0; i < num_devices; i++, dev_list++) {
5322fcf3ce44SJohn Forte 			if (memcmp(dev_list->dev_pwwn.raw_wwn,
5323063d642aSBill Gumbrell 			    dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
5324fcf3ce44SJohn Forte 				(void) free(dev_list_save);
5325fcf3ce44SJohn Forte 				return (0);
5326fcf3ce44SJohn Forte 			}
5327fcf3ce44SJohn Forte 		}
5328fcf3ce44SJohn Forte 		(void) free(dev_list_save);
5329fcf3ce44SJohn Forte 		/* consider a new error code for not found. */
5330fcf3ce44SJohn Forte 		return (L_WWN_NOT_FOUND_IN_DEV_LIST);
5331fcf3ce44SJohn Forte 	}
5332fcf3ce44SJohn Forte 	(void) free(dev_list_save);
5333fcf3ce44SJohn Forte 	return (-1);
5334fcf3ce44SJohn Forte }
5335fcf3ce44SJohn Forte 
5336fcf3ce44SJohn Forte 
5337fcf3ce44SJohn Forte /*
5338fcf3ce44SJohn Forte  * g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
5339fcf3ce44SJohn Forte  * Purpose: get the state of device port login via FCIO_GET_STATE ioctl.
5340fcf3ce44SJohn Forte  *
5341fcf3ce44SJohn Forte  * Input:   fca_path
5342fcf3ce44SJohn Forte  *		fc transport port with fabric/public loop topology
5343fcf3ce44SJohn Forte  *	    port_wwn
5344fcf3ce44SJohn Forte  *		port wwn of device node to logout
5345fcf3ce44SJohn Forte  *	    state
5346fcf3ce44SJohn Forte  *		port login or not
5347fcf3ce44SJohn Forte  *
5348fcf3ce44SJohn Forte  * Returns: 0 on success
5349fcf3ce44SJohn Forte  *	    non-zero on failure
5350fcf3ce44SJohn Forte  */
5351fcf3ce44SJohn Forte static int
g_get_dev_port_state(char * fca_path,la_wwn_t port_wwn,uint32_t * state)5352fcf3ce44SJohn Forte g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
5353fcf3ce44SJohn Forte {
5354063d642aSBill Gumbrell 	int		fd;
5355063d642aSBill Gumbrell 	int		dev_type;
5356063d642aSBill Gumbrell 	fcio_t		fcio;
5357063d642aSBill Gumbrell 	int		verbose = 0;
5358fcf3ce44SJohn Forte 
5359fcf3ce44SJohn Forte 	if ((dev_type = g_get_path_type(fca_path)) == 0) {
5360fcf3ce44SJohn Forte 		return (L_INVALID_PATH);
5361fcf3ce44SJohn Forte 	}
5362fcf3ce44SJohn Forte 
5363fcf3ce44SJohn Forte 	if (!(dev_type & FC_XPORT_MASK)) {
5364fcf3ce44SJohn Forte 		return (L_INVALID_PATH_TYPE);
5365fcf3ce44SJohn Forte 	}
5366fcf3ce44SJohn Forte 
5367fcf3ce44SJohn Forte 	/* open controller */
5368fcf3ce44SJohn Forte 	if ((fd = g_object_open(fca_path, O_NDELAY | O_RDONLY)) == -1)
5369fcf3ce44SJohn Forte 		return (L_OPEN_PATH_FAIL);
5370fcf3ce44SJohn Forte 
5371fcf3ce44SJohn Forte 	/*
5372fcf3ce44SJohn Forte 	 * stores port_wwn to la_wwn_t raw_wwn field
5373fcf3ce44SJohn Forte 	 * and construct fcio structures for FCIO_DEV_LOGIN.
5374fcf3ce44SJohn Forte 	 */
5375fcf3ce44SJohn Forte 	fcio.fcio_cmd = FCIO_GET_STATE;
5376fcf3ce44SJohn Forte 	fcio.fcio_ilen = sizeof (port_wwn);
5377fcf3ce44SJohn Forte 	fcio.fcio_ibuf = (caddr_t)&port_wwn;
5378fcf3ce44SJohn Forte 	fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE;
5379fcf3ce44SJohn Forte 	fcio.fcio_olen = sizeof (uint32_t);
5380fcf3ce44SJohn Forte 	fcio.fcio_obuf = (caddr_t)state;
5381fcf3ce44SJohn Forte 	fcio.fcio_alen = 0;
5382fcf3ce44SJohn Forte 	fcio.fcio_abuf = NULL;
5383fcf3ce44SJohn Forte 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
5384fcf3ce44SJohn Forte 		I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
5385fcf3ce44SJohn Forte 		(void) close(fd);
5386fcf3ce44SJohn Forte 		return (L_FCIO_GET_STATE_FAIL);
5387fcf3ce44SJohn Forte 	} else {
5388fcf3ce44SJohn Forte 		(void) close(fd);
5389fcf3ce44SJohn Forte 		return (0);
5390fcf3ce44SJohn Forte 	}
5391fcf3ce44SJohn Forte }
5392fcf3ce44SJohn Forte 
5393fcf3ce44SJohn Forte /*
5394fcf3ce44SJohn Forte  * Name: lilp_map_cmp
5395fcf3ce44SJohn Forte  *
5396fcf3ce44SJohn Forte  * Description: This function is used to compare the physical location
5397fcf3ce44SJohn Forte  *              of to fc devices in a gfc_map_t.dev_addr arrary.
5398fcf3ce44SJohn Forte  *
5399fcf3ce44SJohn Forte  * Params:
5400fcf3ce44SJohn Forte  *	First device to compare
5401fcf3ce44SJohn Forte  *	Second device to compare
5402fcf3ce44SJohn Forte  *
5403fcf3ce44SJohn Forte  * Return:
5404fcf3ce44SJohn Forte  *   0 = Devices at equal phyiscal location, How did this happen?
5405fcf3ce44SJohn Forte  *  >0 = First device have a higher physical location than second
5406fcf3ce44SJohn Forte  *  <0 = Second device have a higher physical location than first
5407fcf3ce44SJohn Forte  */
lilp_map_cmp(const void * dev1,const void * dev2)5408fcf3ce44SJohn Forte static int lilp_map_cmp(const void* dev1, const void* dev2) {
5409fcf3ce44SJohn Forte 	int i_dev1 = ((fc_port_dev_t *)dev1)->dev_did.priv_lilp_posit;
5410fcf3ce44SJohn Forte 	int i_dev2 = ((fc_port_dev_t *)dev2)->dev_did.priv_lilp_posit;
5411fcf3ce44SJohn Forte 
5412fcf3ce44SJohn Forte 	if (i_dev1 > i_dev2)
5413fcf3ce44SJohn Forte 		return (1);
5414fcf3ce44SJohn Forte 	if (i_dev1 < i_dev2)
5415fcf3ce44SJohn Forte 		return (-1);
5416fcf3ce44SJohn Forte 	return (0);
5417fcf3ce44SJohn Forte }
5418fcf3ce44SJohn Forte 
5419fcf3ce44SJohn Forte /*
5420fcf3ce44SJohn Forte  * Description:
5421fcf3ce44SJohn Forte  *    Retrieves multiple paths to a device based on devid
5422fcf3ce44SJohn Forte  *    Caller must use mplist_free to free mplist structure
5423fcf3ce44SJohn Forte  *    This currently only supports ssd devices.
5424fcf3ce44SJohn Forte  *    The st driver does not register a device id.
5425fcf3ce44SJohn Forte  *
5426fcf3ce44SJohn Forte  * Input Values:
5427fcf3ce44SJohn Forte  *
5428fcf3ce44SJohn Forte  *    devid: ptr to valid ddi_devid_t struct
5429fcf3ce44SJohn Forte  *    root: root handle to device tree snapshot
5430fcf3ce44SJohn Forte  *    drvr_name: driver name to start the node tree search
5431fcf3ce44SJohn Forte  *
5432fcf3ce44SJohn Forte  * Return Value:
5433fcf3ce44SJohn Forte  *    0 on success
5434fcf3ce44SJohn Forte  *    non-zero on failure
5435fcf3ce44SJohn Forte  */
5436fcf3ce44SJohn Forte 
5437fcf3ce44SJohn Forte static int
devid_get_all(ddi_devid_t devid,di_node_t root,char * drvr_name,struct mplist_struct ** mplistp)5438fcf3ce44SJohn Forte devid_get_all(ddi_devid_t devid, di_node_t root, char *drvr_name,
5439063d642aSBill Gumbrell     struct mplist_struct **mplistp)
5440fcf3ce44SJohn Forte {
5441063d642aSBill Gumbrell 	ddi_devid_t mydevid;
5442063d642aSBill Gumbrell 	di_node_t node;
5443063d642aSBill Gumbrell 	char *devfs_path = NULL;
5444063d642aSBill Gumbrell 	struct mplist_struct *mpl, *mpln;
5445fcf3ce44SJohn Forte 
5446fcf3ce44SJohn Forte 	if (devid == NULL || root == NULL || drvr_name == NULL ||
5447063d642aSBill Gumbrell 	    mplistp == NULL ||
5448063d642aSBill Gumbrell 	    (strncmp(drvr_name, SSD_DRVR_NAME, strlen(SSD_DRVR_NAME))
5449063d642aSBill Gumbrell 	    != 0)) {
5450fcf3ce44SJohn Forte 		return (EINVAL);
5451fcf3ce44SJohn Forte 	}
5452fcf3ce44SJohn Forte 
5453fcf3ce44SJohn Forte 	*mplistp = mpl = mpln = (struct mplist_struct *)NULL;
5454fcf3ce44SJohn Forte 
5455fcf3ce44SJohn Forte 	/* point to first node which matches portdrvr */
5456fcf3ce44SJohn Forte 	node = di_drv_first_node(drvr_name, root);
5457fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
5458fcf3ce44SJohn Forte 		return (L_NO_DRIVER_NODES_FOUND);
5459fcf3ce44SJohn Forte 	}
5460fcf3ce44SJohn Forte 
5461fcf3ce44SJohn Forte 	while (node != DI_NODE_NIL) {
5462fcf3ce44SJohn Forte 		if ((mydevid = di_devid(node)) != NULL) {
5463fcf3ce44SJohn Forte 			if (((devid_compare(mydevid, devid)) == 0)) {
5464063d642aSBill Gumbrell 				/* Load multipath list */
5465063d642aSBill Gumbrell 				if ((mpl = (struct mplist_struct *)
5466063d642aSBill Gumbrell 				    calloc(1, sizeof (struct mplist_struct)))
5467063d642aSBill Gumbrell 				    == NULL) {
5468063d642aSBill Gumbrell 					mplist_free(*mplistp);
5469063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
5470063d642aSBill Gumbrell 				}
5471063d642aSBill Gumbrell 				if ((devfs_path = my_devfs_path(node)) ==
5472063d642aSBill Gumbrell 				    NULL) {
5473063d642aSBill Gumbrell 					node = di_drv_next_node(node);
5474063d642aSBill Gumbrell 					S_FREE(mpl);
5475063d642aSBill Gumbrell 					continue;
5476063d642aSBill Gumbrell 				}
5477063d642aSBill Gumbrell 				mpl->devpath = (char *)calloc(1,
5478063d642aSBill Gumbrell 				    strlen(devfs_path) +
5479063d642aSBill Gumbrell 				    strlen(SSD_MINOR_NAME) + 1);
5480063d642aSBill Gumbrell 				if (mpl->devpath == NULL) {
5481063d642aSBill Gumbrell 					S_FREE(mpl);
5482063d642aSBill Gumbrell 					mplist_free(*mplistp);
5483063d642aSBill Gumbrell 					my_devfs_path_free(devfs_path);
5484063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
5485063d642aSBill Gumbrell 				}
5486063d642aSBill Gumbrell 				sprintf(mpl->devpath, "%s%s", devfs_path,
5487063d642aSBill Gumbrell 				    SSD_MINOR_NAME);
5488063d642aSBill Gumbrell 				if (*mplistp == NULL) {
5489063d642aSBill Gumbrell 					*mplistp = mpln = mpl;
5490063d642aSBill Gumbrell 				} else {
5491063d642aSBill Gumbrell 					mpln->next = mpl;
5492063d642aSBill Gumbrell 					mpln = mpl;
5493063d642aSBill Gumbrell 				}
5494fcf3ce44SJohn Forte 				my_devfs_path_free(devfs_path);
5495fcf3ce44SJohn Forte 			}
5496fcf3ce44SJohn Forte 		}
5497fcf3ce44SJohn Forte 	node = di_drv_next_node(node);
5498fcf3ce44SJohn Forte 	}
5499fcf3ce44SJohn Forte 	return (0);
5500fcf3ce44SJohn Forte }
5501fcf3ce44SJohn Forte 
5502fcf3ce44SJohn Forte /*
5503fcf3ce44SJohn Forte  * Frees a previously allocated mplist_struct
5504fcf3ce44SJohn Forte  */
5505fcf3ce44SJohn Forte static void
mplist_free(struct mplist_struct * mplistp)5506fcf3ce44SJohn Forte mplist_free(struct mplist_struct *mplistp)
5507fcf3ce44SJohn Forte {
5508063d642aSBill Gumbrell 	struct mplist_struct *mplistn;
5509fcf3ce44SJohn Forte 
5510fcf3ce44SJohn Forte 	while (mplistp != NULL) {
5511fcf3ce44SJohn Forte 		mplistn = mplistp->next;
5512fcf3ce44SJohn Forte 		if (mplistp->devpath != NULL) {
5513fcf3ce44SJohn Forte 			free(mplistp->devpath);
5514fcf3ce44SJohn Forte 			mplistp->devpath = NULL;
5515fcf3ce44SJohn Forte 		}
5516fcf3ce44SJohn Forte 		free(mplistp);
5517fcf3ce44SJohn Forte 		mplistp = mplistn;
5518fcf3ce44SJohn Forte 	}
5519fcf3ce44SJohn Forte }
5520fcf3ce44SJohn Forte 
5521fcf3ce44SJohn Forte /*
5522fcf3ce44SJohn Forte  * Description
5523fcf3ce44SJohn Forte  *	Retrieves all device nodes based on drvr_name
5524fcf3ce44SJohn Forte  *	Currently supports SSD_DRVR_NAME, ST_DRVR_NAME
5525fcf3ce44SJohn Forte  *	There will be a device node in the libdevinfo
5526fcf3ce44SJohn Forte  *	snapshot only if there is at least one node bound.
5527fcf3ce44SJohn Forte  *
5528fcf3ce44SJohn Forte  * Input values:
5529fcf3ce44SJohn Forte  *	root		valid snapshot handle from di_init(3DEVINFO)
5530fcf3ce44SJohn Forte  *	drvr_name	name of driver to start node search
5531fcf3ce44SJohn Forte  *	wwn_list_ptr	ptr to ptr to WWN_list struct
5532fcf3ce44SJohn Forte  *
5533fcf3ce44SJohn Forte  *
5534fcf3ce44SJohn Forte  */
5535fcf3ce44SJohn Forte static int
devices_get_all(di_node_t root,char * drvr_name,char * minor_name,struct wwn_list_struct ** wwn_list_ptr)5536fcf3ce44SJohn Forte devices_get_all(di_node_t root, char *drvr_name, char *minor_name,
5537063d642aSBill Gumbrell     struct wwn_list_struct **wwn_list_ptr)
5538fcf3ce44SJohn Forte {
5539063d642aSBill Gumbrell 	di_node_t node;
5540063d642aSBill Gumbrell 	char *devfs_path;
5541063d642aSBill Gumbrell 	char devicepath[MAXPATHLEN];
5542063d642aSBill Gumbrell 	uchar_t *nwwn = NULL, *pwwn = NULL;
5543063d642aSBill Gumbrell 	uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
5544063d642aSBill Gumbrell 	WWN_list *wwn_list, *l1, *l2;
5545063d642aSBill Gumbrell 	int scsi_vhci = 0;
5546063d642aSBill Gumbrell 	int err, devtype;
5547fcf3ce44SJohn Forte 
5548fcf3ce44SJohn Forte 	if (root == DI_NODE_NIL || drvr_name == NULL ||
5549063d642aSBill Gumbrell 	    wwn_list_ptr == NULL) {
5550fcf3ce44SJohn Forte 		return (EINVAL);
5551fcf3ce44SJohn Forte 	}
5552fcf3ce44SJohn Forte 
5553fcf3ce44SJohn Forte 	wwn_list = *wwn_list_ptr = NULL;
5554fcf3ce44SJohn Forte 
5555fcf3ce44SJohn Forte 	memset(port_wwn, 0, sizeof (port_wwn));
5556fcf3ce44SJohn Forte 	memset(node_wwn, 0, sizeof (node_wwn));
5557fcf3ce44SJohn Forte 
5558fcf3ce44SJohn Forte 	if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
5559fcf3ce44SJohn Forte 		devtype = DTYPE_DIRECT;
5560fcf3ce44SJohn Forte 	} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
5561fcf3ce44SJohn Forte 		devtype = DTYPE_SEQUENTIAL;
5562fcf3ce44SJohn Forte 	} else {
5563fcf3ce44SJohn Forte 		/*
5564fcf3ce44SJohn Forte 		 * An unsupported driver name was passed in
5565fcf3ce44SJohn Forte 		 */
5566fcf3ce44SJohn Forte 		return (L_DRIVER_NOTSUPP);
5567fcf3ce44SJohn Forte 	}
5568fcf3ce44SJohn Forte 
5569fcf3ce44SJohn Forte 	/* point to first node which matches portdrvr */
5570fcf3ce44SJohn Forte 	node = di_drv_first_node(drvr_name, root);
5571fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
5572fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5573fcf3ce44SJohn Forte 	}
5574fcf3ce44SJohn Forte 
5575fcf3ce44SJohn Forte 	while (node != DI_NODE_NIL) {
5576fcf3ce44SJohn Forte 
5577063d642aSBill Gumbrell 		if ((devfs_path = my_devfs_path(node)) != NULL) {
5578fcf3ce44SJohn Forte 
5579063d642aSBill Gumbrell 			/*
5580063d642aSBill Gumbrell 			 * Check for offline state
5581063d642aSBill Gumbrell 			 */
5582063d642aSBill Gumbrell 			if ((di_state(node) &
5583063d642aSBill Gumbrell 			    DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) {
5584063d642aSBill Gumbrell 				my_devfs_path_free(devfs_path);
5585063d642aSBill Gumbrell 				node = di_drv_next_node(node);
5586063d642aSBill Gumbrell 				continue;
5587063d642aSBill Gumbrell 			}
5588fcf3ce44SJohn Forte 
5589063d642aSBill Gumbrell 			/*
5590063d642aSBill Gumbrell 			 * Only support st, ssd nodes
5591063d642aSBill Gumbrell 			 */
5592063d642aSBill Gumbrell 			if (!strstr(devfs_path, SLSH_DRV_NAME_SSD) &&
5593063d642aSBill Gumbrell 			    !strstr(devfs_path, SLSH_DRV_NAME_ST)) {
5594063d642aSBill Gumbrell 				my_devfs_path_free(devfs_path);
5595063d642aSBill Gumbrell 				node = di_drv_next_node(node);
5596063d642aSBill Gumbrell 				continue;
5597063d642aSBill Gumbrell 			}
5598fcf3ce44SJohn Forte 
5599063d642aSBill Gumbrell 			devicepath[0] = '\0';
5600fcf3ce44SJohn Forte 
5601063d642aSBill Gumbrell 			/*
5602063d642aSBill Gumbrell 			 * form device path
5603063d642aSBill Gumbrell 			 */
5604063d642aSBill Gumbrell 			sprintf(devicepath, "%s%s", devfs_path, minor_name);
5605fcf3ce44SJohn Forte 
5606063d642aSBill Gumbrell 			if ((strstr(devicepath, SCSI_VHCI) == NULL)) {
5607063d642aSBill Gumbrell 				if ((err = get_wwn_data(node, &nwwn, &pwwn)) !=
5608063d642aSBill Gumbrell 				    0) {
5609063d642aSBill Gumbrell 					my_devfs_path_free(devfs_path);
5610063d642aSBill Gumbrell 					return (err);
5611063d642aSBill Gumbrell 				} else {
5612063d642aSBill Gumbrell 					memcpy(node_wwn, nwwn,
5613063d642aSBill Gumbrell 					    sizeof (node_wwn));
5614063d642aSBill Gumbrell 					memcpy(port_wwn, pwwn,
5615063d642aSBill Gumbrell 					    sizeof (port_wwn));
5616063d642aSBill Gumbrell 				}
5617fcf3ce44SJohn Forte 			} else {
5618063d642aSBill Gumbrell 				/*
5619063d642aSBill Gumbrell 				 * Clear values for SCSI VHCI devices.
5620063d642aSBill Gumbrell 				 * node wwn, port wwn are irrevelant at
5621063d642aSBill Gumbrell 				 * the SCSI VHCI level
5622063d642aSBill Gumbrell 				 */
5623063d642aSBill Gumbrell 				scsi_vhci++;
5624063d642aSBill Gumbrell 				memset(port_wwn, 0, sizeof (port_wwn));
5625063d642aSBill Gumbrell 				memset(node_wwn, 0, sizeof (node_wwn));
5626fcf3ce44SJohn Forte 			}
5627fcf3ce44SJohn Forte 
5628063d642aSBill Gumbrell 			/* Got wwns, load data in list */
5629063d642aSBill Gumbrell 			if ((l2 = (struct  wwn_list_struct *)
5630063d642aSBill Gumbrell 			    calloc(1, sizeof (struct  wwn_list_struct))) ==
5631063d642aSBill Gumbrell 			    NULL) {
5632063d642aSBill Gumbrell 				my_devfs_path_free(devfs_path);
5633063d642aSBill Gumbrell 				return (L_MALLOC_FAILED);
5634063d642aSBill Gumbrell 			}
5635063d642aSBill Gumbrell 			if ((l2->physical_path = (char *)
5636063d642aSBill Gumbrell 			    calloc(1, strlen(devicepath) +1)) == NULL) {
5637063d642aSBill Gumbrell 				my_devfs_path_free(devfs_path);
5638063d642aSBill Gumbrell 				return (L_MALLOC_FAILED);
5639063d642aSBill Gumbrell 			}
5640fcf3ce44SJohn Forte 
5641063d642aSBill Gumbrell 			memcpy(l2->w_node_wwn, node_wwn, WWN_SIZE);
5642fcf3ce44SJohn Forte 
5643063d642aSBill Gumbrell 			if (scsi_vhci) {
5644063d642aSBill Gumbrell 				strcpy(l2->node_wwn_s, MSGSTR(12000, "N/A"));
5645063d642aSBill Gumbrell 			} else {
5646063d642aSBill Gumbrell 				copy_wwn_data_to_str(l2->node_wwn_s, node_wwn);
5647063d642aSBill Gumbrell 				copy_wwn_data_to_str(l2->port_wwn_s, port_wwn);
5648063d642aSBill Gumbrell 			}
5649fcf3ce44SJohn Forte 
5650063d642aSBill Gumbrell 			strcpy(l2->physical_path, devicepath);
5651fcf3ce44SJohn Forte 
5652063d642aSBill Gumbrell 			l2->device_type = devtype;
5653063d642aSBill Gumbrell 			if (wwn_list == NULL) {
5654063d642aSBill Gumbrell 				l1 = wwn_list = l2;
5655063d642aSBill Gumbrell 			} else {
5656063d642aSBill Gumbrell 				l2->wwn_prev = l1;
5657063d642aSBill Gumbrell 				l1 = l1->wwn_next = l2;
5658063d642aSBill Gumbrell 			}
5659063d642aSBill Gumbrell 			my_devfs_path_free(devfs_path);
5660063d642aSBill Gumbrell 			scsi_vhci = 0;
5661fcf3ce44SJohn Forte 		}
5662063d642aSBill Gumbrell 		node = di_drv_next_node(node);
5663fcf3ce44SJohn Forte 	}
5664fcf3ce44SJohn Forte 
5665fcf3ce44SJohn Forte 	*wwn_list_ptr = wwn_list; /* pass back ptr to list */
5666fcf3ce44SJohn Forte 
5667fcf3ce44SJohn Forte 	if (*wwn_list_ptr == NULL) {
5668fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5669fcf3ce44SJohn Forte 	} else {
5670fcf3ce44SJohn Forte 		/*
5671fcf3ce44SJohn Forte 		 * Now load the /dev/ paths
5672fcf3ce44SJohn Forte 		 */
5673fcf3ce44SJohn Forte 		if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
5674fcf3ce44SJohn Forte 			if ((err = get_dev_path(wwn_list_ptr, DEV_RDIR,
5675063d642aSBill Gumbrell 			    DIR_MATCH_SSD)) != 0) {
5676fcf3ce44SJohn Forte 				g_free_wwn_list(wwn_list_ptr);
5677fcf3ce44SJohn Forte 				return (err);
5678fcf3ce44SJohn Forte 			}
5679fcf3ce44SJohn Forte 		} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
5680fcf3ce44SJohn Forte 			if ((err = get_dev_path(wwn_list_ptr, DEV_TAPE_DIR,
5681063d642aSBill Gumbrell 			    DIR_MATCH_ST)) != 0) {
5682fcf3ce44SJohn Forte 				g_free_wwn_list(wwn_list_ptr);
5683fcf3ce44SJohn Forte 				return (err);
5684fcf3ce44SJohn Forte 			}
5685fcf3ce44SJohn Forte 		}
5686fcf3ce44SJohn Forte 		return (0);
5687fcf3ce44SJohn Forte 	}
5688fcf3ce44SJohn Forte }
5689fcf3ce44SJohn Forte 
5690fcf3ce44SJohn Forte 
5691fcf3ce44SJohn Forte /*
5692fcf3ce44SJohn Forte  * Access the properties for the node to get the node-wwn, port-wwn property
5693fcf3ce44SJohn Forte  * On error, contents of nwwn, pwwn are unspecified.
5694fcf3ce44SJohn Forte  * On successful return nwwn and pwwn are WWN_SIZE bytes.
5695fcf3ce44SJohn Forte  */
5696fcf3ce44SJohn Forte static int
get_wwn_data(di_node_t node,uchar_t ** nwwn,uchar_t ** pwwn)5697fcf3ce44SJohn Forte get_wwn_data(di_node_t node, uchar_t **nwwn, uchar_t **pwwn)
5698fcf3ce44SJohn Forte {
5699fcf3ce44SJohn Forte 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
5700063d642aSBill Gumbrell 	    nwwn) != WWN_SIZE) {
5701063d642aSBill Gumbrell 		/* If we didn't get back the right count, return error */
5702fcf3ce44SJohn Forte 		return (L_NO_WWN_PROP_FOUND);
5703fcf3ce44SJohn Forte 	}
5704fcf3ce44SJohn Forte 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP,
5705063d642aSBill Gumbrell 	    pwwn) != WWN_SIZE) {
5706063d642aSBill Gumbrell 		/* If we didn't get back the right count, return error */
5707fcf3ce44SJohn Forte 		return (L_NO_WWN_PROP_FOUND);
5708fcf3ce44SJohn Forte 	}
5709fcf3ce44SJohn Forte 	return (0);
5710fcf3ce44SJohn Forte }
5711fcf3ce44SJohn Forte 
5712fcf3ce44SJohn Forte /*
5713fcf3ce44SJohn Forte  * Description
5714fcf3ce44SJohn Forte  *	retrieves the /dev logical path for a WWN_list of devices.
5715fcf3ce44SJohn Forte  * Input values
5716fcf3ce44SJohn Forte  *	wwn_list_ptr	ptr to list returned by devices_get_all
5717fcf3ce44SJohn Forte  *	dir_name	/dev/ directory to search
5718fcf3ce44SJohn Forte  *
5719fcf3ce44SJohn Forte  */
5720fcf3ce44SJohn Forte static int
get_dev_path(struct wwn_list_struct ** wwn_list_ptr,char * dir_name,char * pattern_match)5721fcf3ce44SJohn Forte get_dev_path(struct wwn_list_struct **wwn_list_ptr, char *dir_name,
5722063d642aSBill Gumbrell     char *pattern_match)
5723fcf3ce44SJohn Forte {
5724063d642aSBill Gumbrell 	DIR		*dirp;
5725063d642aSBill Gumbrell 	struct dirent	*entp;
5726063d642aSBill Gumbrell 	char		namebuf[MAXPATHLEN];
5727063d642aSBill Gumbrell 	char		*result = NULL;
5728063d642aSBill Gumbrell 	WWN_list	*wwn_list, *wwn_list_save;
5729063d642aSBill Gumbrell 	char		*env;
5730063d642aSBill Gumbrell 	hrtime_t	start_time, end_time;
5731fcf3ce44SJohn Forte 
5732fcf3ce44SJohn Forte 	if (wwn_list_ptr == NULL || *wwn_list_ptr == NULL ||
5733063d642aSBill Gumbrell 	    dir_name == NULL || pattern_match == NULL) {
5734fcf3ce44SJohn Forte 		return (EINVAL);
5735fcf3ce44SJohn Forte 	}
5736fcf3ce44SJohn Forte 
5737fcf3ce44SJohn Forte 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
5738fcf3ce44SJohn Forte 		start_time = gethrtime();
5739fcf3ce44SJohn Forte 	}
5740fcf3ce44SJohn Forte 
5741fcf3ce44SJohn Forte 	wwn_list = *wwn_list_ptr;
5742fcf3ce44SJohn Forte 
5743fcf3ce44SJohn Forte 	if ((dirp = opendir(dir_name)) == NULL) {
5744fcf3ce44SJohn Forte 		P_DPRINTF("  get_dev_path: No devices found\n");
5745fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5746fcf3ce44SJohn Forte 	}
5747fcf3ce44SJohn Forte 
5748fcf3ce44SJohn Forte 	while ((entp = readdir(dirp)) != NULL) {
5749fcf3ce44SJohn Forte 		/*
5750fcf3ce44SJohn Forte 		 * Ignore current directory and parent directory
5751fcf3ce44SJohn Forte 		 * entries.
5752fcf3ce44SJohn Forte 		 */
5753fcf3ce44SJohn Forte 		if ((strcmp(entp->d_name, ".") == 0) ||
5754fcf3ce44SJohn Forte 		    (strcmp(entp->d_name, "..") == 0) ||
5755fcf3ce44SJohn Forte 		    (fnmatch(pattern_match, entp->d_name, 0) != 0))
5756fcf3ce44SJohn Forte 			continue;
5757fcf3ce44SJohn Forte 
5758fcf3ce44SJohn Forte 		memset(namebuf, 0, sizeof (namebuf));
5759fcf3ce44SJohn Forte 		sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
5760fcf3ce44SJohn Forte 
5761fcf3ce44SJohn Forte 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
5762fcf3ce44SJohn Forte 			ER_DPRINTF("  Warning: Get physical name from"
5763063d642aSBill Gumbrell 			    " link failed. Link=%s\n", namebuf);
5764fcf3ce44SJohn Forte 			continue;
5765fcf3ce44SJohn Forte 		}
5766fcf3ce44SJohn Forte 		for (wwn_list = *wwn_list_ptr; wwn_list != NULL;
5767fcf3ce44SJohn Forte 		    wwn_list = wwn_list->wwn_next) {
5768063d642aSBill Gumbrell 			if (strcmp(wwn_list->physical_path, result) == 0) {
5769063d642aSBill Gumbrell 				/*
5770063d642aSBill Gumbrell 				 * Add information to the list.
5771063d642aSBill Gumbrell 				 */
5772063d642aSBill Gumbrell 				if ((wwn_list->logical_path = (char *)
5773063d642aSBill Gumbrell 				    calloc(1, strlen(namebuf) + 1)) == NULL) {
5774063d642aSBill Gumbrell 					free(result);
5775063d642aSBill Gumbrell 					return (L_MALLOC_FAILED);
5776063d642aSBill Gumbrell 				}
5777063d642aSBill Gumbrell 				strcpy(wwn_list->logical_path, namebuf);
5778063d642aSBill Gumbrell 				break;
5779fcf3ce44SJohn Forte 			}
5780fcf3ce44SJohn Forte 		}
5781fcf3ce44SJohn Forte 		free(result);
5782fcf3ce44SJohn Forte 	}
5783fcf3ce44SJohn Forte 	closedir(dirp);
5784fcf3ce44SJohn Forte 
5785fcf3ce44SJohn Forte 	/*
5786fcf3ce44SJohn Forte 	 * Did we load all of the paths?
5787fcf3ce44SJohn Forte 	 * Note: if there is a missing entry in /dev then
5788fcf3ce44SJohn Forte 	 * the user probably did a cleanup of /dev.
5789fcf3ce44SJohn Forte 	 * Whatever the case, remove the entry as it
5790fcf3ce44SJohn Forte 	 * is invalid.
5791fcf3ce44SJohn Forte 	 */
5792fcf3ce44SJohn Forte 	wwn_list = *wwn_list_ptr;
5793fcf3ce44SJohn Forte 	while (wwn_list != NULL) {
5794fcf3ce44SJohn Forte 		if (wwn_list->logical_path == NULL) {
5795fcf3ce44SJohn Forte 			free(wwn_list->physical_path);
5796fcf3ce44SJohn Forte 			wwn_list_save = wwn_list;
5797fcf3ce44SJohn Forte 			if (wwn_list->wwn_prev != NULL) {
5798fcf3ce44SJohn Forte 				wwn_list->wwn_prev->wwn_next =
5799063d642aSBill Gumbrell 				    wwn_list->wwn_next;
5800fcf3ce44SJohn Forte 			} else {
5801fcf3ce44SJohn Forte 				/*
5802fcf3ce44SJohn Forte 				 * No previous entries
5803fcf3ce44SJohn Forte 				 */
5804fcf3ce44SJohn Forte 				*wwn_list_ptr = wwn_list->wwn_next;
5805fcf3ce44SJohn Forte 			}
5806fcf3ce44SJohn Forte 			if (wwn_list->wwn_next != NULL) {
5807fcf3ce44SJohn Forte 				wwn_list->wwn_next->wwn_prev =
5808063d642aSBill Gumbrell 				    wwn_list->wwn_prev;
5809fcf3ce44SJohn Forte 			}
5810fcf3ce44SJohn Forte 			wwn_list = wwn_list->wwn_next;
5811fcf3ce44SJohn Forte 			free(wwn_list_save);
5812fcf3ce44SJohn Forte 		} else {
5813fcf3ce44SJohn Forte 			wwn_list = wwn_list->wwn_next;
5814fcf3ce44SJohn Forte 		}
5815fcf3ce44SJohn Forte 	}
5816fcf3ce44SJohn Forte 
5817fcf3ce44SJohn Forte 	if (env != NULL) {
5818fcf3ce44SJohn Forte 		end_time = gethrtime();
5819fcf3ce44SJohn Forte 		fprintf(stdout,
5820063d642aSBill Gumbrell 		    "      get_dev_path %s:  "
5821063d642aSBill Gumbrell 		    "\t\tTime = %lld millisec\n",
5822063d642aSBill Gumbrell 		    dir_name, (end_time - start_time)/1000000);
5823fcf3ce44SJohn Forte 	}
5824fcf3ce44SJohn Forte 
5825fcf3ce44SJohn Forte 	if (*wwn_list_ptr == NULL) {
5826fcf3ce44SJohn Forte 		return (L_NO_DEVICES_FOUND);
5827fcf3ce44SJohn Forte 	} else {
5828fcf3ce44SJohn Forte 		return (0);
5829fcf3ce44SJohn Forte 	}
5830fcf3ce44SJohn Forte }
5831fcf3ce44SJohn Forte 
5832fcf3ce44SJohn Forte /*
5833fcf3ce44SJohn Forte  * This functions calls di_devfs_path and gets the path associated with a
5834fcf3ce44SJohn Forte  * given devinfo node. If the path returned does not have a '@' in it, it
5835fcf3ce44SJohn Forte  * checks if the driver is detached and creates a path after looking at the
5836fcf3ce44SJohn Forte  * driver properties.
5837fcf3ce44SJohn Forte  *
5838fcf3ce44SJohn Forte  * di_devfs_path_free is called internally.
5839fcf3ce44SJohn Forte  *
5840fcf3ce44SJohn Forte  * The argument 'path' points to the final value upon return.
5841fcf3ce44SJohn Forte  * Caller must use my_devfs_path_free on returned char *
5842fcf3ce44SJohn Forte  * Note: Only support FC/SCSI_VHCI devices,
5843063d642aSBill Gumbrell  *       for FC check for initiator-interconnect-type prop
5844fcf3ce44SJohn Forte  *
5845fcf3ce44SJohn Forte  */
5846fcf3ce44SJohn Forte static char *
my_devfs_path(di_node_t node)5847fcf3ce44SJohn Forte my_devfs_path(di_node_t node)
5848fcf3ce44SJohn Forte {
5849fcf3ce44SJohn Forte 	uchar_t	*pwwn = NULL;
5850063d642aSBill Gumbrell 	char	*interconnect = NULL;
5851fcf3ce44SJohn Forte 	char	pwwns[WWN_SIZE*2+1];
5852fcf3ce44SJohn Forte 	char	*mypath;
5853fcf3ce44SJohn Forte 	int	scsi_vhci = 0;
5854063d642aSBill Gumbrell 	int	rval;
5855fcf3ce44SJohn Forte 	char	*tptr = NULL, *lun_guid = NULL;
5856fcf3ce44SJohn Forte 	int	*lunnump = NULL;
5857063d642aSBill Gumbrell 	di_node_t	parentnode;
5858fcf3ce44SJohn Forte 
5859fcf3ce44SJohn Forte 	/* sanity check */
5860fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
5861fcf3ce44SJohn Forte 		return (NULL);
5862fcf3ce44SJohn Forte 	}
5863fcf3ce44SJohn Forte 
5864fcf3ce44SJohn Forte 	/* Now go get the path for this node */
5865fcf3ce44SJohn Forte 	if ((tptr = di_devfs_path(node)) == NULL) {
5866fcf3ce44SJohn Forte 		return (NULL);
5867fcf3ce44SJohn Forte 	}
5868fcf3ce44SJohn Forte 
5869063d642aSBill Gumbrell 	parentnode = di_parent_node(node);
5870063d642aSBill Gumbrell 
5871fcf3ce44SJohn Forte 	if ((mypath = (char *)calloc(1, MAXPATHLEN + 1)) == NULL) {
5872fcf3ce44SJohn Forte 		di_devfs_path_free(tptr);
5873fcf3ce44SJohn Forte 		return (NULL);
5874fcf3ce44SJohn Forte 	}
5875fcf3ce44SJohn Forte 
5876fcf3ce44SJohn Forte 	/* Prepend "/devices" to libdevinfo-returned paths */
5877fcf3ce44SJohn Forte 	sprintf(mypath, "%s%s", DEVICES_DIR, tptr);
5878fcf3ce44SJohn Forte 
5879fcf3ce44SJohn Forte 	di_devfs_path_free(tptr);
5880fcf3ce44SJohn Forte 
5881fcf3ce44SJohn Forte 	/*
5882fcf3ce44SJohn Forte 	 * Is this a FC device?
5883063d642aSBill Gumbrell 	 * Check initiator-interconnect-type property
5884fcf3ce44SJohn Forte 	 */
5885fcf3ce44SJohn Forte 	if (strstr(mypath, SCSI_VHCI) == NULL) {
5886063d642aSBill Gumbrell 		rval = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
5887063d642aSBill Gumbrell 		    "initiator-interconnect-type", &interconnect);
5888063d642aSBill Gumbrell 		/* Check for INTERCONNECT_FABRIC_STR & INTERCONNECT_FIBRE_STR */
5889063d642aSBill Gumbrell 		if ((rval <= 0) ||
5890063d642aSBill Gumbrell 		    ((strcmp(interconnect, "FABRIC") != 0) &&
5891063d642aSBill Gumbrell 		    (strcmp(interconnect, "FIBRE") != 0))) {
5892fcf3ce44SJohn Forte 			/* Not a FC device. Free path and return */
5893fcf3ce44SJohn Forte 			free(mypath);
5894fcf3ce44SJohn Forte 			return (NULL);
5895fcf3ce44SJohn Forte 		}
5896fcf3ce44SJohn Forte 	} else {
5897fcf3ce44SJohn Forte 		scsi_vhci++;
5898fcf3ce44SJohn Forte 	}
5899fcf3ce44SJohn Forte 
5900fcf3ce44SJohn Forte 	if ((tptr = strrchr(mypath, '/')) == NULL) {
5901fcf3ce44SJohn Forte 		free(mypath);
5902fcf3ce44SJohn Forte 		return (NULL);
5903fcf3ce44SJohn Forte 	}
5904fcf3ce44SJohn Forte 
5905fcf3ce44SJohn Forte 	if (strchr(tptr, '@') != NULL) {
5906fcf3ce44SJohn Forte 		return (mypath);
5907fcf3ce44SJohn Forte 	}
5908fcf3ce44SJohn Forte 
5909fcf3ce44SJohn Forte 	/*
5910fcf3ce44SJohn Forte 	 * No '@' in path. This can happen when driver is detached.
5911fcf3ce44SJohn Forte 	 * We'll check if the state is detached and if it is, we'll construct
5912fcf3ce44SJohn Forte 	 * the path by looking at the properties.
5913fcf3ce44SJohn Forte 	 */
5914fcf3ce44SJohn Forte 
5915fcf3ce44SJohn Forte 	if ((di_state(node) & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
5916fcf3ce44SJohn Forte 		/*
5917fcf3ce44SJohn Forte 		 * Driver is not detached and no '@' in path.
5918fcf3ce44SJohn Forte 		 * Can't handle it.
5919fcf3ce44SJohn Forte 		 */
5920fcf3ce44SJohn Forte 		free(mypath);
5921fcf3ce44SJohn Forte 		return (NULL);
5922fcf3ce44SJohn Forte 	}
5923fcf3ce44SJohn Forte 
5924fcf3ce44SJohn Forte 	if (!scsi_vhci) {
5925fcf3ce44SJohn Forte 		copy_wwn_data_to_str(pwwns, pwwn);
5926fcf3ce44SJohn Forte 		di_prop_lookup_ints(DDI_DEV_T_ANY, node, LUN_PROP, &lunnump);
5927fcf3ce44SJohn Forte 		sprintf(&mypath[strlen(mypath)], "@w%s,%x", pwwn, *lunnump);
5928fcf3ce44SJohn Forte 	} else {
5929fcf3ce44SJohn Forte 		di_prop_lookup_strings(DDI_DEV_T_ANY, node,
5930063d642aSBill Gumbrell 		    LUN_GUID_PROP, &lun_guid);
5931fcf3ce44SJohn Forte 		sprintf(&mypath[strlen(mypath)], "@g%s", lun_guid);
5932fcf3ce44SJohn Forte 	}
5933fcf3ce44SJohn Forte 	return (mypath);
5934fcf3ce44SJohn Forte }
5935fcf3ce44SJohn Forte 
5936fcf3ce44SJohn Forte static void
my_devfs_path_free(char * path)5937fcf3ce44SJohn Forte my_devfs_path_free(char *path)
5938fcf3ce44SJohn Forte {
5939fcf3ce44SJohn Forte 	if (path != NULL) {
5940fcf3ce44SJohn Forte 		free(path);
5941fcf3ce44SJohn Forte 	}
5942fcf3ce44SJohn Forte }
5943fcf3ce44SJohn Forte 
5944fcf3ce44SJohn Forte /*
5945fcf3ce44SJohn Forte  * from_ptr: ptr to uchar_t array of size WWN_SIZE
5946fcf3ce44SJohn Forte  * to_ptr: char ptr to string of size WWN_SIZE*2+1
5947fcf3ce44SJohn Forte  */
5948fcf3ce44SJohn Forte static void
copy_wwn_data_to_str(char * to_ptr,const uchar_t * from_ptr)5949fcf3ce44SJohn Forte copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
5950fcf3ce44SJohn Forte {
5951fcf3ce44SJohn Forte 	if ((to_ptr == NULL) || (from_ptr == NULL))
5952fcf3ce44SJohn Forte 		return;
5953fcf3ce44SJohn Forte 
5954fcf3ce44SJohn Forte 	sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
5955063d642aSBill Gumbrell 	    from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
5956063d642aSBill Gumbrell 	    from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
5957fcf3ce44SJohn Forte }
5958fcf3ce44SJohn Forte 
5959fcf3ce44SJohn Forte /*
5960fcf3ce44SJohn Forte  * Open the requested directory and get one valid open.
5961fcf3ce44SJohn Forte  * If a device is busy, return.
5962fcf3ce44SJohn Forte  * Only need to open one device since
5963fcf3ce44SJohn Forte  * that implies there will be a node returned from
5964fcf3ce44SJohn Forte  * di_drv_first_node()
5965fcf3ce44SJohn Forte  * dir_name: logical device name directory
5966fcf3ce44SJohn Forte  *	(DEV_TAPE_DIR, DEV_RDIR)
5967fcf3ce44SJohn Forte  * pattern_match: used by fnmatch on directory entry
5968fcf3ce44SJohn Forte  *	(DIR_MATCH_SSD, DIR_MATCH_ST)
5969fcf3ce44SJohn Forte  * drvr_path: path type to verify ("/ssd@", "/st@")
5970fcf3ce44SJohn Forte  *	(SLSH_DRV_NAME_ST, SLSH_DRV_NAME_SSD)
5971fcf3ce44SJohn Forte  *
5972fcf3ce44SJohn Forte  * Returns: None
5973fcf3ce44SJohn Forte  */
5974fcf3ce44SJohn Forte static void
init_drv(char * dir_name,char * pattern_match,char * drvr_path)5975fcf3ce44SJohn Forte init_drv(char *dir_name, char *pattern_match, char *drvr_path)
5976fcf3ce44SJohn Forte {
5977063d642aSBill Gumbrell 	DIR		*dirp;
5978063d642aSBill Gumbrell 	struct dirent	*entp;
5979063d642aSBill Gumbrell 	char		namebuf[MAXPATHLEN];
5980063d642aSBill Gumbrell 	char		*result = NULL;
5981063d642aSBill Gumbrell 	int		fd;
5982fcf3ce44SJohn Forte 
5983fcf3ce44SJohn Forte 	if ((dirp = opendir(dir_name)) == NULL) {
5984fcf3ce44SJohn Forte 		return;
5985fcf3ce44SJohn Forte 	}
5986fcf3ce44SJohn Forte 
5987fcf3ce44SJohn Forte 	while ((entp = readdir(dirp)) != NULL) {
5988fcf3ce44SJohn Forte 		/*
5989fcf3ce44SJohn Forte 		 * Ignore current directory and parent directory
5990fcf3ce44SJohn Forte 		 * entries.
5991fcf3ce44SJohn Forte 		 */
5992fcf3ce44SJohn Forte 		if ((strcmp(entp->d_name, ".") == 0) ||
5993fcf3ce44SJohn Forte 		    (strcmp(entp->d_name, "..") == 0) ||
5994fcf3ce44SJohn Forte 		    (fnmatch(pattern_match, entp->d_name, 0) != 0)) {
5995fcf3ce44SJohn Forte 			continue;
5996fcf3ce44SJohn Forte 		}
5997fcf3ce44SJohn Forte 
5998fcf3ce44SJohn Forte 		memset(namebuf, 0, sizeof (namebuf));
5999fcf3ce44SJohn Forte 		sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
6000fcf3ce44SJohn Forte 
6001fcf3ce44SJohn Forte 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
6002fcf3ce44SJohn Forte 			ER_DPRINTF("  Warning: Get physical name from"
6003063d642aSBill Gumbrell 			    " link failed. Link=%s\n", namebuf);
6004fcf3ce44SJohn Forte 			continue;
6005fcf3ce44SJohn Forte 		}
6006fcf3ce44SJohn Forte 
6007fcf3ce44SJohn Forte 		if (strstr(result, drvr_path) == NULL) {
6008fcf3ce44SJohn Forte 			free(result);
6009fcf3ce44SJohn Forte 			result = NULL;
6010fcf3ce44SJohn Forte 			continue;
6011fcf3ce44SJohn Forte 		}
6012fcf3ce44SJohn Forte 
6013fcf3ce44SJohn Forte 		if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) != -1) {
6014fcf3ce44SJohn Forte 			close(fd);
6015fcf3ce44SJohn Forte 			break;
6016fcf3ce44SJohn Forte 		} else if (errno != EBUSY) {
6017fcf3ce44SJohn Forte 			free(result);
6018fcf3ce44SJohn Forte 			result = NULL;
6019fcf3ce44SJohn Forte 			continue;
6020fcf3ce44SJohn Forte 		} else {
6021fcf3ce44SJohn Forte 			break;
6022fcf3ce44SJohn Forte 		}
6023fcf3ce44SJohn Forte 	}
6024fcf3ce44SJohn Forte 	free(result);
6025fcf3ce44SJohn Forte 	closedir(dirp);
6026fcf3ce44SJohn Forte }
6027