1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*LINTLIBRARY*/
28 
29 /*
30  * I18N message number ranges
31  *  This file: 12000 - 12499
32  *  Shared common messages: 1 - 1999
33  */
34 
35 /*
36  *	This module is part of the Fibre Channel Interface library.
37  */
38 
39 /* #define		_POSIX_SOURCE 1 */
40 
41 
42 /*	Includes	*/
43 #include	<stdlib.h>
44 #include	<stdio.h>
45 #include	<sys/file.h>
46 #include	<sys/types.h>
47 #include	<sys/stat.h>
48 #include	<sys/mkdev.h>
49 #include	<sys/param.h>
50 #include	<fcntl.h>
51 #include	<unistd.h>
52 #include	<string.h>
53 #include	<sys/scsi/scsi.h>
54 #include	<dirent.h>		/* for DIR */
55 #include	<sys/vtoc.h>
56 #include	<nl_types.h>
57 #include	<strings.h>
58 #include	<errno.h>
59 #include	<sys/ddi.h>		/* for max */
60 #include	<fnmatch.h>
61 #include	<l_common.h>
62 #include	<stgcom.h>
63 #include	<l_error.h>
64 #include	<g_state.h>
65 #include	<g_scsi.h>
66 #include	<sys/fibre-channel/ulp/fcp_util.h>
67 #include	<sys/fibre-channel/impl/fc_error.h>
68 #include	<sys/fibre-channel/impl/fcph.h>
69 #include	<sys/socalio.h>
70 #include	<libdevinfo.h>
71 #include	<ctype.h>
72 #include	<devid.h>
73 
74 /* Some forward declarations of static functions */
75 /*
76  * becomes extern interface for Tapestry.
77  * static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *);
78  * static int g_get_dev_list(char *, fc_port_dev_t **, int *, int);
79  */
80 static int	g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
81 static int	g_set_port_state(char *, int);
82 static int	g_dev_log_in_out(char *, la_wwn_t, uint16_t);
83 static int	g_get_dev_port_state(char *, la_wwn_t, uint32_t *);
84 static void	g_free_rls(AL_rls *);
85 static int	g_scsi_inquiry_cmd80(int, uchar_t *, int);
86 static int	get_fca_inq_dtype(char *, la_wwn_t, uchar_t *);
87 static int	g_find_supported_inq_page(int, int);
88 static int	wwn_list_name_compare(const void *, const void *);
89 static int	devid_get_all(ddi_devid_t, di_node_t, char *,
90 			struct mplist_struct **);
91 static int	get_multipath(char *, struct dlist **,
92 			struct wwn_list_struct *);
93 static int	get_multipath_disk(char *, struct dlist **,
94 			struct wwn_list_struct *);
95 static void	mplist_free(struct mplist_struct *);
96 static int	get_wwn_data(di_node_t, uchar_t **, uchar_t **);
97 static int	get_dev_path(struct wwn_list_struct **, char *, char *);
98 static int	insert_missing_pwwn(char *, struct wwn_list_struct **);
99 static int	get_scsi_vhci_port_wwn(char *, uchar_t *);
100 static int	search_wwn_entry(struct wwn_list_found_struct *, uchar_t *,
101 		uchar_t *);
102 static int	add_wwn_entry(struct wwn_list_found_struct **, uchar_t *,
103 		uchar_t *);
104 static int	string_to_wwn(uchar_t *, uchar_t *);
105 static int	get_wwns(char *, uchar_t *, uchar_t *, int *,
106 		struct wwn_list_found_struct **);
107 
108 /* type for g_dev_map_init related routines */
109 
110 #define	S_FREE(x)	(((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
111 
112 typedef struct impl_map_dev_prop {
113 	char	prop_name[MAXNAMELEN];
114 	int	prop_type;
115 	int	prop_size;
116 	void	*prop_data;
117 	int	prop_error;
118 	struct impl_map_dev_prop	*next;
119 } impl_map_dev_prop_t;
120 
121 typedef struct impl_map_dev {
122 	int			flag;
123 	uint_t			topo;
124 	impl_map_dev_prop_t	*prop_list;
125 	struct impl_map_dev	*parent;
126 	struct impl_map_dev	*child;
127 	struct impl_map_dev	*next;
128 } impl_map_dev_t;
129 
130 /*	Defines		*/
131 #define	VERBPRINT	if (verbose) (void) printf
132 
133 #define	DIR_MATCH_ST		"*[0-9+]n"
134 #define	DIR_MATCH_SSD		"*s2"
135 
136 #define	PROP_NOEXIST		0
137 #define	PROP_EXIST		1
138 
139 /*	Prototypes	*/
140 static int create_map(char *, gfc_map_t *, int, int);
141 static char ctoi(char);
142 static int	lilp_map_cmp(const void*, const void*);
143 static int	devices_get_all(di_node_t, char *, char *,
144 			struct wwn_list_struct **);
145 static char	*my_devfs_path(di_node_t);
146 static void	my_devfs_path_free(char *path);
147 static void	copy_wwn_data_to_str(char *, const uchar_t *);
148 static void	init_drv(char *, char *, char *);
149 
150 /* static for g_dev_map_init related routines */
151 
152 static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t,
153 	uchar_t *, uchar_t *, int, int);
154 static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int);
155 static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **);
156 static void free_prop_list(impl_map_dev_prop_t **);
157 static void free_child_list(impl_map_dev_t **);
158 static u_longlong_t wwnConversion(uchar_t *wwn);
159 
160 uchar_t g_switch_to_alpa[] = {
161 	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
162 	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
163 	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
164 	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
165 	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
166 	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
167 	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
168 	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
169 	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
170 	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
171 	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
172 	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
173 	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
174 };
175 
176 uchar_t g_sf_alpa_to_switch[] = {
177 	0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
178 	0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
179 	0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
180 	0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
181 	0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
182 	0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
183 	0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
184 	0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
185 	0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
186 	0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
187 	0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
188 	0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
189 	0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
190 	0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
191 	0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
192 	0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
193 	0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
194 	0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
195 	0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
196 	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
197 	0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
198 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
199 	0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
200 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
201 };
202 
203 
204 
205 /*
206  * Check if device is in the map.
207  *
208  * PARAMS:
209  *	map - loop map returned from fc port
210  *	tid - device ID for private map or 24-bit alpa for fabric map
211  *
212  * RETURNS:
213  *	 1 if device present in the map.
214  *	 0 otherwise.
215  *
216  */
217 int
g_device_in_map(gfc_map_t * map,int tid)218 g_device_in_map(gfc_map_t *map, int tid)
219 {
220 	int i, j;
221 	gfc_port_dev_info_t	*dev_ptr;
222 
223 	dev_ptr = map->dev_addr;
224 	if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) ||
225 	    (map->hba_addr.port_topology == FC_TOP_FABRIC)) {
226 		for (i = 0; i < map->count; i++, dev_ptr++) {
227 			if (dev_ptr->
228 			    gfc_port_dev.pub_port.dev_did.port_id == tid) {
229 				/* Does not count if WWN == 0 */
230 				for (j = 0; j < FC_WWN_SIZE; j++)
231 					if (dev_ptr->gfc_port_dev.pub_port.
232 					    dev_pwwn.raw_wwn[j] != 0)
233 						return (1);
234 			}
235 		}
236 	} else {
237 		for (i = 0; i < map->count; i++, dev_ptr++) {
238 			if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa ==
239 			    (int)g_switch_to_alpa[tid]) {
240 				/* Does not count if WWN == 0 */
241 				for (j = 0; j < WWN_SIZE; j++)
242 					if (dev_ptr->gfc_port_dev.priv_port.
243 					    sf_port_wwn[j] != 0)
244 						return (1);
245 			}
246 		}
247 	}
248 	return (0);
249 }
250 
251 /*
252  * Inserts any missing port wwns for mpxio device paths
253  * which are in ONLINE or STANDBY state.
254  */
255 static int
insert_missing_pwwn(char * phys_path,struct wwn_list_struct ** wwn_list_ptr)256 insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr)
257 {
258 	mp_pathlist_t	pathlist;
259 	int	i, pathcnt, match;
260 	struct	wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found;
261 	char	pwwn1[WWN_S_LEN];
262 
263 	/*
264 	 * Now check each scsi_vhci device path to find any missed
265 	 * port wwns and insert a new wwn list entry for the missed
266 	 * port wwn
267 	 */
268 	if (g_get_pathlist(phys_path, &pathlist)) {
269 		/* Free memory for pathlist before return */
270 		S_FREE(pathlist.path_info);
271 		return (L_INVALID_PATH);
272 	}
273 
274 	pathcnt = pathlist.path_count;
275 	for (i = 0; i < pathcnt; i++) {
276 		/*
277 		 * Just search for ONLINE and STANDBY paths as
278 		 * those should be the only missing wwn entries.
279 		 * There is a very small window for an offline
280 		 * to have occurred between the time we retrieved
281 		 * the device list and a call to this function.
282 		 * If that happens, we just won't add it to
283 		 * the list which is probably a good thing.
284 		 */
285 		if (pathlist.path_info[i].path_state ==
286 		    MDI_PATHINFO_STATE_ONLINE ||
287 		    pathlist.path_info[i].path_state ==
288 		    MDI_PATHINFO_STATE_STANDBY) {
289 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
290 			    WWN_S_LEN - 1);
291 			pwwn1[WWN_S_LEN - 1] = '\0';
292 			/*
293 			 * Now search through wwn list for matching
294 			 * device path AND pwwn
295 			 * If it's found, continue to next path.
296 			 * If it's not found, add it the wwn list.
297 			 */
298 			match = 0;
299 
300 			for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL;
301 			    wwn_list_s = wwn_list_s->wwn_next) {
302 				if (strncmp(phys_path,
303 				    wwn_list_s->physical_path,
304 				    strlen(phys_path)) == 0) {
305 					wwn_list_found = wwn_list_s;
306 					if (strncmp(pwwn1,
307 					    wwn_list_s->port_wwn_s,
308 					    WWN_S_LEN) == 0) {
309 						match++;
310 						break;
311 					}
312 				}
313 			}
314 			if (match) {
315 				continue;
316 			} else {
317 				/*
318 				 * didn't find a match but the mpxio
319 				 * device is in the list. Retrieve
320 				 * the info from the wwn_list_found
321 				 * and add it to the list.
322 				 */
323 				if ((new_wwn = (struct  wwn_list_struct *)
324 				    calloc(1,
325 				    sizeof (struct  wwn_list_struct)))
326 				    == NULL) {
327 					S_FREE(pathlist.path_info);
328 					return (L_MALLOC_FAILED);
329 				}
330 				if ((new_wwn->physical_path = (char *)
331 				    calloc(1,
332 				    strlen(wwn_list_found->physical_path)
333 				    + 1)) == NULL) {
334 					S_FREE(pathlist.path_info);
335 					return (L_MALLOC_FAILED);
336 				}
337 				if ((new_wwn->logical_path = (char *)
338 				    calloc(1,
339 				    strlen(wwn_list_found->logical_path)
340 				    + 1)) == NULL) {
341 					S_FREE(pathlist.path_info);
342 					return (L_MALLOC_FAILED);
343 				}
344 
345 				/*
346 				 * Insert new_wwn at the beginning of the list.
347 				 */
348 				new_wwn->wwn_next = *wwn_list_ptr;
349 				(*wwn_list_ptr)->wwn_prev = new_wwn;
350 
351 				/* set new starting ptr */
352 				*wwn_list_ptr = new_wwn;
353 
354 				memcpy(new_wwn->physical_path,
355 				    wwn_list_found->physical_path,
356 				    strlen(wwn_list_found->physical_path));
357 				memcpy(new_wwn->logical_path,
358 				    wwn_list_found->logical_path,
359 				    strlen(wwn_list_found->logical_path));
360 				/*
361 				 * Copy found node wwn data to this new entry
362 				 * Node wwn is required for the wwn_list
363 				 * however for mpxio devices it is not
364 				 * relevant as it may apply to multiple
365 				 * target controllers, so just use what
366 				 * we already have in wwn_list_found.
367 				 */
368 				memcpy(new_wwn->node_wwn_s,
369 				    wwn_list_found->node_wwn_s, WWN_S_LEN);
370 				memcpy(new_wwn->w_node_wwn,
371 				    wwn_list_found->w_node_wwn, WWN_SIZE);
372 				new_wwn->device_type =
373 				    wwn_list_found->device_type;
374 				memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN);
375 			}
376 		}
377 	}
378 	S_FREE(pathlist.path_info);
379 	return (0);
380 }
381 
382 /*
383  * gets the port wwn for a scsi_vhci device using ONLINE path priority
384  */
385 static int
get_scsi_vhci_port_wwn(char * phys_path,uchar_t * port_wwn)386 get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn)
387 {
388 	mp_pathlist_t	pathlist;
389 	int	i, pathcnt, found;
390 	char	pwwn1[WWN_S_LEN];
391 
392 	if (g_get_pathlist(phys_path, &pathlist)) {
393 		return (L_INVALID_PATH);
394 	}
395 
396 	found = 0;
397 	pathcnt = pathlist.path_count;
398 	/*
399 	 * Look for an ONLINE path first.
400 	 * If that fails, get the STANDBY path port WWN
401 	 * If that fails, give up
402 	 */
403 	for (i = 0; found == 0 && i < pathcnt; i++) {
404 		if (pathlist.path_info[i].path_state ==
405 		    MDI_PATHINFO_STATE_ONLINE) {
406 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
407 			    WWN_S_LEN - 1);
408 			pwwn1[WWN_S_LEN - 1] = '\0';
409 			found++;
410 		}
411 	}
412 
413 	for (i = 0; found == 0 && i < pathcnt; i++) {
414 		if (pathlist.path_info[i].path_state ==
415 		    MDI_PATHINFO_STATE_STANDBY) {
416 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
417 			    WWN_S_LEN - 1);
418 			pwwn1[WWN_S_LEN - 1] = '\0';
419 			found++;
420 		}
421 	}
422 
423 	S_FREE(pathlist.path_info);
424 	if (found) {
425 		return (string_to_wwn((uchar_t *)pwwn1, port_wwn));
426 	} else {
427 		return (-1);
428 	}
429 }
430 
431 /*
432  * searches wwn_list_found for the pwwn passed in
433  * and sets the corresponding nwwn on return.
434  * If no match is found, -1 is returned and nwwn is not set.
435  */
436 static int
search_wwn_entry(struct wwn_list_found_struct * wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)437 search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn,
438     uchar_t *nwwn)
439 {
440 	struct	wwn_list_found_struct *wwn_list_s;
441 
442 	for (wwn_list_s = wwn_list_found; wwn_list_s != NULL;
443 	    wwn_list_s = wwn_list_s->wwn_next) {
444 		if (memcmp(pwwn, wwn_list_s->port_wwn, WWN_SIZE) == 0) {
445 			memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE);
446 			return (0);
447 		}
448 	}
449 	return (-1);
450 }
451 
452 /*
453  * adds a nwwn, pwwn entry to the next entry in wwn_list_found list
454  */
455 static int
add_wwn_entry(struct wwn_list_found_struct ** wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)456 add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn,
457     uchar_t *nwwn)
458 {
459 	struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL;
460 
461 	/* Got wwns, load data in list */
462 	if ((new_wwn = (struct  wwn_list_found_struct *)
463 	    calloc(1, sizeof (struct  wwn_list_found_struct))) == NULL) {
464 		return (L_MALLOC_FAILED);
465 	}
466 
467 	memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE);
468 	memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE);
469 
470 	/*
471 	 * Insert new_wwn in the list
472 	 */
473 	if (*wwn_list_found != NULL) {
474 		temp_wwn_list_found = (*wwn_list_found)->wwn_next;
475 		(*wwn_list_found)->wwn_next = new_wwn;
476 	} else {
477 		*wwn_list_found = new_wwn;
478 	}
479 	new_wwn->wwn_next = temp_wwn_list_found;
480 
481 	return (0);
482 }
483 
484 
485 /*
486  * Create a linked list of all the WWN's for all FC_AL disks and
487  * tapes that are attached to this host.
488  *
489  * RETURN VALUES: 0 O.K.
490  *
491  * wwn_list pointer:
492  *			NULL: No devices found.
493  *			!NULL: Devices found
494  *                      wwn_list points to a linked list of wwn's.
495  */
496 int
g_get_wwn_list(struct wwn_list_struct ** wwn_list_ptr,int verbose)497 g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose)
498 {
499 	struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL;
500 	struct wwn_list_found_struct *wwn_list_found = NULL;
501 	int err;
502 	int al_pa;
503 	uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
504 	hrtime_t	start_time, end_time;
505 	char *env = NULL;
506 
507 	/* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */
508 	if (wwn_list_ptr == NULL) {
509 		return (L_NULL_WWN_LIST);
510 	}
511 
512 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
513 		start_time = gethrtime();
514 	}
515 
516 	if ((err = g_devices_get_all(wwn_list_ptr)) != 0) {
517 		return (err);
518 	}
519 
520 	/*
521 	 * retain backward compatibility with g_get_wwn_list
522 	 * and retrieve the WWN for scsi_vhci devices in the
523 	 * same fashion
524 	 * Note that for scsi_vhci devices, the wwn fields are
525 	 * not relevant but in the previous versions
526 	 * we loaded the wwns so...
527 	 */
528 	wwn_list_p = *wwn_list_ptr;
529 	while (wwn_list_p != NULL) {
530 		if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
531 			/* get port wwn of first ONLINE, STANDBY */
532 			if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path,
533 			    port_wwn)) == 0) {
534 				if ((search_wwn_entry(wwn_list_found, port_wwn,
535 				    node_wwn)) != 0) {
536 					if ((err =
537 					    get_wwns(wwn_list_p->physical_path,
538 					    port_wwn,
539 					    node_wwn, &al_pa,
540 					    &wwn_list_found)) != 0) {
541 						g_free_wwn_list_found(
542 						    &wwn_list_found);
543 						return (err);
544 					}
545 				}
546 			} else {
547 				/* Use g_get_wwn as a last resort */
548 				if ((err = g_get_wwn(wwn_list_p->physical_path,
549 				    port_wwn, node_wwn, &al_pa, 0)) != 0) {
550 					/*
551 					 * this is a bad WWN.
552 					 * remove it from the wwn_list.
553 					 *
554 					 * After removing the bad WWN,
555 					 * wwn_list_p should point to the next
556 					 * node in the list.
557 					 */
558 					if ((wwn_list_p->wwn_prev == NULL) &&
559 					    (wwn_list_p->wwn_next == NULL)) {
560 						*wwn_list_ptr = NULL;
561 						free(wwn_list_p);
562 						g_free_wwn_list_found(
563 						    &wwn_list_found);
564 						return (L_NO_DEVICES_FOUND);
565 					} else if (
566 					    wwn_list_p->wwn_prev == NULL) {
567 						*wwn_list_ptr =
568 						    wwn_list_p->wwn_next;
569 						free(wwn_list_p);
570 						wwn_list_p = *wwn_list_ptr;
571 						wwn_list_p->wwn_prev = NULL;
572 					} else if (
573 					    wwn_list_p->wwn_next == NULL) {
574 						wwn_list_p->wwn_prev->wwn_next =
575 						    NULL;
576 						free(wwn_list_p);
577 						wwn_list_p = NULL;
578 					} else {
579 						wwn_list_tmp_p =
580 						    wwn_list_p->wwn_next;
581 						wwn_list_p->wwn_prev->wwn_next =
582 						    wwn_list_p->wwn_next;
583 						wwn_list_p->wwn_next->wwn_prev =
584 						    wwn_list_p->wwn_prev;
585 						free(wwn_list_p);
586 						wwn_list_p = wwn_list_tmp_p;
587 					}
588 					continue;
589 				}
590 			}
591 			copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn);
592 			copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn);
593 			memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE);
594 		}
595 		wwn_list_p = wwn_list_p->wwn_next;
596 	}
597 	g_free_wwn_list_found(&wwn_list_found);
598 
599 	/*
600 	 * Now go through the list one more time to add entries for
601 	 * any missing port wwns.
602 	 * This allows a search on port wwn for any paths which are
603 	 * ONLINE or STANDBY. We don't care about OFFLINE as those won't
604 	 * and should not show up in the list
605 	 */
606 	for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL;
607 	    wwn_list_p = wwn_list_p->wwn_next) {
608 		if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
609 			if ((err = insert_missing_pwwn(
610 			    wwn_list_p->physical_path, wwn_list_ptr)) != 0)
611 				return (err);
612 		}
613 	}
614 
615 	if (env != NULL) {
616 		end_time = gethrtime();
617 		fprintf(stdout, "      g_get_wwn_list: "
618 		    "\t\tTime = %lld millisec\n",
619 		    (end_time - start_time)/1000000);
620 	}
621 	return (0);
622 
623 }
624 
625 int
g_devices_get_all(struct wwn_list_struct ** wwn_list_ptr)626 g_devices_get_all(struct wwn_list_struct **wwn_list_ptr)
627 {
628 	struct wwn_list_struct *tape_ptr = NULL;
629 	struct wwn_list_struct *tmp;
630 	int err;
631 	di_node_t root;
632 	hrtime_t	start_time, end_time;
633 	char *env = NULL;
634 
635 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
636 		start_time = gethrtime();
637 	}
638 
639 	/*
640 	 * Try to prime di_drv_first_node()
641 	 * If there are no nodes bound, di_drv_first_node()
642 	 * will return nothing.
643 	 */
644 	init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST);
645 	init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD);
646 
647 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
648 		return (L_DEV_SNAPSHOT_FAILED);
649 	}
650 
651 	if (env != NULL) {
652 		end_time = gethrtime();
653 		fprintf(stdout, "      di_init - /:  "
654 		    "\t\tTime = %lld millisec\n",
655 		    (end_time - start_time)/1000000);
656 	}
657 
658 	if (env != NULL) {
659 		start_time = gethrtime();
660 	}
661 
662 	if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME,
663 	    wwn_list_ptr)) != 0) {
664 		if (err != L_NO_DEVICES_FOUND) {
665 			di_fini(root);
666 			g_free_wwn_list(&tape_ptr);
667 			g_free_wwn_list(wwn_list_ptr);
668 			return (err);
669 		}
670 	}
671 
672 	if (env != NULL) {
673 		end_time = gethrtime();
674 		fprintf(stdout, "      devices_get_all - ssd:  "
675 		    "\t\tTime = %lld millisec\n",
676 		    (end_time - start_time)/1000000);
677 	}
678 
679 	if (env != NULL) {
680 		start_time = gethrtime();
681 	}
682 
683 	if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME,
684 	    &tape_ptr)) != 0) {
685 		di_fini(root);
686 		if (err != L_NO_DEVICES_FOUND) {
687 			g_free_wwn_list(&tape_ptr);
688 			g_free_wwn_list(wwn_list_ptr);
689 			return (err);
690 		} else {
691 			/*
692 			 * if *wwn_list_ptr == NULL
693 			 * we have disks but no tapes
694 			 * Just return
695 			 */
696 			if (*wwn_list_ptr != NULL) {
697 				return (0);
698 			} else {
699 				/*
700 				 * No disks or tapes
701 				 */
702 				g_free_wwn_list(&tape_ptr);
703 				g_free_wwn_list(wwn_list_ptr);
704 				return (err);
705 			}
706 		}
707 	}
708 
709 	if (env != NULL) {
710 		end_time = gethrtime();
711 		fprintf(stdout, "      devices_get_all - st: "
712 		    "\t\tTime = %lld millisec\n",
713 		    (end_time - start_time)/1000000);
714 	}
715 
716 	/* Now link the two together */
717 	if (*wwn_list_ptr != NULL) { /* We have both disks and tapes */
718 		/* Walk to the end of it */
719 		for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL;
720 		    tmp = tmp->wwn_next)
721 			;
722 		tmp->wwn_next = tape_ptr;
723 		tape_ptr->wwn_prev = tmp;
724 		di_fini(root);
725 		return (0);
726 	}
727 
728 	/* else we have no disks */
729 	*wwn_list_ptr = tape_ptr;
730 	di_fini(root);
731 	return (0);
732 }
733 
734 void
g_free_wwn_list_found(struct wwn_list_found_struct ** wwn_list_found)735 g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found)
736 {
737 	WWN_list_found	    *next = NULL;
738 
739 	/* return if wwn_list_found is NULL */
740 	if (wwn_list_found == NULL) {
741 		return;
742 	}
743 	for (; *wwn_list_found != NULL; *wwn_list_found = next) {
744 		next = (*wwn_list_found)->wwn_next;
745 		g_destroy_data(*wwn_list_found);
746 		*wwn_list_found = NULL;
747 	}
748 }
749 
750 void
g_free_wwn_list(struct wwn_list_struct ** wwn_list)751 g_free_wwn_list(struct wwn_list_struct **wwn_list)
752 {
753 	WWN_list	*next = NULL;
754 
755 	/* return if wwn_list is NULL */
756 	if (wwn_list == NULL) {
757 		return;
758 	}
759 
760 	for (; *wwn_list != NULL; *wwn_list = next) {
761 		next = (*wwn_list)->wwn_next;
762 		if ((*wwn_list)->physical_path != NULL)
763 			(void) g_destroy_data((*wwn_list)->physical_path);
764 		if ((*wwn_list)->logical_path != NULL)
765 			(void) g_destroy_data((*wwn_list)->logical_path);
766 		(void) g_destroy_data(*wwn_list);
767 	}
768 	wwn_list = NULL;
769 }
770 
771 
772 
773 
774 void
g_sort_wwn_list(struct wwn_list_struct ** wwn_list)775 g_sort_wwn_list(struct wwn_list_struct **wwn_list)
776 {
777 	int			i, n;
778 	struct wwn_list_struct	**wwn_list_array;
779 	struct wwn_list_struct	*wwn_list_ptr;
780 	struct wwn_list_struct	**wwn_list_array_ptr1;
781 	struct wwn_list_struct	**wwn_list_array_ptr2;
782 
783 	/*
784 	 * Count the number of wwn_list in the list
785 	 */
786 	for (n = 0,  wwn_list_ptr = *wwn_list;
787 	    wwn_list_ptr != NULL;
788 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
789 		n++;
790 	}
791 	if (n <= 1) {
792 		return;
793 	}
794 
795 	/*
796 	 * Allocate a simple wwn_list array and fill it in
797 	 */
798 	wwn_list_array = (struct wwn_list_struct **)
799 	    g_zalloc((n+1) * sizeof (struct wwn_list_struct *));
800 
801 	wwn_list_array_ptr1 = wwn_list_array;
802 	for (wwn_list_ptr = *wwn_list;
803 	    wwn_list_ptr != NULL;
804 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
805 		*wwn_list_array_ptr1++ = wwn_list_ptr;
806 	}
807 	*wwn_list_array_ptr1 = NULL;
808 
809 	/*
810 	 * Sort the wwn_list array
811 	 */
812 	qsort((void *) wwn_list_array, n,
813 	    sizeof (struct wwn_list_struct *), wwn_list_name_compare);
814 
815 	/*
816 	 * Rebuild the linked list wwn_list structure
817 	 */
818 	wwn_list_array_ptr1 = wwn_list_array;
819 	*wwn_list = *wwn_list_array_ptr1;
820 	wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1;
821 	(*wwn_list_array_ptr1)->wwn_prev = NULL;
822 	for (i = 0; i < n - 1; i++) {
823 		(*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1;
824 		(*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++;
825 	}
826 	(*wwn_list_array_ptr1)->wwn_next = NULL;
827 
828 	/*
829 	 * Clean up
830 	 */
831 	(void) g_destroy_data((void *)wwn_list_array);
832 }
833 
834 int
wwn_list_name_compare(const void * arg1,const void * arg2)835 wwn_list_name_compare(const void *arg1, const void *arg2)
836 {
837 	char	*s1, *s2;
838 	int	n1, n2;
839 	char	*p1, *p2;
840 
841 	s1 = (*((struct wwn_list_struct **)arg1))->logical_path;
842 	s2 = (*((struct wwn_list_struct **)arg2))->logical_path;
843 	for (;;) {
844 		if (*s1 == 0 || *s2 == 0)
845 			break;
846 		if ((isdigit(*s1) && isdigit(*s2))) {
847 			n1 = strtol(s1, &p1, 10);
848 			n2 = strtol(s2, &p2, 10);
849 			if (n1 != n2) {
850 				return (n1 - n2);
851 			}
852 			s1 = p1;
853 			s2 = p2;
854 		} else if (*s1 != *s2) {
855 			break;
856 		} else {
857 			s1++;
858 			s2++;
859 		}
860 	}
861 	return (*s1 - *s2);
862 }
863 
864 /*
865  * Get the limited map for FC4 devices.
866  * This function is specific to FC4
867  * devices and doesn't work for FC (leadville) devices.
868  *
869  * RETURN VALUES:
870  *	0	 O.K.
871  *	non-zero otherwise
872  *
873  * lilpmap *map_ptr:
874  *		NULL: No devices found
875  *		!NULL: if devices found
876  */
877 int
g_get_limited_map(char * path,struct lilpmap * map_ptr,int verbose)878 g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose)
879 {
880 	int	fd, i;
881 	char	drvr_path[MAXPATHLEN];
882 	struct	stat	stbuf;
883 
884 
885 	/* initialize map */
886 	(void) memset(map_ptr, 0, sizeof (struct lilpmap));
887 
888 	(void) strcpy(drvr_path, path);
889 	/*
890 	 * Get the path to the :devctl driver
891 	 *
892 	 * This assumes the path looks something like this:
893 	 * /devices/sbus@1f,0/SUNW,socal@1,0:1
894 	 * or
895 	 * /devices/sbus@1f,0/SUNW,socal@1,0
896 	 * or
897 	 * a 1 level PCI type driver
898 	 */
899 	if (stat(drvr_path, &stbuf) < 0) {
900 		return (L_LSTAT_ERROR);
901 	}
902 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
903 		/* append a port. Just try 0 since they did not give us one */
904 		(void) strcat(drvr_path, ":0");
905 	}
906 
907 	P_DPRINTF("  g_get_limited_map: Geting drive map from:"
908 	    " %s\n", drvr_path);
909 
910 	/* open controller */
911 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
912 		return (L_OPEN_PATH_FAIL);
913 
914 	if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) {
915 		I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
916 		(void) close(fd);
917 		return (L_FCIO_GETMAP_IOCTL_FAIL);
918 	}
919 	(void) close(fd);
920 
921 	/*
922 	 * Check for reasonableness.
923 	 */
924 	if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) {
925 		return (L_INVALID_LOOP_MAP);
926 	}
927 	for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) {
928 		if (map_ptr->lilp_list[i] > 0xef) {
929 			return (L_INVALID_LOOP_MAP);
930 		}
931 	}
932 
933 	return (0);
934 }
935 
936 
937 /*
938  * For leadville specific HBA's ONLY.
939  * Get the host specific parameters,
940  * al_pa, hard address, node/port WWN etc.
941  *
942  * OUTPUT:
943  *	fc_port_dev_t structure.
944  *
945  * RETURNS:
946  *	0	if  OK
947  *	non-zero in case of error.
948  */
949 int
g_get_host_params(char * host_path,fc_port_dev_t * host_val,int verbose)950 g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose)
951 {
952 	int		err;
953 	int		fd;
954 	int		dev_type;
955 	fcio_t		fcio;
956 
957 	/* return invalid path if host_path is NULL */
958 	if (host_path == NULL) {
959 		return (L_INVALID_PATH);
960 	}
961 	/* return invalid arg if host_val is NULL */
962 	if (host_val == NULL) {
963 		return (L_INVALID_ARG);
964 	}
965 
966 	dev_type = g_get_path_type(host_path);
967 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
968 		return (L_INVALID_PATH_TYPE);
969 	}
970 	if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) {
971 		return (L_OPEN_PATH_FAIL);
972 	}
973 
974 	/* initialize structure */
975 	(void) memset(host_val, 0, sizeof (struct fc_port_dev));
976 
977 	fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
978 	fcio.fcio_xfer = FCIO_XFER_READ;
979 	fcio.fcio_obuf = (caddr_t)host_val;
980 	fcio.fcio_olen = sizeof (fc_port_dev_t);
981 
982 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
983 		I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
984 		(void) close(fd);
985 		return (L_FCIO_GET_HOST_PARAMS_FAIL);
986 	}
987 	(void) close(fd);
988 
989 	/* get the inquiry information for the leadville HBA. */
990 	if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn,
991 	    &host_val->dev_dtype)) != 0) {
992 		return (err);
993 	}
994 	return (0);
995 }
996 
997 
998 
999 /*
1000  * Issue FCIO ioctls to the port(fp) driver.
1001  * FCIO ioctl needs to be retried when it
1002  * is returned with an EINVAL error, wait
1003  * time between retries should be atleast
1004  * WAIT_FCIO_IOCTL (too much of a time to wait!!)
1005  *
1006  * OUTPUT:
1007  *	fcio_t structure
1008  *
1009  * RETURNS:
1010  *	0	 if O.K.
1011  *	non-zero otherwise.
1012  */
1013 int
g_issue_fcio_ioctl(int fd,fcio_t * fcio,int verbose)1014 g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose)
1015 {
1016 	int	ntries;
1017 
1018 	for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
1019 		if (ioctl(fd, FCIO_CMD, fcio) != 0) {
1020 			if ((errno == EAGAIN) &&
1021 			    (ntries+1 < RETRY_FCIO_IOCTL)) {
1022 				/* wait WAIT_FCIO_IOCTL */
1023 				(void) usleep(WAIT_FCIO_IOCTL);
1024 				continue;
1025 			}
1026 			I_DPRINTF("FCIO ioctl failed.\n"
1027 			    "Error: %s. fc_error = %d (0x%x)\n",
1028 			    strerror(errno), fcio->fcio_errno,
1029 			    fcio->fcio_errno);
1030 			if (errno == EINVAL) {
1031 				if (fcio->fcio_errno == FC_TOOMANY) {
1032 					return (L_INVALID_DEVICE_COUNT);
1033 				} else {
1034 					return (errno);
1035 				}
1036 			}
1037 			/*
1038 			 * When port is offlined, qlc
1039 			 * returns the FC_OFFLINE error and errno
1040 			 * is set to EIO.
1041 			 * We do want to ignore this error,
1042 			 * especially when an enclosure is
1043 			 * removed from the loop.
1044 			 */
1045 			if (fcio->fcio_errno == FC_OFFLINE)
1046 				break;
1047 			return (-1);
1048 		}
1049 		break;
1050 	}
1051 
1052 	return (0);
1053 }
1054 
1055 /*
1056  * This function issues the FCP_TGT_INQUIRY ioctl to
1057  * the fcp module
1058  *
1059  * OUTPUT:
1060  *	fcp_ioctl structure in fcp_data is filled in by fcp
1061  *
1062  * RETURN VALUES :
1063  *	0 on Success
1064  *	Non-zero otherwise
1065  */
1066 static int
g_issue_fcp_ioctl(int fd,struct fcp_ioctl * fcp_data,int verbose)1067 g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose)
1068 {
1069 	int			num_tries = 0;
1070 	struct device_data	*dev_data = NULL;
1071 
1072 	/*
1073 	 * Issue the ioctl to FCP
1074 	 * The retries are required because the driver may
1075 	 * need some time to respond at times.
1076 	 */
1077 	while (num_tries++ < RETRY_FCP_IOCTL) {
1078 		/* if ioctl fails it is an error from Solaris operation. */
1079 		if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) {
1080 			if (errno == EAGAIN) {
1081 				(void) usleep(WAIT_FCP_IOCTL);
1082 				continue;
1083 			} else {
1084 				break;
1085 			}
1086 		}
1087 		dev_data = (struct device_data *)((void *)(fcp_data->list));
1088 		if (dev_data->dev_status == 0) {
1089 			return (0);
1090 		}
1091 
1092 		if (dev_data->dev_status == EAGAIN) {
1093 			(void) usleep(WAIT_FCP_IOCTL);
1094 			continue;
1095 		} else {
1096 			dev_data->dev0_type = DTYPE_UNKNOWN;
1097 			return (0);
1098 		}
1099 	}
1100 
1101 	return (L_FCP_TGT_INQUIRY_FAIL);
1102 }
1103 
1104 /*
1105  * Get the number of devices and also
1106  * a list of devices accessible through
1107  * the device's port as specified by path.
1108  * The calling function * is responsible for freeing the dev_list.
1109  *
1110  * Acquires inq_dtype from g_get_inq_dtype() and
1111  * stores into dev_dtype field of fc_port_dev.
1112  *
1113  * For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login
1114  * and get inq dtype.
1115  *
1116  * dev_list:
1117  *	NULL:	  No devices found, in case of an error
1118  *	Non-NULL: Devices found.
1119  * ndevs:
1120  *	set to the number of devices
1121  *	accessible through the port.
1122  *
1123  * RETURNS:
1124  *	0	 if O.K.
1125  *	non-zero otherwise
1126  */
1127 int
g_get_dev_list(char * path,fc_port_dev_t ** dev_list,int * ndevs)1128 g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs)
1129 {
1130 	int		num_devices = 0;
1131 	int		i, err, ulp_failure = 0, new_count = 0;
1132 	int		dev_type;
1133 	int		fd;
1134 	char		fcapath[MAXPATHLEN];
1135 	char		*char_ptr;
1136 	struct	stat	stbuf;
1137 	fcio_t		fcio;
1138 	uint32_t	port_top;
1139 	fc_port_dev_t	*dlist;
1140 
1141 	*dev_list = dlist = NULL;
1142 	(void) strcpy(fcapath, path);
1143 	/*
1144 	 * Get the path to the :devctl driver
1145 	 *
1146 	 * This assumes the path looks something like this:
1147 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1148 	 * or
1149 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1150 	 * or
1151 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1152 	 * or
1153 	 * a 1 level PCI type driver but still :devctl
1154 	 */
1155 	if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) {
1156 		if ((char_ptr = strrchr(fcapath, '/')) == NULL) {
1157 			return (L_INVALID_PATH);
1158 		}
1159 		*char_ptr = '\0';   /* Terminate sting  */
1160 		/* append controller */
1161 		(void) strcat(fcapath, FC_CTLR);
1162 	} else {
1163 		if (stat(fcapath, &stbuf) < 0) {
1164 			return (L_LSTAT_ERROR);
1165 		}
1166 		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1167 			/* append controller */
1168 			(void) strcat(fcapath, FC_CTLR);
1169 		}
1170 	}
1171 	dev_type = g_get_path_type(fcapath);
1172 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1173 		return (L_INVALID_PATH_TYPE);
1174 	}
1175 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1176 		return (L_OPEN_PATH_FAIL);
1177 	}
1178 
1179 	/*
1180 	 * Get the device list from port driver
1181 	 */
1182 	fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
1183 	fcio.fcio_olen = sizeof (num_devices);
1184 	fcio.fcio_xfer = FCIO_XFER_READ;
1185 	fcio.fcio_obuf = (caddr_t)&num_devices;
1186 	if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
1187 		I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
1188 		(void) close(fd);
1189 		return (L_FCIO_GET_NUM_DEVS_FAIL);
1190 	}
1191 	if (num_devices == 0) {
1192 		*ndevs = 0;
1193 		(void) close(fd);
1194 		return (L_NO_DEVICES_FOUND);
1195 	}
1196 
1197 	if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1198 	    sizeof (fc_port_dev_t))) == NULL) {
1199 		(void) close(fd);
1200 		return (L_MALLOC_FAILED);
1201 	}
1202 	bzero((caddr_t)&fcio, sizeof (fcio));
1203 	/* Get the device list */
1204 	fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1205 	/* Information read operation */
1206 	fcio.fcio_xfer = FCIO_XFER_READ;
1207 	fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1208 	fcio.fcio_obuf = (caddr_t)dlist;
1209 	/* new device count */
1210 	fcio.fcio_alen = sizeof (new_count);
1211 	fcio.fcio_abuf = (caddr_t)&new_count;
1212 	if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1213 		if (err == L_INVALID_DEVICE_COUNT) {
1214 			/*
1215 			 * original buffer was small so allocate buffer
1216 			 * with a new count and retry.
1217 			 */
1218 			free(dlist);
1219 			num_devices = new_count;
1220 			new_count = 0;
1221 			if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1222 			    sizeof (fc_port_dev_t))) == NULL) {
1223 				(void) close(fd);
1224 				return (L_MALLOC_FAILED);
1225 			}
1226 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1227 			/* Information read operation */
1228 			fcio.fcio_xfer = FCIO_XFER_READ;
1229 			fcio.fcio_obuf = (caddr_t)dlist;
1230 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1231 			/* new device count */
1232 			fcio.fcio_alen = sizeof (new_count);
1233 			fcio.fcio_abuf = (caddr_t)&new_count;
1234 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1235 				if (err == L_INVALID_DEVICE_COUNT) {
1236 					/*
1237 					 * No more retry. There may be severe
1238 					 * hardware problem so return error
1239 					 * here.
1240 					 */
1241 					I_DPRINTF(" Device count was %d"
1242 					    " should have been %d\n",
1243 					    num_devices, new_count);
1244 				} else {
1245 					I_DPRINTF(
1246 					    " FCIO_GET_DEV_LIST ioctl failed.");
1247 					err = L_FCIO_GET_DEV_LIST_FAIL;
1248 				}
1249 				free(dlist);
1250 				(void) close(fd);
1251 				return (err);
1252 			}
1253 		} else {
1254 			I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
1255 			free(dlist);
1256 			(void) close(fd);
1257 			return (L_FCIO_GET_DEV_LIST_FAIL);
1258 		}
1259 	}
1260 
1261 	/*
1262 	 * if new count is smaller than the original number from
1263 	 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
1264 	 * and continue.
1265 	 */
1266 	if (new_count < num_devices) {
1267 		if (new_count == 0) {
1268 			*ndevs = 0;
1269 			(void) close(fd);
1270 			S_FREE(dlist);
1271 			return (L_NO_DEVICES_FOUND);
1272 		}
1273 		num_devices = new_count;
1274 		if ((dlist = (fc_port_dev_t *)realloc(dlist,
1275 		    (new_count * sizeof (fc_port_dev_t))))
1276 		    == NULL) {
1277 			S_FREE(dlist);
1278 			(void) close(fd);
1279 			return (L_MALLOC_FAILED);
1280 		}
1281 	}
1282 
1283 	*dev_list = dlist;
1284 	*ndevs = num_devices;
1285 
1286 	/* close here since fcapath will be passed to other routines. */
1287 	(void) close(fd);
1288 
1289 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1290 		free(*dev_list);
1291 		*dev_list = NULL;
1292 		return (err);
1293 	}
1294 
1295 	/* Get the inq_dtype for each device on dev list. */
1296 	for (i = 0; i < num_devices; i++, dlist++) {
1297 		/* Get the inq_dtype for each device. */
1298 		if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn,
1299 		    &dlist->dev_dtype)) != 0) {
1300 			/*
1301 			 * if g_get_inq_dtype failed on g_dev_login
1302 			 * or g_issue_fcp_ioctl, continue to the next
1303 			 * dev on dlist.
1304 			 * L_GET_DEV_LIST_ULP_FAILURE is returned
1305 			 * after processing the whole dlist.
1306 			 */
1307 			if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
1308 			    (err == L_FCP_TGT_INQUIRY_FAIL)) {
1309 				ulp_failure = 1;
1310 				dlist->dev_dtype = GFC_ERR_INQ_DTYPE;
1311 			} else {
1312 				(void) free(*dev_list);
1313 				*dev_list = NULL;
1314 				return (err);
1315 			}
1316 		}
1317 	}
1318 
1319 	if (ulp_failure) {
1320 		return (L_GET_DEV_LIST_ULP_FAILURE);
1321 	} else {
1322 		return (0);
1323 	}
1324 }
1325 
1326 
1327 /* Constant used by g_get_inq_dtype() */
1328 #define	FCP_PATH	"/devices/pseudo/fcp@0:fcp"
1329 
1330 /*
1331  * Gets the inq_dtype for devices on the fabric FC driver
1332  * through an ioctl to the FCP module.
1333  *
1334  * OUTPUT:
1335  *	inq_dtype is set to the dtype on success
1336  *
1337  * RETURN VALUES:
1338  *	0 on Success
1339  *	Non-zero on error
1340  */
1341 int
g_get_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)1342 g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1343 {
1344 	int			dev_type, fd;
1345 	int			err, fcp_fd;
1346 	uint32_t		state;
1347 	uint32_t		port_top = 0;
1348 	struct fcp_ioctl	fcp_data;
1349 	struct device_data	inq_data;
1350 	struct stat		sbuf;
1351 
1352 	dev_type = g_get_path_type(fcapath);
1353 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1354 		return (L_INVALID_PATH_TYPE);
1355 	}
1356 
1357 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
1358 		return (err);
1359 	}
1360 
1361 	if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) {
1362 		/*
1363 		 * if there is an error on getting port state we will
1364 		 * continue to login.
1365 		 * state can be either of
1366 		 * PORT_DEVICE_INVALID, PORT_DEVICE_VALID,
1367 		 * PORT_DEVICE_LOGGED_IN.  Trying port login
1368 		 * unless already logged in.
1369 		 * It will be examined if there is an adverse
1370 		 * effect on invalid state device.
1371 		 */
1372 		if (((err = g_get_dev_port_state(fcapath, pwwn, &state))
1373 		    != 0) || (state != PORT_DEVICE_LOGGED_IN)) {
1374 			/* do port login to fabric device.  */
1375 			if ((err = g_dev_login(fcapath, pwwn)) != 0) {
1376 				return (err);
1377 			}
1378 		}
1379 	}
1380 
1381 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1)
1382 		return (L_OPEN_PATH_FAIL);
1383 
1384 	if (fstat(fd, &sbuf) == -1) {
1385 		(void) close(fd);
1386 		return (L_FSTAT_ERROR);
1387 	}
1388 
1389 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1390 		(void) close(fd);
1391 		return (L_OPEN_PATH_FAIL);
1392 	}
1393 
1394 	/* Get the minor number for an fp instance */
1395 	fcp_data.fp_minor = minor(sbuf.st_rdev);
1396 
1397 	fcp_data.listlen = 1;
1398 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
1399 	fcp_data.list = (caddr_t)&inq_data;
1400 
1401 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1402 		close(fd);
1403 		close(fcp_fd);
1404 		return (err);
1405 	}
1406 	*inq_dtype = inq_data.dev0_type;
1407 
1408 	close(fd);
1409 	close(fcp_fd);
1410 
1411 	return (err);
1412 }
1413 
1414 /*
1415  * Gets the inq_dtype for devices on the fabric FC driver
1416  * through an ioctl to the FCP module.
1417  *
1418  * This is exactly same as g_get_inq_dtype except that it does not do
1419  * g_dev_login(). That is for the case when the FCA tries to get its own
1420  * inq_dtype and in such a case, it cannot PLOGI into itself.
1421  *
1422  * OUTPUT:
1423  *	inq_dtype is set to the dtype on success
1424  *
1425  * RETURN VALUES:
1426  *	0 on Success
1427  *	Non-zero on error
1428  */
1429 static int
get_fca_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)1430 get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
1431 {
1432 	int			dev_type, fd;
1433 	int			err, fcp_fd;
1434 	struct fcp_ioctl	fcp_data;
1435 	struct device_data	inq_data;
1436 	struct stat		sbuf;
1437 
1438 	dev_type = g_get_path_type(fcapath);
1439 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
1440 		return (L_INVALID_PATH_TYPE);
1441 	}
1442 
1443 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
1444 		return (L_OPEN_PATH_FAIL);
1445 	}
1446 
1447 	if (fstat(fd, &sbuf) == -1) {
1448 		(void) close(fd);
1449 		return (L_FSTAT_ERROR);
1450 	}
1451 
1452 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
1453 		(void) close(fd);
1454 		return (L_OPEN_PATH_FAIL);
1455 	}
1456 
1457 	/* Get the minor number for an fp instance */
1458 	fcp_data.fp_minor = minor(sbuf.st_rdev);
1459 
1460 	fcp_data.listlen = 1;
1461 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
1462 	fcp_data.list = (caddr_t)&inq_data;
1463 
1464 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
1465 		close(fd);
1466 		close(fcp_fd);
1467 		return (err);
1468 	}
1469 	*inq_dtype = inq_data.dev0_type;
1470 
1471 	close(fd);
1472 	close(fcp_fd);
1473 
1474 	return (0);
1475 }
1476 
1477 /*
1478  * This function returns the traditional g_get_dev_map. Device list
1479  * and local hba seperate.
1480  */
1481 int
g_get_dev_map(char * path,gfc_map_t * map_ptr,int verbose)1482 g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose)
1483 {
1484 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD));
1485 }
1486 
1487 /*
1488  * This function returns the device map with local hba in physical
1489  * order.  Note: Physical order is only returned properly for
1490  * private loop. local hba is also included seperate
1491  */
1492 int
g_get_lilp_map(char * path,gfc_map_t * map_ptr,int verbose)1493 g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose)
1494 {
1495 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP));
1496 }
1497 
1498 /*
1499  * Gets device map from nexus driver
1500  *
1501  * PARAMS:
1502  *	path -	must be the physical path to a device
1503  *	map  -	loop map returned from fc port.
1504  *	verbose - options.
1505  *
1506  * LOGIC:
1507  *	1. check the validity of path via g_get_path_type.
1508  *	2. If FC path, get the topology of the path via
1509  *		g_get_fca_port_topology.
1510  *
1511  *	3. If FC type(Leadville statck)
1512  *		g_get_dev_list to get the device node list of fc_port_dev_t.
1513  *		g_get_host_params to get the fca port node of fc_port_dev_t.
1514  *
1515  *		Case of fabric or public loop topology
1516  *			Check if the port id > 0xffff.
1517  *			Move device node and fca port node to
1518  *			gfc_map structure via gfc_port_dev_info_t
1519  *			pub_port union.
1520  *			Issue g_get_inq_dtype to get FCP inquiry data
1521  *			and store it into gfc_port_dev_info_t.
1522  *
1523  *		Case of private loop topology
1524  *			Check if the port id < 0xff.
1525  *			Move device node and fca port node to
1526  *			gfc_map structure via gfc_port_dev_info_t
1527  *			priv_port union.
1528  *			Issue g_get_inq_dtype to get FCP inquiry data
1529  *			and store it into gfc_port_dev_info_t.
1530  *
1531  *	   else FC4 type(socal/sf or ifp stack)
1532  *		SFIOCGMAP ioctl to get the device and hba nodes of
1533  *			sf_addr_pair_t.
1534  *
1535  *
1536  * RETURNS:
1537  *	0	: if OK
1538  *	non-zero: otherwise
1539  */
1540 int
create_map(char * path,gfc_map_t * map_ptr,int verbose,int map_type)1541 create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type)
1542 {
1543 	int		fd, i, j, num_devices = 0, err, pathcnt = 1;
1544 	char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
1545 	char		*char_ptr;
1546 	struct stat	stbuf;
1547 	fc_port_dev_t	*dev_list, *dlistptr;
1548 	uint32_t	hba_port_top = 0;
1549 	uint_t		dev_type;
1550 	sf_al_map_t	sf_map;
1551 	gfc_port_dev_info_t	*dev_ptr;
1552 	fc_port_dev_t	fp_hba_port;
1553 	mp_pathlist_t	pathlist;
1554 	int		p_on = 0, p_st = 0;
1555 
1556 	/* return invalid path if path is NULL */
1557 	if (path == NULL) {
1558 		return (L_INVALID_PATH);
1559 	}
1560 	/* return invalid arg if map_ptr is NULL */
1561 	if (map_ptr == NULL) {
1562 		return (L_INVALID_ARG);
1563 	}
1564 
1565 	map_ptr->dev_addr = NULL;
1566 	map_ptr->count = 0;
1567 	(void) strcpy(drvr_path, path);
1568 	/*
1569 	 * Get the path to the :devctl driver
1570 	 *
1571 	 * This assumes the path looks something like this:
1572 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
1573 	 * or
1574 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
1575 	 * or
1576 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
1577 	 * or
1578 	 * a 1 level PCI type driver but still :devctl
1579 	 */
1580 	if (strstr(path, SCSI_VHCI)) {
1581 		(void) strcpy(drvr_path0, path);
1582 		if (g_get_pathlist(drvr_path0, &pathlist)) {
1583 			return (L_INVALID_PATH);
1584 		}
1585 		pathcnt = pathlist.path_count;
1586 		p_on = p_st = 0;
1587 		for (i = 0; i < pathcnt; i++) {
1588 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
1589 				if (pathlist.path_info[i].path_state ==
1590 				    MDI_PATHINFO_STATE_ONLINE) {
1591 					p_on = i;
1592 					break;
1593 				} else if (pathlist.path_info[i].path_state ==
1594 				    MDI_PATHINFO_STATE_STANDBY) {
1595 					p_st = i;
1596 				}
1597 			}
1598 		}
1599 		if (pathlist.path_info[p_on].path_state ==
1600 		    MDI_PATHINFO_STATE_ONLINE) {
1601 			/* on_line path */
1602 			(void) strcpy(drvr_path,
1603 			    pathlist.path_info[p_on].path_hba);
1604 		} else {
1605 			/* standby or path0 */
1606 			(void) strcpy(drvr_path,
1607 			    pathlist.path_info[p_st].path_hba);
1608 		}
1609 		free(pathlist.path_info);
1610 		(void) strcat(drvr_path, FC_CTLR);
1611 	} else {
1612 		(void) strcpy(drvr_path, path);
1613 		if (strstr(drvr_path, DRV_NAME_SSD) ||
1614 		    strstr(drvr_path, SES_NAME) ||
1615 		    strstr(drvr_path, DRV_NAME_ST)) {
1616 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
1617 				return (L_INVALID_PATH);
1618 			}
1619 			*char_ptr = '\0';   /* Terminate sting  */
1620 			/* append controller */
1621 			(void) strcat(drvr_path, FC_CTLR);
1622 		} else {
1623 			if (stat(drvr_path, &stbuf) < 0) {
1624 				return (L_LSTAT_ERROR);
1625 			}
1626 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
1627 				/* append controller */
1628 				(void) strcat(drvr_path, FC_CTLR);
1629 			}
1630 		}
1631 	}
1632 
1633 	P_DPRINTF("  g_get_dev_map: Geting drive map from:"
1634 	    " %s\n", drvr_path);
1635 
1636 	dev_type = g_get_path_type(drvr_path);
1637 	if ((dev_type == 0) || !(dev_type & XPORT_MASK)) {
1638 		return (L_INVALID_PATH_TYPE);
1639 	}
1640 
1641 	/* get fiber topology */
1642 	if ((err = g_get_fca_port_topology(drvr_path,
1643 	    &hba_port_top, verbose)) != 0) {
1644 		return (err);
1645 	}
1646 
1647 	/* for FC devices. */
1648 	if (dev_type & FC_FCA_MASK) {
1649 		/*
1650 		 * if g_get_dev_list fails with L_NO_DEVICES_FOUND
1651 		 * we still want to call g_get_host_params to try to find the
1652 		 * HBA.  If we do not see any HBAs on the loop, the
1653 		 * g_get_host_params will fail when it trys to issue the target
1654 		 * inquiry ioctl.  In this case, we would still like to return
1655 		 * L_NO_DEVICES_FOUND.
1656 		 *
1657 		 * If g_get_dev_list fails with L_NO_DEVICES_FOUND and
1658 		 * g_get_host_params fails, the function returns
1659 		 * L_NO_DEVICES_FOUND
1660 		 */
1661 		if ((err = g_get_dev_list(drvr_path, &dev_list,
1662 		    &num_devices)) != 0) {
1663 			/*
1664 			 * g_get_dev_map doesn't allow ulp failure
1665 			 * to continue thus we need to free dev_list
1666 			 * here.
1667 			 */
1668 			if (err == L_GET_DEV_LIST_ULP_FAILURE) {
1669 				(void) free(dev_list);
1670 			}
1671 			if (err != L_NO_DEVICES_FOUND) {
1672 				return (err);
1673 			}
1674 		}
1675 
1676 		/* Get local HBA information */
1677 		if ((err = g_get_host_params(drvr_path, &fp_hba_port,
1678 		    verbose)) != 0) {
1679 			(void) free(dev_list);
1680 			if (num_devices == 0)
1681 				return (L_NO_DEVICES_FOUND);
1682 			else
1683 				return (err);
1684 		}
1685 
1686 		/* If devices, other than local HBA are found	*/
1687 		/* allocate space for them in the gfc_map.	*/
1688 		if (num_devices > 0) {
1689 
1690 			/* If map type is on MAP_FORMAT_LILP we need	*/
1691 			/* to add space for the local HBA		*/
1692 			if (map_type == MAP_FORMAT_LILP) {
1693 				map_ptr->count = ++num_devices;
1694 			} else {
1695 				map_ptr->count = num_devices;
1696 			}
1697 
1698 			if ((map_ptr->dev_addr = (gfc_port_dev_info_t *)
1699 			    calloc(map_ptr->count,
1700 			    sizeof (gfc_port_dev_info_t))) == NULL) {
1701 				(void) free(dev_list);
1702 				return (L_MALLOC_FAILED);
1703 			}
1704 		}
1705 
1706 		/* If we want the lilp map then we need to do a little	*/
1707 		/* work here.  The lilp map contains the local hba in	*/
1708 		/* the dev_addr.  Once this has been added qsort the	*/
1709 		/* dev_addr array so it's in physical order.		*/
1710 		/* The lilp map will contain the local hba in the	*/
1711 		/* dev_addr array only when num_devices > 0		*/
1712 		if (map_type == MAP_FORMAT_LILP && num_devices > 0) {
1713 
1714 			/* First we need to allocate one additional	*/
1715 			/* device to the dev_addr structure, for the	*/
1716 			/* local hba					*/
1717 			if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
1718 			    (num_devices * sizeof (fc_port_dev_t))))
1719 			    == NULL) {
1720 				S_FREE(dev_list);
1721 				(void) free(map_ptr->dev_addr);
1722 				map_ptr->dev_addr = NULL;
1723 				return (L_MALLOC_FAILED);
1724 			}
1725 
1726 			/* Next, copy the local hba into this new loc.	*/
1727 			if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
1728 			    sizeof (fc_port_dev_t)) == NULL) {
1729 				(void) free(dev_list);
1730 				(void) free(map_ptr->dev_addr);
1731 				map_ptr->dev_addr = NULL;
1732 				return (L_MEMCPY_FAILED);
1733 			}
1734 
1735 			/* Now sort by physical location		*/
1736 			qsort((void*)dev_list, num_devices,
1737 			    sizeof (fc_port_dev_t), lilp_map_cmp);
1738 		}
1739 
1740 		dlistptr = dev_list;
1741 		dev_ptr = map_ptr->dev_addr;
1742 
1743 		switch (hba_port_top) {
1744 		case FC_TOP_FABRIC:
1745 		case FC_TOP_PUBLIC_LOOP:
1746 			if (fp_hba_port.dev_did.port_id <= 0xffff) {
1747 				(void) free(dlistptr);
1748 				(void) free(map_ptr->dev_addr);
1749 				map_ptr->dev_addr = NULL;
1750 				return (L_INVALID_FABRIC_ADDRESS);
1751 			} else {
1752 				map_ptr->hba_addr.port_topology = hba_port_top;
1753 				map_ptr->hba_addr.gfc_port_dev.pub_port =
1754 				    fp_hba_port;
1755 			}
1756 			for (i = 0; i < num_devices; i++, dev_ptr++,
1757 			    dev_list++) {
1758 				if (dev_list->dev_did.port_id <= 0xffff) {
1759 					(void) free(dlistptr);
1760 					(void) free(map_ptr->dev_addr);
1761 					map_ptr->dev_addr = NULL;
1762 					return (L_INVALID_FABRIC_ADDRESS);
1763 				} else {
1764 					dev_ptr->port_topology = hba_port_top;
1765 					dev_ptr->gfc_port_dev.pub_port =
1766 					    *dev_list;
1767 				}
1768 			}
1769 			break;
1770 		case FC_TOP_PRIVATE_LOOP:
1771 			/*
1772 			 * Map the (new->old) structures here.
1773 			 * Checking (i < SF_NUM_ENTRIES_IN_MAP) just to
1774 			 * make sure that we don't overrun the map structure
1775 			 * since it can hold data for upto 126 devices.
1776 			 */
1777 			if (fp_hba_port.dev_did.port_id > 0xff) {
1778 				(void) free(dlistptr);
1779 				(void) free(map_ptr->dev_addr);
1780 				map_ptr->dev_addr = NULL;
1781 				return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1782 			} else {
1783 				map_ptr->hba_addr.port_topology = hba_port_top;
1784 				map_ptr->hba_addr.gfc_port_dev.
1785 				    priv_port.sf_al_pa =
1786 				    (uchar_t)fp_hba_port.dev_did.port_id;
1787 				map_ptr->hba_addr.gfc_port_dev.
1788 				    priv_port.sf_hard_address = (uchar_t)
1789 				    fp_hba_port.dev_hard_addr.hard_addr;
1790 				for (j = 0; j < FC_WWN_SIZE; j++) {
1791 					map_ptr->hba_addr.gfc_port_dev.
1792 					    priv_port.sf_node_wwn[j] =
1793 					    fp_hba_port.dev_nwwn.raw_wwn[j];
1794 					map_ptr->hba_addr.gfc_port_dev.
1795 					    priv_port.sf_port_wwn[j] =
1796 					    fp_hba_port.dev_pwwn.raw_wwn[j];
1797 				}
1798 				map_ptr->hba_addr.gfc_port_dev.
1799 				    priv_port.sf_inq_dtype =
1800 				    fp_hba_port.dev_dtype;
1801 			}
1802 
1803 			for (i = 0; (i < num_devices &&
1804 			    i < SF_NUM_ENTRIES_IN_MAP);
1805 			    i++, dev_ptr++, dev_list++) {
1806 				/*
1807 				 * Out of 24 bits of port_id, copy only
1808 				 * 8 bits to al_pa. This works okay for
1809 				 * devices that're on a private loop.
1810 				 */
1811 				if (dev_list->dev_did.port_id > 0xff) {
1812 					(void) free(dlistptr);
1813 					(void) free(map_ptr->dev_addr);
1814 					map_ptr->dev_addr = NULL;
1815 					return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1816 				}
1817 				dev_ptr->port_topology = hba_port_top;
1818 				dev_ptr->gfc_port_dev.priv_port.sf_al_pa
1819 				    = (uchar_t)dev_list->dev_did.port_id;
1820 
1821 			/* Code refactorization is needed for C style */
1822 			dev_ptr->gfc_port_dev.priv_port.sf_hard_address
1823 			    = (uchar_t)dev_list->dev_hard_addr.hard_addr;
1824 
1825 				for (j = 0; j < FC_WWN_SIZE; j++) {
1826 
1827 			dev_ptr->gfc_port_dev.priv_port.sf_node_wwn[j] =
1828 			    dev_list->dev_nwwn.raw_wwn[j];
1829 			dev_ptr->gfc_port_dev.priv_port.sf_port_wwn[j] =
1830 			    dev_list->dev_pwwn.raw_wwn[j];
1831 
1832 				}
1833 				dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype =
1834 				    dev_list->dev_dtype;
1835 			}
1836 			break;
1837 		case FC_TOP_PT_PT:
1838 			(void) free(dlistptr);
1839 			(void) free(map_ptr->dev_addr);
1840 			map_ptr->dev_addr = NULL;
1841 			return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
1842 		default:
1843 			(void) free(dlistptr);
1844 			(void) free(map_ptr->dev_addr);
1845 			map_ptr->dev_addr = NULL;
1846 			return (L_UNEXPECTED_FC_TOPOLOGY);
1847 		}	/* End of switch on port_topology */
1848 		(void) free(dlistptr);
1849 
1850 	} else {	/* sf and fc4/pci devices */
1851 		if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
1852 			return (errno);
1853 		/* initialize map */
1854 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
1855 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
1856 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
1857 			(void) close(fd);
1858 			return (L_SFIOCGMAP_IOCTL_FAIL);
1859 		}
1860 		/* Check for reasonableness. */
1861 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
1862 			(void) close(fd);
1863 			return (L_INVALID_LOOP_MAP);
1864 		}
1865 		if (sf_map.sf_count == 0) {
1866 			(void) close(fd);
1867 			return (L_NO_DEVICES_FOUND);
1868 		}
1869 
1870 		map_ptr->count = sf_map.sf_count;
1871 		if ((map_ptr->dev_addr =
1872 		    (gfc_port_dev_info_t *)calloc(map_ptr->count,
1873 		    sizeof (gfc_port_dev_info_t))) == NULL) {
1874 			(void) close(fd);
1875 			return (L_MALLOC_FAILED);
1876 		}
1877 		dev_ptr = map_ptr->dev_addr;
1878 		for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) {
1879 			if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) {
1880 				(void) free(map_ptr->dev_addr);
1881 				map_ptr->dev_addr = NULL;
1882 				(void) close(fd);
1883 				return (L_INVALID_LOOP_MAP);
1884 			}
1885 			dev_ptr->port_topology = hba_port_top;
1886 			dev_ptr->gfc_port_dev.priv_port =
1887 			    sf_map.sf_addr_pair[i];
1888 		}
1889 		map_ptr->hba_addr.port_topology = hba_port_top;
1890 		map_ptr->hba_addr.gfc_port_dev.priv_port =
1891 		    sf_map.sf_hba_addr;
1892 		(void) close(fd);
1893 	}
1894 
1895 	return (0);
1896 }
1897 
1898 /*
1899  * This function consturct FC proerty list using map_dev_fc_prop_list.
1900  *
1901  * port WWN, node WWN, port addr and hard addr properties is constructed.
1902  *
1903  * return 0 if OK.
1904  * otherwise returns error code.
1905  */
1906 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)1907 update_map_dev_fc_prop(impl_map_dev_prop_t **prop_list, uint32_t map_topo,
1908     uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr)
1909 {
1910 	impl_map_dev_prop_t	*prop_ptr, *pl_start = NULL, *pl_end = NULL;
1911 	uchar_t *port_wwn_data, *node_wwn_data;
1912 	int *port_addr_data, *hard_addr_data;
1913 
1914 	/* consrtruct port addr property. */
1915 	if ((map_topo == FC_TOP_FABRIC) || (map_topo == FC_TOP_PUBLIC_LOOP)) {
1916 		if (port_addr <= 0xffff) {
1917 			return (L_INVALID_FABRIC_ADDRESS);
1918 		}
1919 	} else if (map_topo == FC_TOP_PRIVATE_LOOP) {
1920 		if (port_addr > 0xff) {
1921 			return (L_INVALID_PRIVATE_LOOP_ADDRESS);
1922 		}
1923 	}
1924 
1925 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1926 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1927 		return (L_MALLOC_FAILED);
1928 	}
1929 	(void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP,
1930 	    strlen(PORT_ADDR_PROP));
1931 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1932 
1933 	if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1934 		free(prop_ptr);
1935 		return (L_MALLOC_FAILED);
1936 	}
1937 	*port_addr_data = port_addr;
1938 	prop_ptr->prop_data = port_addr_data;
1939 
1940 	pl_start = pl_end = prop_ptr;
1941 
1942 	/* consrtruct port WWN property. */
1943 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1944 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1945 		free_prop_list(&pl_start);
1946 		return (L_MALLOC_FAILED);
1947 	}
1948 	(void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP,
1949 	    strlen(PORT_WWN_PROP));
1950 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1951 
1952 	if ((port_wwn_data = (uchar_t *)calloc(1, FC_WWN_SIZE)) == NULL) {
1953 		free_prop_list(&pl_start);
1954 		return (L_MALLOC_FAILED);
1955 	}
1956 	memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE);
1957 	prop_ptr->prop_data = port_wwn_data;
1958 	prop_ptr->prop_size = FC_WWN_SIZE;
1959 	pl_end->next = prop_ptr;
1960 	pl_end = prop_ptr;
1961 
1962 	/* consrtruct node WWN property. */
1963 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1964 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1965 		free_prop_list(&pl_start);
1966 		return (L_MALLOC_FAILED);
1967 	}
1968 	(void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP,
1969 	    strlen(NODE_WWN_PROP));
1970 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
1971 
1972 	if ((node_wwn_data = (uchar_t *)calloc(
1973 	    1, FC_WWN_SIZE)) == NULL) {
1974 		free_prop_list(&pl_start);
1975 		return (L_MALLOC_FAILED);
1976 	}
1977 	memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE);
1978 	prop_ptr->prop_data = node_wwn_data;
1979 	prop_ptr->prop_size = FC_WWN_SIZE;
1980 	pl_end->next = prop_ptr;
1981 	pl_end = prop_ptr;
1982 
1983 	/* consrtruct hard addr property. */
1984 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1985 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
1986 		free_prop_list(&pl_start);
1987 		return (L_MALLOC_FAILED);
1988 	}
1989 	(void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP,
1990 	    strlen(HARD_ADDR_PROP));
1991 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
1992 
1993 	if ((hard_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
1994 		free_prop_list(&pl_start);
1995 		return (L_MALLOC_FAILED);
1996 	}
1997 	*hard_addr_data = hard_addr;
1998 	prop_ptr->prop_data = hard_addr_data;
1999 	pl_end->next = prop_ptr;
2000 	pl_end = prop_ptr;
2001 
2002 	if (*prop_list == NULL) {
2003 		*prop_list = pl_start;
2004 	} else {
2005 		pl_end->next = (*prop_list)->next;
2006 		*prop_list = pl_start;
2007 	}
2008 
2009 	return (0);
2010 }
2011 
2012 /*
2013  * This function consturct FCP inq dtype propery.
2014  * if inq_dtype is null the property is constrcted with err info.
2015  *
2016  * L_MALLOC_FAILED is the only possible error.
2017  */
2018 static int
update_map_dev_FCP_prop(impl_map_dev_prop_t ** prop_list,uchar_t * inq_dtype,int err,int exist)2019 update_map_dev_FCP_prop(impl_map_dev_prop_t **prop_list,
2020     uchar_t *inq_dtype, int err, int exist)
2021 {
2022 	impl_map_dev_prop_t	*prop_ptr, *old_prop_ptr;
2023 	uchar_t *inq_dtype_data;
2024 
2025 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
2026 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
2027 		return (L_MALLOC_FAILED);
2028 	}
2029 
2030 	(void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP,
2031 	    strlen(INQ_DTYPE_PROP));
2032 
2033 	if (inq_dtype == NULL) {
2034 		prop_ptr->prop_data = NULL;
2035 		prop_ptr->prop_error = err;
2036 	} else {
2037 		if ((inq_dtype_data = (uchar_t *)calloc(
2038 		    1, sizeof (uchar_t))) == NULL) {
2039 			free(prop_ptr);
2040 			return (L_MALLOC_FAILED);
2041 		}
2042 		memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t));
2043 		prop_ptr->prop_data = inq_dtype_data;
2044 		prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
2045 		prop_ptr->prop_size = sizeof (uchar_t);
2046 	}
2047 
2048 	if (*prop_list == NULL) {
2049 		*prop_list = prop_ptr;
2050 	} else {
2051 		if (exist == PROP_EXIST) {
2052 			prop_ptr->next = (*prop_list)->next;
2053 			old_prop_ptr = *prop_list;
2054 			*prop_list = prop_ptr;
2055 			free((uchar_t *)(old_prop_ptr->prop_data));
2056 			old_prop_ptr->prop_data = NULL;
2057 			S_FREE(old_prop_ptr);
2058 		} else {
2059 			prop_ptr->next = *prop_list;
2060 			*prop_list = prop_ptr;
2061 		}
2062 	}
2063 
2064 	return (0);
2065 }
2066 
2067 /*
2068  * This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl()
2069  * to get the inq_dtype of input device and calls update_map_dev_FCP_prop().
2070  * inq_dtype is set to NULL and pass error code if inq_dtype data is not
2071  * requried.
2072  *
2073  * return error from update_map_dev_FCP_prop().
2074  */
2075 static int
handle_map_dev_FCP_prop(minor_t fp_xport_minor,la_wwn_t port_wwn,impl_map_dev_prop_t ** prop_list)2076 handle_map_dev_FCP_prop(minor_t fp_xport_minor, la_wwn_t port_wwn,
2077     impl_map_dev_prop_t **prop_list)
2078 {
2079 	struct device_data	inq_data;
2080 	int			fcp_fd, err;
2081 	struct fcp_ioctl	fcp_data;
2082 	uchar_t			inq_dtype;
2083 
2084 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
2085 		update_map_dev_FCP_prop(prop_list, NULL,
2086 		    L_OPEN_PATH_FAIL, PROP_NOEXIST);
2087 	}
2088 
2089 	/* Get the minor number for an fp instance */
2090 	fcp_data.fp_minor = fp_xport_minor;
2091 
2092 	/* Get FCP prop for the hba first. */
2093 	fcp_data.listlen = 1;
2094 	inq_data.dev_pwwn = port_wwn;
2095 	fcp_data.list = (caddr_t)&inq_data;
2096 
2097 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
2098 		/* if ioctl error then set the prop_error.	*/
2099 		if ((err = update_map_dev_FCP_prop(
2100 		    prop_list, NULL, err, PROP_NOEXIST)) != 0) {
2101 			return (err);
2102 		}
2103 	} else {
2104 		inq_dtype = inq_data.dev0_type;
2105 		if ((err = update_map_dev_FCP_prop(
2106 		    prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) {
2107 			return (err);
2108 		}
2109 	}
2110 
2111 	return (0);
2112 }
2113 
2114 /*
2115  * Construct device map tree from nexus driver
2116  *
2117  * PARAMS:
2118  *	path -	must be the physical path to a device
2119  *	l_err  - ptr to an error code.  Set when NULL is returned.
2120  *	flag -  device map fomat and property type.
2121  *
2122  * LOGIC:
2123  *	1. check the validity of path via g_get_path_type.
2124  *	2. If FC path, get the topology of the path via
2125  *		g_get_fca_port_topology.
2126  *
2127  *	3. If FC type(Leadville statck)
2128  *		FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t.
2129  *		FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t.
2130  *
2131  *		root of tree is set with host_params info
2132  *			FC propery is set.
2133  *			FCP property is set if reqyested through flag.
2134  *				Issue g_issue_fcp_ioctl to get FCP inquiry data
2135  *		consruruct list of children via dev_list.
2136  *			FC property is set.
2137  *			FCP property is set if reqyested through flag.
2138  *				Issue FCIO_DEV_LOGIN if it is fabric device.
2139  *				Issue g_issue_fcp_ioctl to get FCP inquiry data.
2140  *
2141  *	   else FC4 type(socal/sf or ifp stack)
2142  *		SFIOCGMAP ioctl to get the device and hba nodes of
2143  *			sf_addr_pair_t.
2144  *		FCIO_GETMAP ioctl to get hba port info.
2145  *		consturct map and child tree list and
2146  *		set the properties as private loop devices.
2147  *
2148  * RETURNS:
2149  *	ptr to map is returned if OK.
2150  *	NULL and l_err is set otherwise.
2151  */
2152 gfc_dev_t
g_dev_map_init(char * path,int * l_err,int flag)2153 g_dev_map_init(char *path, int *l_err, int flag)
2154 {
2155 	int		fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0;
2156 	char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
2157 	char		*char_ptr, *nexus_path;
2158 	struct stat	stbuf;
2159 	fc_port_dev_t	*dev_list = NULL, *dlist;
2160 	uint32_t	hba_port_top, state;
2161 	uint_t		path_type;
2162 	sf_al_map_t	sf_map;
2163 	fc_port_dev_t	fp_hba_port;
2164 	mp_pathlist_t	pathlist;
2165 	int		p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd;
2166 	fcio_t		fcio;
2167 	struct lilpmap	limited_map;
2168 	impl_map_dev_t	*impl_map, *impl_dev;
2169 	impl_map_dev_t	*mdl_start = NULL, *mdl_end = NULL;
2170 	struct stat	sbuf;
2171 
2172 	if (l_err == NULL) {
2173 		return (NULL);
2174 	}
2175 
2176 	if (path == NULL) {
2177 		*l_err = L_INVALID_PATH;
2178 		return (NULL);
2179 	}
2180 
2181 	*l_err = 0;
2182 
2183 	(void) strcpy(drvr_path, path);
2184 	/*
2185 	 * Get the path to the :devctl driver
2186 	 *
2187 	 * This assumes the path looks something like this:
2188 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
2189 	 * or
2190 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
2191 	 * or
2192 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
2193 	 * or
2194 	 * a 1 level PCI type driver but still :devctl
2195 	 */
2196 	if (strstr(path, SCSI_VHCI)) {
2197 		(void) strcpy(drvr_path0, path);
2198 		if (g_get_pathlist(drvr_path0, &pathlist)) {
2199 			*l_err = L_INVALID_PATH;
2200 			return (NULL);
2201 		}
2202 		pathcnt = pathlist.path_count;
2203 		p_on = p_st = 0;
2204 		for (i = 0; i < pathcnt; i++) {
2205 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
2206 				if (pathlist.path_info[i].path_state ==
2207 				    MDI_PATHINFO_STATE_ONLINE) {
2208 					p_on = i;
2209 					break;
2210 				} else if (pathlist.path_info[i].path_state ==
2211 				    MDI_PATHINFO_STATE_STANDBY) {
2212 					p_st = i;
2213 				}
2214 			}
2215 		}
2216 		if (pathlist.path_info[p_on].path_state ==
2217 		    MDI_PATHINFO_STATE_ONLINE) {
2218 			/* on_line path */
2219 			(void) strcpy(drvr_path,
2220 			    pathlist.path_info[p_on].path_hba);
2221 		} else {
2222 			/* standby or path0 */
2223 			(void) strcpy(drvr_path,
2224 			    pathlist.path_info[p_st].path_hba);
2225 		}
2226 		free(pathlist.path_info);
2227 		(void) strcat(drvr_path, FC_CTLR);
2228 	} else {
2229 		(void) strcpy(drvr_path, path);
2230 		if (strstr(drvr_path, DRV_NAME_SSD) ||
2231 		    strstr(drvr_path, SES_NAME) ||
2232 		    strstr(drvr_path, DRV_NAME_ST)) {
2233 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
2234 				*l_err = L_INVALID_PATH;
2235 				return (NULL);
2236 			}
2237 			*char_ptr = '\0';   /* Terminate sting  */
2238 			/* append controller */
2239 			(void) strcat(drvr_path, FC_CTLR);
2240 		} else {
2241 			if (stat(drvr_path, &stbuf) < 0) {
2242 				*l_err = L_LSTAT_ERROR;
2243 				return (NULL);
2244 			}
2245 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
2246 				/* append controller */
2247 				(void) strcat(drvr_path, FC_CTLR);
2248 			}
2249 		}
2250 	}
2251 
2252 	P_DPRINTF("  g_dev_map_init: Geting drive map from:"
2253 	    " %s\n", drvr_path);
2254 
2255 	path_type = g_get_path_type(drvr_path);
2256 	if ((path_type == 0) || !(path_type & XPORT_MASK)) {
2257 		*l_err = L_INVALID_PATH_TYPE;
2258 		return (NULL);
2259 	}
2260 
2261 	/* get fiber topology */
2262 	if ((err = g_get_fca_port_topology(drvr_path,
2263 	    &hba_port_top, 0)) != 0) {
2264 		*l_err = err;
2265 		return (NULL);
2266 	}
2267 
2268 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) {
2269 		*l_err = errno;
2270 		return (NULL);
2271 	}
2272 
2273 	/* for FC devices. */
2274 	if (path_type & FC_FCA_MASK) {
2275 		/* get the number of device first. */
2276 		fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
2277 		fcio.fcio_olen = sizeof (num_devices);
2278 		fcio.fcio_xfer = FCIO_XFER_READ;
2279 		fcio.fcio_obuf = (caddr_t)&num_devices;
2280 		if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2281 			I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
2282 			(void) close(fd);
2283 			*l_err = L_FCIO_GET_NUM_DEVS_FAIL;
2284 			return (NULL);
2285 		}
2286 		if (num_devices != 0) {
2287 			if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
2288 			    sizeof (fc_port_dev_t))) == NULL) {
2289 				(void) close(fd);
2290 				*l_err = L_MALLOC_FAILED;
2291 				return (NULL);
2292 			}
2293 
2294 			bzero((caddr_t)&fcio, sizeof (fcio));
2295 			/* Get the device list */
2296 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2297 			/* Information read operation */
2298 			fcio.fcio_xfer = FCIO_XFER_READ;
2299 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
2300 			fcio.fcio_obuf = (caddr_t)dev_list;
2301 			/* new device count */
2302 			fcio.fcio_alen = sizeof (new_count);
2303 			fcio.fcio_abuf = (caddr_t)&new_count;
2304 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
2305 				if (err == L_INVALID_DEVICE_COUNT) {
2306 					/*
2307 					 * original buffer was small so allocate
2308 					 * buffer with a new count and retry.
2309 					 */
2310 					free(dev_list);
2311 					num_devices = new_count;
2312 					new_count = 0;
2313 					if ((dev_list = (fc_port_dev_t *)
2314 					    calloc(num_devices,
2315 					    sizeof (fc_port_dev_t))) == NULL) {
2316 						(void) close(fd);
2317 						*l_err = L_MALLOC_FAILED;
2318 						return (NULL);
2319 					}
2320 					fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2321 					/* Information read operation */
2322 					fcio.fcio_xfer = FCIO_XFER_READ;
2323 					fcio.fcio_obuf = (caddr_t)dev_list;
2324 					fcio.fcio_olen = num_devices *
2325 					    sizeof (fc_port_dev_t);
2326 					/* new device count */
2327 					fcio.fcio_alen = sizeof (new_count);
2328 					fcio.fcio_abuf = (caddr_t)&new_count;
2329 					if ((err = g_issue_fcio_ioctl(fd, &fcio,
2330 					    0)) != 0) {
2331 						if (err ==
2332 						    L_INVALID_DEVICE_COUNT) {
2333 							/*
2334 							 * No more retry. There
2335 							 * may be severe
2336 							 * hardware problem so
2337 							 * return error here.
2338 							 */
2339 							I_DPRINTF(" Device"
2340 							    " count was %d"
2341 							    " should have been"
2342 							    " %d\n",
2343 							    num_devices,
2344 							    new_count);
2345 							free(dev_list);
2346 							(void) close(fd);
2347 
2348 						*l_err = L_INVALID_DEVICE_COUNT;
2349 
2350 							return (NULL);
2351 						} else {
2352 
2353 				/* Code refactorization is needed for C style */
2354 				I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
2355 
2356 							free(dev_list);
2357 							(void) close(fd);
2358 
2359 					*l_err = L_FCIO_GET_DEV_LIST_FAIL;
2360 
2361 							return (NULL);
2362 						}
2363 					}
2364 				}
2365 			}
2366 		}
2367 
2368 		/*
2369 		 * if new count is smaller than the original number from
2370 		 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
2371 		 * and continue.
2372 		 */
2373 		if (new_count < num_devices) {
2374 			num_devices = new_count;
2375 			if (new_count > 0) {
2376 				if ((dev_list = (fc_port_dev_t *)
2377 				    realloc(dev_list,
2378 				    (new_count * sizeof (fc_port_dev_t))))
2379 				    == NULL) {
2380 					S_FREE(dev_list);
2381 					(void) close(fd);
2382 					*l_err = L_MALLOC_FAILED;
2383 					return (NULL);
2384 				}
2385 			}
2386 		}
2387 
2388 		/* get the host param info */
2389 		(void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev));
2390 		fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
2391 		fcio.fcio_xfer = FCIO_XFER_READ;
2392 		fcio.fcio_obuf = (caddr_t)&fp_hba_port;
2393 		fcio.fcio_olen = sizeof (fc_port_dev_t);
2394 
2395 		if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2396 			I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
2397 			(void) close(fd);
2398 			if (num_devices == 0) {
2399 				*l_err = L_NO_DEVICES_FOUND;
2400 			} else {
2401 				free(dev_list);
2402 				*l_err = L_FCIO_GET_HOST_PARAMS_FAIL;
2403 			}
2404 			(void) close(fd);
2405 			return (NULL);
2406 		}
2407 
2408 		/* If we want the lilp map then we need to do a little	*/
2409 		/* work here.  The lilp map contains the local hba in	*/
2410 		/* the dev_addr.  Once this has been added qsort the	*/
2411 		/* dev_addr array so it's in physical order.		*/
2412 		if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) {
2413 			/* First we need to allocate one additional	*/
2414 			/* device to the dev_addr structure, for the	*/
2415 			/* local hba					*/
2416 			if (num_devices > 0) {
2417 				if ((dev_list = (fc_port_dev_t *)
2418 				    realloc(dev_list,
2419 				    (++num_devices *
2420 				    sizeof (fc_port_dev_t)))) == NULL) {
2421 					(void) close(fd);
2422 					/*
2423 					 * In case dev_list is not null free
2424 					 * it.
2425 					 */
2426 					S_FREE(dev_list);
2427 					*l_err =  L_MALLOC_FAILED;
2428 					return (NULL);
2429 				}
2430 
2431 				/*
2432 				 * Next, copy the local hba into this new
2433 				 * loc.
2434 				 */
2435 				if (memcpy(dev_list+(num_devices-1),
2436 				    &fp_hba_port,
2437 				    sizeof (fc_port_dev_t)) == NULL) {
2438 					(void) free(dev_list);
2439 					(void) close(fd);
2440 					*l_err =  L_MEMCPY_FAILED;
2441 					return (NULL);
2442 				}
2443 
2444 				/* Now sort by physical location */
2445 				qsort((void*)dev_list, num_devices,
2446 				    sizeof (fc_port_dev_t), lilp_map_cmp);
2447 			}
2448 		}
2449 
2450 
2451 		/* We have dev list info and host param info.	*/
2452 		/* Now constructs map tree with these info.	*/
2453 		/* First consturct the root of the map tree	*/
2454 		/* with host param.				*/
2455 		if ((impl_map = (impl_map_dev_t *)calloc(
2456 		    1, sizeof (impl_map_dev_t))) == NULL) {
2457 			(void) free(dev_list);
2458 			(void) close(fd);
2459 			*l_err = L_MALLOC_FAILED;
2460 			return (NULL);
2461 		}
2462 		impl_map->flag = flag;
2463 		impl_map->topo = hba_port_top;
2464 
2465 		/* consturct hba property list.	*/
2466 		if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2467 		    hba_port_top, fp_hba_port.dev_pwwn.raw_wwn,
2468 		    fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id,
2469 		    fp_hba_port.dev_hard_addr.hard_addr)) != 0) {
2470 			(void) free(dev_list);
2471 			(void) close(fd);
2472 			g_dev_map_fini(impl_map);
2473 			*l_err = err;
2474 			return (NULL);
2475 		}
2476 
2477 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2478 			if (fstat(fd, &sbuf) == -1) {
2479 				(void) free(dev_list);
2480 				(void) close(fd);
2481 				g_dev_map_fini(impl_map);
2482 				*l_err = L_FSTAT_ERROR;
2483 				return (NULL);
2484 			}
2485 			if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
2486 			    fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) {
2487 				(void) free(dev_list);
2488 				(void) close(fd);
2489 				g_dev_map_fini(impl_map);
2490 				*l_err = err;
2491 				return (NULL);
2492 			}
2493 		}
2494 
2495 		/* consturct child for each device and	*/
2496 		/* set device property list.		*/
2497 		dlist = dev_list;
2498 		for (i = 0; i < num_devices; i++, dlist++) {
2499 			if ((impl_dev = (impl_map_dev_t *)calloc(
2500 			    1, sizeof (impl_map_dev_t))) == NULL) {
2501 				(void) free(dev_list);
2502 				(void) close(fd);
2503 				g_dev_map_fini(impl_map);
2504 				*l_err = L_MALLOC_FAILED;
2505 				return (NULL);
2506 			}
2507 			/* set the map as parent */
2508 			impl_dev->parent = impl_map;
2509 			if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2510 			    hba_port_top, dlist->dev_pwwn.raw_wwn,
2511 			    dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id,
2512 			    dlist->dev_hard_addr.hard_addr)) != 0) {
2513 				(void) free(dev_list);
2514 				(void) close(fd);
2515 				g_dev_map_fini(impl_map);
2516 				*l_err = err;
2517 				return (NULL);
2518 			}
2519 			if (i == 0) {
2520 				mdl_start = mdl_end = impl_dev;
2521 			} else {
2522 				mdl_end->next = impl_dev;
2523 				mdl_end = impl_dev;
2524 			}
2525 			if ((flag & MAP_XPORT_PROP_ONLY) !=
2526 			    MAP_XPORT_PROP_ONLY) {
2527 			if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
2528 			    (hba_port_top == FC_TOP_FABRIC)) &&
2529 			    (memcmp(fp_hba_port.dev_pwwn.raw_wwn,
2530 			    dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) {
2531 				(void) memset(&fcio, 0, sizeof (fcio_t));
2532 				fcio.fcio_cmd = FCIO_GET_STATE;
2533 				fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
2534 				fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
2535 				fcio.fcio_xfer = FCIO_XFER_READ |
2536 				    FCIO_XFER_WRITE;
2537 				fcio.fcio_olen = sizeof (uint32_t);
2538 				fcio.fcio_obuf = (caddr_t)&state;
2539 				fcio.fcio_alen = 0;
2540 				fcio.fcio_abuf = NULL;
2541 				if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2542 					I_DPRINTF(
2543 					    " FCIO_GET_STATE ioctl failed.\n");
2544 					if ((err = update_map_dev_FCP_prop(
2545 					    &impl_dev->prop_list, NULL,
2546 					    L_FCIO_GET_STATE_FAIL,
2547 					    PROP_NOEXIST)) != 0) {
2548 						(void) free(dev_list);
2549 						(void) close(fd);
2550 						g_dev_map_fini(impl_map);
2551 						*l_err = err;
2552 						return (NULL);
2553 					}
2554 				}
2555 				if (state != PORT_DEVICE_LOGGED_IN) {
2556 					(void) close(fd);
2557 					if ((fd = g_object_open(drvr_path,
2558 					    O_NDELAY | O_RDONLY | O_EXCL)) ==
2559 					    -1) {
2560 						(void) free(dev_list);
2561 						g_dev_map_fini(impl_map);
2562 						*l_err = L_OPEN_PATH_FAIL;
2563 						return (NULL);
2564 					}
2565 					(void) memset(&fcio, 0,
2566 					    sizeof (fcio_t));
2567 					fcio.fcio_cmd = FCIO_DEV_LOGIN;
2568 					fcio.fcio_ilen =
2569 					    sizeof (dlist->dev_pwwn);
2570 					fcio.fcio_ibuf =
2571 					    (caddr_t)&dlist->dev_pwwn;
2572 					fcio.fcio_xfer = FCIO_XFER_WRITE;
2573 					fcio.fcio_olen = fcio.fcio_alen = 0;
2574 					fcio.fcio_obuf = fcio.fcio_abuf = NULL;
2575 					if (g_issue_fcio_ioctl(fd, &fcio, 0) !=
2576 					    0) {
2577 
2578 				/* Code refactorization is needed for C style */
2579 				I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
2580 
2581 				if ((err = update_map_dev_FCP_prop(
2582 				    &impl_dev->prop_list, NULL,
2583 				    L_FCIO_DEV_LOGIN_FAIL,
2584 				    PROP_NOEXIST)) != 0) {
2585 					(void) free(dev_list);
2586 					(void) close(fd);
2587 					g_dev_map_fini(impl_map);
2588 					*l_err = err;
2589 					return (NULL);
2590 				}
2591 
2592 							/*
2593 							 * plogi failed continue
2594 							 * to next dev
2595 							 */
2596 							continue;
2597 						}
2598 					}
2599 				}
2600 				/* sbuf should be set from hba_port handling. */
2601 				if ((err = handle_map_dev_FCP_prop(
2602 				    minor(sbuf.st_rdev),
2603 				    dlist->dev_pwwn, &impl_dev->prop_list)) !=
2604 				    0) {
2605 					(void) free(dev_list);
2606 					(void) close(fd);
2607 					g_dev_map_fini(impl_map);
2608 					*l_err = err;
2609 					return (NULL);
2610 				}
2611 			}
2612 		}
2613 		/* connect the children to to map.	*/
2614 		impl_map->child = mdl_start;
2615 		S_FREE(dev_list);
2616 
2617 	} else {	/* sf and fc4/pci devices */
2618 		/* initialize map */
2619 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
2620 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
2621 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
2622 			(void) close(fd);
2623 			*l_err = L_SFIOCGMAP_IOCTL_FAIL;
2624 			return (NULL);
2625 		}
2626 		/* Check for reasonableness. */
2627 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
2628 			(void) close(fd);
2629 			*l_err = L_INVALID_LOOP_MAP;
2630 			return (NULL);
2631 		}
2632 
2633 		if (sf_map.sf_count == 0) {
2634 			(void) close(fd);
2635 			*l_err = L_NO_DEVICES_FOUND;
2636 			return (NULL);
2637 		}
2638 
2639 		if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) {
2640 			(void) close(fd);
2641 			*l_err = err;
2642 			return (NULL);
2643 		}
2644 
2645 		if ((nexus_fd =
2646 		    g_object_open(nexus_path, O_NDELAY | O_RDONLY)) == -1) {
2647 			(void) close(fd);
2648 			S_FREE(nexus_path);
2649 			*l_err = errno;
2650 			return (NULL);
2651 		}
2652 
2653 		/* get limited map to get hba param info */
2654 		if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) {
2655 			I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
2656 			(void) close(fd);
2657 			(void) close(nexus_fd);
2658 			S_FREE(nexus_path);
2659 			*l_err = L_FCIO_GETMAP_IOCTL_FAIL;
2660 			return (NULL);
2661 		}
2662 		(void) close(nexus_fd);
2663 		S_FREE(nexus_path);
2664 
2665 		for (i = 0; i < sf_map.sf_count; i++) {
2666 			if (sf_map.sf_addr_pair[i].sf_al_pa ==
2667 			    limited_map.lilp_myalpa) {
2668 				sf_map.sf_hba_addr = sf_map.sf_addr_pair[i];
2669 				hba_alpa_found = 1;
2670 			}
2671 		}
2672 
2673 		if (!(hba_alpa_found)) {
2674 			(void) close(fd);
2675 			*l_err = L_INVALID_LOOP_MAP;
2676 			return (NULL);
2677 		}
2678 
2679 		/* We have dev list info and host param info.	*/
2680 		/* Now constructs map tree with these info.	*/
2681 		/* First consturct the root of the map tree	*/
2682 		/* with host param.				*/
2683 		if ((impl_map = (impl_map_dev_t *)calloc(
2684 		    1, sizeof (impl_map_dev_t))) == NULL) {
2685 			(void) close(fd);
2686 			*l_err = L_MALLOC_FAILED;
2687 			return (NULL);
2688 		}
2689 		impl_map->flag = flag;
2690 		impl_map->topo = hba_port_top;
2691 
2692 		/* consturct hba property list.	*/
2693 		if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
2694 		    hba_port_top, sf_map.sf_hba_addr.sf_port_wwn,
2695 		    sf_map.sf_hba_addr.sf_node_wwn,
2696 		    (int)sf_map.sf_hba_addr.sf_al_pa,
2697 		    (int)sf_map.sf_hba_addr.sf_hard_address)) != 0) {
2698 			(void) close(fd);
2699 			g_dev_map_fini(impl_map);
2700 			*l_err = err;
2701 			return (NULL);
2702 		}
2703 
2704 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2705 			if ((err = update_map_dev_FCP_prop(&impl_map->prop_list,
2706 			    &sf_map.sf_hba_addr.sf_inq_dtype, 0,
2707 			    PROP_NOEXIST)) != 0) {
2708 				(void) close(fd);
2709 				g_dev_map_fini(impl_map);
2710 				*l_err = err;
2711 				return (NULL);
2712 			}
2713 		}
2714 
2715 		for (i = 0; i < sf_map.sf_count; i++) {
2716 			if ((impl_dev = (impl_map_dev_t *)calloc(
2717 			    1, sizeof (impl_map_dev_t))) == NULL) {
2718 				(void) close(fd);
2719 				g_dev_map_fini(impl_map);
2720 				*l_err = L_MALLOC_FAILED;
2721 				return (NULL);
2722 			}
2723 			/* set the map as parent */
2724 			impl_dev->parent = impl_map;
2725 			if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2726 			    hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn,
2727 			    sf_map.sf_addr_pair[i].sf_node_wwn,
2728 			    (int)(sf_map.sf_addr_pair[i].sf_al_pa),
2729 			    (int)(sf_map.sf_addr_pair[i].sf_hard_address))) !=
2730 			    0) {
2731 				(void) close(fd);
2732 				g_dev_map_fini(impl_map);
2733 				*l_err = err;
2734 				return (NULL);
2735 			}
2736 			if (i == 0) {
2737 				mdl_start = mdl_end = impl_dev;
2738 			} else {
2739 				mdl_end->next = impl_dev;
2740 				mdl_end = impl_dev;
2741 			}
2742 			if ((flag & MAP_XPORT_PROP_ONLY) !=
2743 			    MAP_XPORT_PROP_ONLY) {
2744 				if ((err = update_map_dev_FCP_prop(
2745 				    &impl_dev->prop_list,
2746 				    &sf_map.sf_addr_pair[i].sf_inq_dtype, 0,
2747 				    PROP_NOEXIST)) != 0) {
2748 					(void) close(fd);
2749 					g_dev_map_fini(impl_map);
2750 					*l_err = err;
2751 					return (NULL);
2752 				}
2753 			}
2754 		} /* end of for loop */
2755 
2756 		impl_map->child = mdl_start;
2757 	} /* end of else */
2758 
2759 	close(fd);
2760 	return ((gfc_dev_t)(impl_map));
2761 }
2762 
2763 /*
2764  * This function deallocates memory for propery list.
2765  */
2766 static void
free_prop_list(impl_map_dev_prop_t ** prop_list)2767 free_prop_list(impl_map_dev_prop_t **prop_list)
2768 {
2769 	impl_map_dev_prop_t *lp, *olp;
2770 
2771 	lp = *prop_list;
2772 	while (lp != NULL) {
2773 		switch (lp->prop_type) {
2774 		case GFC_PROP_TYPE_BYTES:
2775 			free((uchar_t *)(lp->prop_data));
2776 			break;
2777 		case GFC_PROP_TYPE_INT:
2778 			free((int *)(lp->prop_data));
2779 			break;
2780 		case GFC_PROP_TYPE_STRING:
2781 			free((char *)(lp->prop_data));
2782 			break;
2783 		default:
2784 			break;
2785 		}
2786 		lp->prop_data = NULL;
2787 		olp = lp;
2788 		lp = olp->next;
2789 		S_FREE(olp);
2790 	}
2791 
2792 	*prop_list = NULL;
2793 }
2794 
2795 /*
2796  * This function deallocates memory for children list.
2797  */
2798 static void
free_child_list(impl_map_dev_t ** dev_list)2799 free_child_list(impl_map_dev_t **dev_list)
2800 {
2801 	impl_map_dev_t *lp, *olp;
2802 
2803 	lp = *dev_list;
2804 	while (lp != NULL) {
2805 		free_prop_list(&lp->prop_list);
2806 		olp = lp;
2807 		lp = olp->next;
2808 		S_FREE(olp);
2809 	}
2810 
2811 	*dev_list = NULL;
2812 }
2813 
2814 /*
2815  * This function deallocates memory for the whole map.
2816  */
2817 void
g_dev_map_fini(gfc_dev_t map)2818 g_dev_map_fini(gfc_dev_t map)
2819 {
2820 	impl_map_dev_t *impl_map;
2821 
2822 	impl_map = (impl_map_dev_t *)map;
2823 
2824 	if (impl_map != NULL) {
2825 		free_prop_list(&impl_map->prop_list);
2826 		free_child_list(&impl_map->child);
2827 		S_FREE(impl_map);
2828 	}
2829 }
2830 
2831 /*
2832  * This function passes back topology of the input map.
2833  * input should be a handle form g_dev_map_init().
2834  *
2835  * return 0 if OK.
2836  * return error code otherwise.
2837  */
2838 int
g_get_map_topology(gfc_dev_t map,uint_t * topology)2839 g_get_map_topology(gfc_dev_t map, uint_t *topology)
2840 {
2841 	impl_map_dev_t	*impl_map;
2842 
2843 	if (map == NULL) {
2844 		return (L_INVALID_MAP_DEV_ADDR);
2845 	}
2846 
2847 	if (topology == NULL) {
2848 		return (L_INVALID_ARG);
2849 	}
2850 
2851 	impl_map = (impl_map_dev_t *)map;
2852 
2853 	*topology = impl_map->topo;
2854 
2855 	return (0);
2856 }
2857 
2858 /*
2859  * This function returns the first device handle of the input map.
2860  * map input should be a handle form g_dev_map_init().
2861  *
2862  * l_err set to 0 if OK.
2863  * l_err set to error code otherwise.
2864  */
2865 gfc_dev_t
g_get_first_dev(gfc_dev_t map,int * l_err)2866 g_get_first_dev(gfc_dev_t map, int *l_err)
2867 {
2868 	impl_map_dev_t	*impl_map;
2869 
2870 	if (l_err == NULL) {
2871 		return (NULL);
2872 	}
2873 
2874 	*l_err = 0;
2875 
2876 	if (map == NULL) {
2877 		*l_err = L_INVALID_MAP_DEV_ADDR;
2878 		return (NULL);
2879 	}
2880 
2881 	impl_map = (impl_map_dev_t *)map;
2882 
2883 	if (impl_map->child == NULL) {
2884 		*l_err = L_NO_SUCH_DEV_FOUND;
2885 	}
2886 
2887 	return ((gfc_dev_t)(impl_map->child));
2888 }
2889 
2890 /*
2891  * This function returns the next device handle of the input map.
2892  * map_dev input should be a handle for device.
2893  *
2894  * l_err set to 0 if OK.
2895  * l_err set to error code otherwise.
2896  */
2897 gfc_dev_t
g_get_next_dev(gfc_dev_t map_dev,int * l_err)2898 g_get_next_dev(gfc_dev_t map_dev, int *l_err)
2899 {
2900 	impl_map_dev_t	*impl_dev;
2901 
2902 	if (l_err == NULL) {
2903 		return (NULL);
2904 	}
2905 
2906 	*l_err = 0;
2907 
2908 	if (map_dev == NULL) {
2909 		*l_err = L_INVALID_MAP_DEV_ADDR;
2910 		return (NULL);
2911 	}
2912 
2913 	impl_dev = (impl_map_dev_t *)map_dev;
2914 
2915 	if (impl_dev->next == NULL) {
2916 		*l_err = L_NO_SUCH_DEV_FOUND;
2917 	}
2918 
2919 	return ((gfc_dev_t)(impl_dev->next));
2920 }
2921 
2922 /*
2923  * This function passes back uchar_t type property and its count.
2924  * map_dev input should be a handle for device.
2925  *
2926  * return 0 if OK.
2927  * return error code otherwise.
2928  */
2929 int
g_dev_prop_lookup_bytes(gfc_dev_t map_dev,const char * prop_name,int * prop_data_count,uchar_t ** prop_data)2930 g_dev_prop_lookup_bytes(gfc_dev_t map_dev, const char *prop_name,
2931     int *prop_data_count, uchar_t **prop_data)
2932 {
2933 	impl_map_dev_t *impl_dev;
2934 	impl_map_dev_prop_t *impl_prop;
2935 	int err;
2936 
2937 	if (map_dev == NULL) {
2938 		return (L_INVALID_MAP_DEV_ADDR);
2939 	}
2940 
2941 	if ((prop_name == NULL) || (prop_data == NULL) ||
2942 	    (prop_data_count == NULL)) {
2943 		return (L_INVALID_ARG);
2944 	}
2945 
2946 	impl_dev = (impl_map_dev_t *)map_dev;
2947 	impl_prop = impl_dev->prop_list;
2948 
2949 	err = L_INVALID_MAP_DEV_PROP_NAME;
2950 
2951 	while (impl_prop) {
2952 		if (strncmp(impl_prop->prop_name, prop_name,
2953 		    strlen(prop_name)) == 0) {
2954 			if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
2955 				err = L_INVALID_MAP_DEV_PROP_TYPE;
2956 				break;
2957 			}
2958 			if (impl_prop->prop_data) {
2959 				*prop_data = (uchar_t *)(impl_prop->prop_data);
2960 				*prop_data_count = impl_prop->prop_size;
2961 				return (0);
2962 			} else {
2963 				err = impl_prop->prop_error;
2964 			}
2965 			break;
2966 		}
2967 		impl_prop = impl_prop->next;
2968 	}
2969 
2970 	return (err);
2971 }
2972 
2973 /*
2974  * This function passes back int type property.
2975  * map_dev input should be a handle for device.
2976  *
2977  * return 0 if OK.
2978  * return error code otherwise.
2979  */
2980 int
g_dev_prop_lookup_ints(gfc_dev_t map_dev,const char * prop_name,int ** prop_data)2981 g_dev_prop_lookup_ints(gfc_dev_t map_dev, const char *prop_name,
2982     int **prop_data)
2983 {
2984 	impl_map_dev_t *impl_dev;
2985 	impl_map_dev_prop_t *impl_prop;
2986 	int err;
2987 
2988 	if (map_dev == NULL) {
2989 		return (L_INVALID_MAP_DEV_ADDR);
2990 	}
2991 
2992 	if ((prop_name == NULL) || (prop_data == NULL)) {
2993 		return (L_INVALID_ARG);
2994 	}
2995 
2996 	impl_dev = (impl_map_dev_t *)map_dev;
2997 	impl_prop = impl_dev->prop_list;
2998 
2999 	err = L_INVALID_MAP_DEV_PROP_NAME;
3000 
3001 	while (impl_prop) {
3002 		if (strncmp(impl_prop->prop_name, prop_name,
3003 		    strlen(prop_name)) == 0) {
3004 			if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3005 			err = L_INVALID_MAP_DEV_PROP_TYPE;
3006 			break;
3007 			}
3008 			if (impl_prop->prop_data) {
3009 				*prop_data = (int *)(impl_prop->prop_data);
3010 				return (0);
3011 			} else {
3012 				err = impl_prop->prop_error;
3013 			}
3014 			break;
3015 		}
3016 		impl_prop = impl_prop->next;
3017 	}
3018 
3019 	return (err);
3020 }
3021 
3022 /*
3023  * This function passes back int type property.
3024  * map_dev input should be a handle for device.
3025  *
3026  * return 0 if OK.
3027  * return error code otherwise.
3028  */
3029 int
g_dev_prop_lookup_strings(gfc_dev_t map_dev,const char * prop_name,char ** prop_data)3030 g_dev_prop_lookup_strings(gfc_dev_t map_dev, const char *prop_name,
3031     char **prop_data)
3032 {
3033 	impl_map_dev_t *impl_dev;
3034 	impl_map_dev_prop_t *impl_prop;
3035 	int err;
3036 
3037 	if (map_dev == NULL) {
3038 		return (L_INVALID_MAP_DEV_ADDR);
3039 	}
3040 
3041 	if ((prop_name == NULL) || (prop_data == NULL)) {
3042 		return (L_INVALID_ARG);
3043 	}
3044 
3045 	impl_dev = (impl_map_dev_t *)map_dev;
3046 	impl_prop = impl_dev->prop_list;
3047 
3048 	err = L_INVALID_MAP_DEV_PROP_NAME;
3049 
3050 	while (impl_prop) {
3051 		if (strncmp(impl_prop->prop_name, prop_name,
3052 		    strlen(prop_name)) == 0) {
3053 			if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3054 				err = L_INVALID_MAP_DEV_PROP_TYPE;
3055 				break;
3056 			}
3057 			if (impl_prop->prop_data) {
3058 				*prop_data = (char *)(impl_prop->prop_data);
3059 				return (0);
3060 			} else {
3061 				err = impl_prop->prop_error;
3062 			}
3063 			break;
3064 		}
3065 		impl_prop = impl_prop->next;
3066 	}
3067 
3068 	return (err);
3069 }
3070 
3071 /*
3072  * This function returns the handle for the first property of the input device.
3073  * map_dev input should be a handle form a device.
3074  *
3075  * l_err set to 0 if OK.
3076  * l_err set to error code otherwise.
3077  */
3078 gfc_prop_t
g_get_first_dev_prop(gfc_dev_t map_dev,int * l_err)3079 g_get_first_dev_prop(gfc_dev_t map_dev, int *l_err)
3080 {
3081 	impl_map_dev_t	*impl_dev;
3082 
3083 	if (l_err == NULL) {
3084 		return (NULL);
3085 	}
3086 
3087 	*l_err = 0;
3088 
3089 	if (map_dev == NULL) {
3090 		*l_err = L_INVALID_MAP_DEV_ADDR;
3091 		return (NULL);
3092 	}
3093 
3094 	impl_dev = (impl_map_dev_t *)map_dev;
3095 
3096 	if (impl_dev->prop_list == NULL) {
3097 		*l_err = L_NO_SUCH_PROP_FOUND;
3098 	}
3099 
3100 	return ((gfc_prop_t)(impl_dev->prop_list));
3101 }
3102 
3103 /*
3104  * This function returns the handle for next property handle of the input prop.
3105  * map_prop input should be a handle for property.
3106  *
3107  * l_err set to 0 if OK.
3108  * l_err set to error code otherwise.
3109  */
3110 gfc_prop_t
g_get_next_dev_prop(gfc_prop_t map_prop,int * l_err)3111 g_get_next_dev_prop(gfc_prop_t map_prop, int *l_err)
3112 {
3113 	impl_map_dev_prop_t	*impl_prop;
3114 
3115 	if (l_err == NULL) {
3116 		return (NULL);
3117 	}
3118 
3119 	*l_err = 0;
3120 
3121 	if (map_prop == NULL) {
3122 		*l_err = L_INVALID_MAP_DEV_PROP;
3123 		return (NULL);
3124 	}
3125 
3126 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3127 
3128 	if (impl_prop->next == NULL) {
3129 		*l_err = L_NO_SUCH_PROP_FOUND;
3130 	}
3131 
3132 	return ((gfc_prop_t)(impl_prop->next));
3133 }
3134 
3135 /*
3136  * This function returns the name of the property of the input prop.
3137  * map_prop input should be a handle for property.
3138  *
3139  * return name string if OK.
3140  * returns NULL and l_err set to error code otherwise.
3141  */
3142 char *
g_get_dev_prop_name(gfc_prop_t map_prop,int * l_err)3143 g_get_dev_prop_name(gfc_prop_t map_prop, int *l_err)
3144 {
3145 	impl_map_dev_prop_t	*impl_prop;
3146 
3147 	if (l_err == NULL) {
3148 		return (NULL);
3149 	}
3150 
3151 	*l_err = 0;
3152 
3153 	if (map_prop == NULL) {
3154 		*l_err = L_INVALID_MAP_DEV_PROP;
3155 		return (NULL);
3156 	}
3157 
3158 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3159 
3160 	return (impl_prop->prop_name);
3161 }
3162 
3163 /*
3164  * This function returns the type of the property of the input prop.
3165  * map_prop input should be a handle for property.
3166  *
3167  * return type if OK.
3168  * returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise.
3169  */
3170 int
g_get_dev_prop_type(gfc_prop_t map_prop,int * l_err)3171 g_get_dev_prop_type(gfc_prop_t map_prop, int *l_err)
3172 {
3173 	impl_map_dev_prop_t	*impl_prop;
3174 
3175 	if (l_err != NULL) {
3176 		*l_err = 0;
3177 	} else {
3178 		return (L_INVALID_ARG);
3179 	}
3180 
3181 	if (map_prop == NULL) {
3182 		*l_err = L_INVALID_MAP_DEV_PROP;
3183 		return (GFC_PROP_TYPE_UNKNOWN);
3184 	}
3185 
3186 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3187 
3188 	return (impl_prop->prop_type);
3189 }
3190 
3191 /*
3192  * This function passes back uchar_t type property and its count.
3193  * map_prop input should be a handle for property.
3194  *
3195  * return 0 if OK.
3196  * return error code otherwise.
3197  */
3198 int
g_get_dev_prop_bytes(gfc_prop_t map_prop,int * prop_data_count,uchar_t ** prop_data)3199 g_get_dev_prop_bytes(gfc_prop_t map_prop, int *prop_data_count,
3200     uchar_t **prop_data)
3201 {
3202 	impl_map_dev_prop_t *impl_prop;
3203 
3204 	if (map_prop == NULL) {
3205 		return (L_INVALID_MAP_DEV_ADDR);
3206 	}
3207 
3208 	if ((prop_data == NULL) || (prop_data_count == NULL)) {
3209 		return (L_INVALID_ARG);
3210 	}
3211 
3212 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3213 
3214 	if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
3215 		return (L_INVALID_MAP_DEV_PROP_TYPE);
3216 	}
3217 	if (impl_prop->prop_data) {
3218 		*prop_data = (uchar_t *)(impl_prop->prop_data);
3219 		*prop_data_count = impl_prop->prop_size;
3220 	} else {
3221 		return (impl_prop->prop_error);
3222 	}
3223 
3224 	return (0);
3225 }
3226 
3227 /*
3228  * This function passes back int type property.
3229  * map_prop input should be a handle for property.
3230  *
3231  * return 0 if OK.
3232  * return error code otherwise.
3233  */
3234 int
g_get_dev_prop_ints(gfc_prop_t map_prop,int ** prop_data)3235 g_get_dev_prop_ints(gfc_prop_t map_prop, int **prop_data)
3236 {
3237 	impl_map_dev_prop_t *impl_prop;
3238 
3239 	if (map_prop == NULL) {
3240 		return (L_INVALID_MAP_DEV_ADDR);
3241 	}
3242 
3243 	if (prop_data == NULL) {
3244 		return (L_INVALID_ARG);
3245 	}
3246 
3247 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3248 
3249 	if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3250 		return (L_INVALID_MAP_DEV_PROP_TYPE);
3251 	}
3252 	if (impl_prop->prop_data) {
3253 		*prop_data = (int *)(impl_prop->prop_data);
3254 	} else {
3255 		return (impl_prop->prop_error);
3256 	}
3257 
3258 	return (0);
3259 }
3260 
3261 /*
3262  * This function passes back string type property.
3263  * map_prop input should be a handle for property.
3264  *
3265  * return 0 if OK.
3266  * return error code otherwise.
3267  */
3268 int
g_get_dev_prop_strings(gfc_prop_t map_prop,char ** prop_data)3269 g_get_dev_prop_strings(gfc_prop_t map_prop, char **prop_data)
3270 {
3271 	impl_map_dev_prop_t *impl_prop;
3272 
3273 	if (map_prop == NULL) {
3274 		return (L_INVALID_MAP_DEV_ADDR);
3275 	}
3276 
3277 	if (prop_data == NULL) {
3278 		return (L_INVALID_ARG);
3279 	}
3280 
3281 	impl_prop = (impl_map_dev_prop_t *)map_prop;
3282 
3283 	if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3284 		return (L_INVALID_MAP_DEV_PROP_TYPE);
3285 	}
3286 	if (impl_prop->prop_data) {
3287 		*prop_data = (char *)(impl_prop->prop_data);
3288 	} else {
3289 		return (impl_prop->prop_error);
3290 	}
3291 
3292 	return (0);
3293 }
3294 
3295 /*
3296  * Free the linked list allocated by g_rdls()
3297  */
3298 static void
g_free_rls(AL_rls * rlsptr)3299 g_free_rls(AL_rls *rlsptr)
3300 {
3301 	AL_rls *trlsptr;
3302 
3303 	while (rlsptr != NULL) {
3304 		trlsptr = rlsptr->next;
3305 		free(rlsptr);
3306 		rlsptr = trlsptr;
3307 	}
3308 }
3309 
3310 /*
3311  * Read the extended link error status block
3312  * from the specified device and Host Adapter.
3313  *
3314  * PARAMS:
3315  *	path_phys - physical path to an FC device
3316  *	rls_ptr   - pointer to read link state structure
3317  *
3318  * RETURNS:
3319  *	0	: if OK
3320  *	non-zero: otherwise
3321  */
3322 int
g_rdls(char * path_phys,struct al_rls ** rls_ptr,int verbose)3323 g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose)
3324 {
3325 	char		nexus_path[MAXPATHLEN], *nexus_path_ptr;
3326 	int		fd, fp_fd, err, length, exp_map_flag = 0, *port_addr;
3327 	struct lilpmap	map;
3328 	AL_rls		*rls, *c1 = NULL, *c2 = NULL;
3329 	uchar_t		i, *port_wwn_byte;
3330 	la_wwn_t	port_wwn;
3331 	sf_al_map_t	exp_map;
3332 	char		*charPtr, fp_path[MAXPATHLEN];
3333 	uint_t		dev_type;
3334 	struct stat	stbuf;
3335 	fcio_t		fcio;
3336 	fc_portid_t	rls_req;
3337 	fc_rls_acc_t	rls_payload;
3338 	gfc_dev_t	map_root, map_dev;
3339 	uint32_t	hba_port_top, state;
3340 	int		pathcnt = 1, count;
3341 	mp_pathlist_t	pathlist;
3342 	int		p_on = 0, p_st = 0;
3343 
3344 	/* return invalid path if path_phys is NULL */
3345 	if (path_phys == NULL) {
3346 		return (L_INVALID_PATH);
3347 	}
3348 	/* return invalid arg if rls_ptr is NULL */
3349 	if (rls_ptr == NULL) {
3350 		return (L_INVALID_ARG);
3351 	}
3352 
3353 	*rls_ptr = rls = NULL;
3354 
3355 	if (strstr(path_phys, SCSI_VHCI) != NULL) {
3356 		(void) strcpy(fp_path, path_phys);
3357 		if (g_get_pathlist(fp_path, &pathlist)) {
3358 			return (L_INVALID_PATH);
3359 		}
3360 		pathcnt = pathlist.path_count;
3361 		p_on = p_st = 0;
3362 		for (i = 0; i < pathcnt; i++) {
3363 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
3364 				if (pathlist.path_info[i].path_state ==
3365 				    MDI_PATHINFO_STATE_ONLINE) {
3366 					p_on = i;
3367 					break;
3368 				} else if (pathlist.path_info[i].path_state ==
3369 				    MDI_PATHINFO_STATE_STANDBY) {
3370 					p_st = i;
3371 				}
3372 			}
3373 		}
3374 		if (pathlist.path_info[p_on].path_state ==
3375 		    MDI_PATHINFO_STATE_ONLINE) {
3376 			/* on_line path */
3377 			(void) strcpy(fp_path,
3378 			    pathlist.path_info[p_on].path_hba);
3379 		} else {
3380 			/* standby or path0 */
3381 			(void) strcpy(fp_path,
3382 			    pathlist.path_info[p_st].path_hba);
3383 		}
3384 		free(pathlist.path_info);
3385 	} else {
3386 		(void) strcpy(fp_path, path_phys);
3387 	}
3388 
3389 	/* Get map of devices on this loop. */
3390 	if ((dev_type = g_get_path_type(fp_path)) == 0) {
3391 		return (L_INVALID_PATH);
3392 	}
3393 	if (dev_type & FC_FCA_MASK) {
3394 		if (strstr(path_phys, SCSI_VHCI) != NULL) {
3395 			(void) strcat(fp_path, FC_CTLR);
3396 		} else if (strstr(fp_path, DRV_NAME_SSD) ||
3397 		    strstr(fp_path, DRV_NAME_ST) ||
3398 		    strstr(fp_path, SES_NAME)) {
3399 			if ((charPtr = strrchr(fp_path, '/')) == NULL) {
3400 				return (L_INVALID_PATH);
3401 			}
3402 			*charPtr = '\0';
3403 			/* append devctl to the path */
3404 			(void) strcat(fp_path, FC_CTLR);
3405 		} else {
3406 			if (stat(fp_path, &stbuf) < 0) {
3407 				return (L_LSTAT_ERROR);
3408 			}
3409 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
3410 				/* append devctl to the path */
3411 				(void) strcat(fp_path, FC_CTLR);
3412 			}
3413 		}
3414 
3415 		if ((map_root = g_dev_map_init(fp_path, &err,
3416 		    MAP_XPORT_PROP_ONLY)) == NULL) {
3417 			return (err);
3418 		}
3419 
3420 	} else { /* FC4_FCA_MASK type path */
3421 		(void) memset(&map, 0, sizeof (struct lilpmap));
3422 
3423 		if ((err = g_get_nexus_path(path_phys,
3424 		    &nexus_path_ptr)) != 0) {
3425 			return (err);
3426 		}
3427 		(void) strcpy(nexus_path, nexus_path_ptr);
3428 		g_destroy_data(nexus_path_ptr);
3429 
3430 		/* open driver */
3431 		if ((fd = g_object_open(nexus_path,
3432 		    O_NDELAY | O_RDONLY)) == -1)
3433 			return (errno);
3434 
3435 		/*
3436 		 * First try using the socal version of the map.
3437 		 * If that fails get the expanded vesion.
3438 		 */
3439 		if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
3440 			I_DPRINTF("  FCIO_GETMAP ioctl failed.\n");
3441 			if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) {
3442 				I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
3443 				(void) close(fd);
3444 				return (L_SFIOCGMAP_IOCTL_FAIL);
3445 			}
3446 			/* Check for reasonableness. */
3447 			if ((exp_map.sf_count > 126) ||
3448 			    (exp_map.sf_count < 0)) {
3449 				(void) close(fd);
3450 				return (L_INVALID_LOOP_MAP);
3451 			}
3452 			for (i = 0; i < exp_map.sf_count; i++) {
3453 				if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) {
3454 					(void) close(fd);
3455 					return (L_INVALID_LOOP_MAP);
3456 				}
3457 			}
3458 			length = exp_map.sf_count;
3459 			exp_map_flag++;
3460 		} else {
3461 			I_DPRINTF("  g_rdls:"
3462 			    " FCIO_GETMAP ioctl returned %d entries.\n",
3463 			    map.lilp_length);
3464 			/* Check for reasonableness. */
3465 			if (map.lilp_length > sizeof (map.lilp_list)) {
3466 				(void) close(fd);
3467 				return (L_FCIOGETMAP_INVLD_LEN);
3468 			}
3469 			length = map.lilp_length;
3470 		}
3471 		for (i = 0; i < length; i++) {
3472 			if ((c2 = (struct al_rls *)
3473 			    g_zalloc(sizeof (struct al_rls))) == NULL) {
3474 				close(fd);
3475 				return (L_MALLOC_FAILED);
3476 			}
3477 			if (rls == NULL) {
3478 				c1 = rls = c2;
3479 			} else {
3480 				for (c1 = rls; c1->next; c1 =  c1->next) {};
3481 				c1 = c1->next = c2;
3482 			}
3483 			(void) strcpy(c1->driver_path, nexus_path);
3484 			if (exp_map_flag) {
3485 				c1->payload.rls_portno = c1->al_ha =
3486 				    exp_map.sf_addr_pair[i].sf_al_pa;
3487 			} else {
3488 				c1->payload.rls_portno = c1->al_ha =
3489 				    map.lilp_list[i];
3490 			}
3491 			c1->payload.rls_linkfail =
3492 			    (uint_t)0xff000000; /* get LESB for this port */
3493 			I_DPRINTF("  g_rdls:"
3494 			    " al_pa 0x%x\n", c1->payload.rls_portno);
3495 
3496 			if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) {
3497 				/*
3498 				 * The ifp driver will return ENXIO when rls
3499 				 * is issued for same initiator on loop when
3500 				 * there is more than one on the loop.
3501 				 * Rather than completely fail, continue on.
3502 				 * Set values in the payload struct to -1 as
3503 				 * this is what socal is currently doing for
3504 				 * the case of same initiator rls.
3505 				 */
3506 				if ((dev_type & FC4_PCI_FCA) &&
3507 				    (errno == ENXIO)) {
3508 					c1->payload.rls_linkfail =
3509 					    c1->payload.rls_syncfail =
3510 					    c1->payload.rls_sigfail =
3511 					    c1->payload.rls_primitiverr =
3512 					    c1->payload.rls_invalidword =
3513 					    c1->payload.rls_invalidcrc =
3514 					    (uint_t)0xffffffff;
3515 				} else {
3516 					I_DPRINTF("  FCIO_LINKSTATUS ioctl"
3517 					    " failed with errno %d.\n", errno);
3518 					g_free_rls(rls);
3519 					(void) close(fd);
3520 					return (L_FCIO_LINKSTATUS_FAILED);
3521 				}
3522 			}
3523 			I_DPRINTF("  g_rdls: al_pa returned by ioctl 0x%x\n",
3524 			    c1->payload.rls_portno);
3525 		}
3526 		*rls_ptr = rls; /* Pass back pointer */
3527 
3528 		(void) close(fd);
3529 		return (0);
3530 	}
3531 
3532 	/* Now we need to take care of FC_FCA_MASK case.	*/
3533 	/* we have map created already via g_dev_map_init.	*/
3534 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
3535 		g_dev_map_fini(map_root);
3536 		return (err);
3537 	}
3538 
3539 	if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
3540 		g_dev_map_fini(map_root);
3541 		if (err != L_NO_SUCH_DEV_FOUND) {
3542 			return (err);
3543 		} else {
3544 			return (L_NO_DEVICES_FOUND);
3545 		}
3546 	}
3547 
3548 	while (map_dev) {
3549 		if ((err = g_dev_prop_lookup_ints(
3550 		    map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3551 			g_dev_map_fini(map_root);
3552 			g_free_rls(rls);
3553 			return (err);
3554 		}
3555 
3556 		if ((c2 = (struct al_rls *)
3557 		    g_zalloc(sizeof (struct al_rls))) == NULL) {
3558 			g_dev_map_fini(map_root);
3559 			g_free_rls(rls);
3560 			close(fd);
3561 			return (L_MALLOC_FAILED);
3562 		}
3563 		if (rls == NULL) {
3564 			c1 = rls = c2;
3565 		} else {
3566 			for (c1 = rls; c1->next; c1 =  c1->next) {};
3567 			c1 = c1->next = c2;
3568 		}
3569 		/* Set the al_ha here */
3570 		c1->al_ha = rls_req.port_id = *port_addr;
3571 
3572 		/*
3573 		 * fp uses different input/output structures for
3574 		 * rls. Load the values returned for the fp ioctl
3575 		 * into the structure passed back to the caller
3576 		 * Note: There is no reason for the path
3577 		 * to be loaded into AL_rls as is done for socal/ifp
3578 		 * above.
3579 		 */
3580 		if ((hba_port_top == FC_TOP_FABRIC) ||
3581 		    (hba_port_top == FC_TOP_PUBLIC_LOOP)) {
3582 			if ((err = g_dev_prop_lookup_bytes(
3583 			    map_dev, PORT_WWN_PROP, &count,
3584 			    &port_wwn_byte)) != 0) {
3585 				g_dev_map_fini(map_root);
3586 				g_free_rls(rls);
3587 				return (err);
3588 			}
3589 			memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE);
3590 			if ((err = g_get_dev_port_state(
3591 			    fp_path, port_wwn, &state)) == 0) {
3592 				if (state != PORT_DEVICE_LOGGED_IN) {
3593 					if ((err = g_dev_login(fp_path,
3594 					    port_wwn)) != 0) {
3595 
3596 					c1->payload.rls_linkfail =
3597 					    c1->payload.rls_syncfail =
3598 					    c1->payload.rls_sigfail =
3599 					    c1->payload.rls_primitiverr =
3600 					    c1->payload.rls_invalidword =
3601 					    c1->payload.rls_invalidcrc =
3602 					    (uint_t)0xffffffff;
3603 						if (((map_dev =
3604 						    g_get_next_dev(map_dev,
3605 						    &err))
3606 						    == NULL) &&
3607 						    (err !=
3608 						    L_NO_SUCH_DEV_FOUND)) {
3609 							g_dev_map_fini(
3610 							    map_root);
3611 							g_free_rls(rls);
3612 							return (err);
3613 						}
3614 						continue;
3615 					}
3616 				}
3617 			} /* if g_get_dev_port_state fails proceed. */
3618 		}
3619 
3620 		fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3621 		if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3622 			g_dev_map_fini(map_root);
3623 			g_free_rls(rls);
3624 			return (L_OPEN_PATH_FAIL);
3625 		}
3626 		fcio.fcio_cmd = FCIO_LINK_STATUS;
3627 		fcio.fcio_ibuf = (caddr_t)&rls_req;
3628 		fcio.fcio_ilen = sizeof (rls_req);
3629 		fcio.fcio_xfer = FCIO_XFER_RW;
3630 		fcio.fcio_flags = 0;
3631 		fcio.fcio_obuf = (caddr_t)&rls_payload;
3632 		fcio.fcio_olen = sizeof (rls_payload);
3633 		if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3634 			c1->payload.rls_linkfail =
3635 			    c1->payload.rls_syncfail =
3636 			    c1->payload.rls_sigfail =
3637 			    c1->payload.rls_primitiverr =
3638 			    c1->payload.rls_invalidword =
3639 			    c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3640 		} else {
3641 			/*
3642 			 * Load the values into the struct passed
3643 			 * back to the caller
3644 			 */
3645 			c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3646 			c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3647 			c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3648 			c1->payload.rls_primitiverr =
3649 			    rls_payload.rls_prim_seq_err;
3650 			c1->payload.rls_invalidword =
3651 			    rls_payload.rls_invalid_word;
3652 			c1->payload.rls_invalidcrc =
3653 			    rls_payload.rls_invalid_crc;
3654 		}
3655 		(void) close(fp_fd);
3656 
3657 		if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3658 		    (err != L_NO_SUCH_DEV_FOUND)) {
3659 			g_dev_map_fini(map_root);
3660 			g_free_rls(rls);
3661 			return (err);
3662 		}
3663 	}
3664 
3665 	/* for Leadville issue a final call for the initiator */
3666 
3667 	if ((err = g_dev_prop_lookup_ints(
3668 	    map_root, PORT_ADDR_PROP, &port_addr)) != 0) {
3669 		g_dev_map_fini(map_root);
3670 		g_free_rls(rls);
3671 		return (err);
3672 	}
3673 
3674 	if ((c2 = (struct