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.