xref: /onnv-gate/usr/src/lib/storage/libg_fc/common/map.c (revision 11547:c40173d8b5c4)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*11547SBill.Gumbrell@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM 
277836SJohn.Forte@Sun.COM /*LINTLIBRARY*/
287836SJohn.Forte@Sun.COM 
297836SJohn.Forte@Sun.COM /*
307836SJohn.Forte@Sun.COM  * I18N message number ranges
317836SJohn.Forte@Sun.COM  *  This file: 12000 - 12499
327836SJohn.Forte@Sun.COM  *  Shared common messages: 1 - 1999
337836SJohn.Forte@Sun.COM  */
347836SJohn.Forte@Sun.COM 
357836SJohn.Forte@Sun.COM /*
367836SJohn.Forte@Sun.COM  *	This module is part of the Fibre Channel Interface library.
377836SJohn.Forte@Sun.COM  */
387836SJohn.Forte@Sun.COM 
397836SJohn.Forte@Sun.COM /* #define		_POSIX_SOURCE 1 */
407836SJohn.Forte@Sun.COM 
417836SJohn.Forte@Sun.COM 
427836SJohn.Forte@Sun.COM /*	Includes	*/
437836SJohn.Forte@Sun.COM #include	<stdlib.h>
447836SJohn.Forte@Sun.COM #include	<stdio.h>
457836SJohn.Forte@Sun.COM #include	<sys/file.h>
467836SJohn.Forte@Sun.COM #include	<sys/types.h>
477836SJohn.Forte@Sun.COM #include	<sys/stat.h>
487836SJohn.Forte@Sun.COM #include	<sys/mkdev.h>
497836SJohn.Forte@Sun.COM #include	<sys/param.h>
507836SJohn.Forte@Sun.COM #include	<fcntl.h>
517836SJohn.Forte@Sun.COM #include	<unistd.h>
527836SJohn.Forte@Sun.COM #include	<string.h>
537836SJohn.Forte@Sun.COM #include	<sys/scsi/scsi.h>
547836SJohn.Forte@Sun.COM #include	<dirent.h>		/* for DIR */
557836SJohn.Forte@Sun.COM #include	<sys/vtoc.h>
567836SJohn.Forte@Sun.COM #include	<nl_types.h>
577836SJohn.Forte@Sun.COM #include	<strings.h>
587836SJohn.Forte@Sun.COM #include	<errno.h>
597836SJohn.Forte@Sun.COM #include	<sys/ddi.h>		/* for max */
607836SJohn.Forte@Sun.COM #include	<fnmatch.h>
617836SJohn.Forte@Sun.COM #include	<l_common.h>
627836SJohn.Forte@Sun.COM #include	<stgcom.h>
637836SJohn.Forte@Sun.COM #include	<l_error.h>
647836SJohn.Forte@Sun.COM #include	<g_state.h>
657836SJohn.Forte@Sun.COM #include	<g_scsi.h>
667836SJohn.Forte@Sun.COM #include	<sys/fibre-channel/ulp/fcp_util.h>
677836SJohn.Forte@Sun.COM #include	<sys/fibre-channel/impl/fc_error.h>
687836SJohn.Forte@Sun.COM #include	<sys/fibre-channel/impl/fcph.h>
697836SJohn.Forte@Sun.COM #include	<sys/socalio.h>
707836SJohn.Forte@Sun.COM #include	<libdevinfo.h>
717836SJohn.Forte@Sun.COM #include	<ctype.h>
727836SJohn.Forte@Sun.COM #include	<devid.h>
737836SJohn.Forte@Sun.COM 
747836SJohn.Forte@Sun.COM /* Some forward declarations of static functions */
757836SJohn.Forte@Sun.COM /*
767836SJohn.Forte@Sun.COM  * becomes extern interface for Tapestry.
777836SJohn.Forte@Sun.COM  * static int g_get_inq_dtype(char *, la_wwn_t, uchar_t *);
787836SJohn.Forte@Sun.COM  * static int g_get_dev_list(char *, fc_port_dev_t **, int *, int);
797836SJohn.Forte@Sun.COM  */
807836SJohn.Forte@Sun.COM static int	g_issue_fcp_ioctl(int, struct fcp_ioctl *, int);
817836SJohn.Forte@Sun.COM static int	g_set_port_state(char *, int);
827836SJohn.Forte@Sun.COM static int	g_dev_log_in_out(char *, la_wwn_t, uint16_t);
837836SJohn.Forte@Sun.COM static int	g_get_dev_port_state(char *, la_wwn_t, uint32_t *);
847836SJohn.Forte@Sun.COM static void	g_free_rls(AL_rls *);
857836SJohn.Forte@Sun.COM static int	g_scsi_inquiry_cmd80(int, uchar_t *, int);
867836SJohn.Forte@Sun.COM static int	get_fca_inq_dtype(char *, la_wwn_t, uchar_t *);
877836SJohn.Forte@Sun.COM static int	g_find_supported_inq_page(int, int);
887836SJohn.Forte@Sun.COM static int	wwn_list_name_compare(const void *, const void *);
897836SJohn.Forte@Sun.COM static int	devid_get_all(ddi_devid_t, di_node_t, char *,
907836SJohn.Forte@Sun.COM 			struct mplist_struct **);
917836SJohn.Forte@Sun.COM static int	get_multipath(char *, struct dlist **,
927836SJohn.Forte@Sun.COM 			struct wwn_list_struct *);
937836SJohn.Forte@Sun.COM static int	get_multipath_disk(char *, struct dlist **,
947836SJohn.Forte@Sun.COM 			struct wwn_list_struct *);
957836SJohn.Forte@Sun.COM static void	mplist_free(struct mplist_struct *);
967836SJohn.Forte@Sun.COM static int	get_wwn_data(di_node_t, uchar_t **, uchar_t **);
977836SJohn.Forte@Sun.COM static int	get_dev_path(struct wwn_list_struct **, char *, char *);
987836SJohn.Forte@Sun.COM static int	insert_missing_pwwn(char *, struct wwn_list_struct **);
997836SJohn.Forte@Sun.COM static int	get_scsi_vhci_port_wwn(char *, uchar_t *);
1007836SJohn.Forte@Sun.COM static int	search_wwn_entry(struct wwn_list_found_struct *, uchar_t *,
1017836SJohn.Forte@Sun.COM 		uchar_t *);
1027836SJohn.Forte@Sun.COM static int	add_wwn_entry(struct wwn_list_found_struct **, uchar_t *,
1037836SJohn.Forte@Sun.COM 		uchar_t *);
1047836SJohn.Forte@Sun.COM static int	string_to_wwn(uchar_t *, uchar_t *);
1057836SJohn.Forte@Sun.COM static int	get_wwns(char *, uchar_t *, uchar_t *, int *,
1067836SJohn.Forte@Sun.COM 		struct wwn_list_found_struct **);
1077836SJohn.Forte@Sun.COM 
1087836SJohn.Forte@Sun.COM /* type for g_dev_map_init related routines */
1097836SJohn.Forte@Sun.COM 
1107836SJohn.Forte@Sun.COM #define	S_FREE(x)	(((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
1117836SJohn.Forte@Sun.COM 
1127836SJohn.Forte@Sun.COM typedef struct impl_map_dev_prop {
1137836SJohn.Forte@Sun.COM 	char	prop_name[MAXNAMELEN];
1147836SJohn.Forte@Sun.COM 	int	prop_type;
1157836SJohn.Forte@Sun.COM 	int	prop_size;
1167836SJohn.Forte@Sun.COM 	void 	*prop_data;
1177836SJohn.Forte@Sun.COM 	int 	prop_error;
1187836SJohn.Forte@Sun.COM 	struct impl_map_dev_prop	*next;
1197836SJohn.Forte@Sun.COM } impl_map_dev_prop_t;
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM typedef struct impl_map_dev {
1227836SJohn.Forte@Sun.COM 	int			flag;
1237836SJohn.Forte@Sun.COM 	uint_t			topo;
1247836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t	*prop_list;
1257836SJohn.Forte@Sun.COM 	struct impl_map_dev	*parent;
1267836SJohn.Forte@Sun.COM 	struct impl_map_dev	*child;
1277836SJohn.Forte@Sun.COM 	struct impl_map_dev 	*next;
1287836SJohn.Forte@Sun.COM } impl_map_dev_t;
1297836SJohn.Forte@Sun.COM 
1307836SJohn.Forte@Sun.COM /*	Defines 	*/
1317836SJohn.Forte@Sun.COM #define	VERBPRINT	if (verbose) (void) printf
1327836SJohn.Forte@Sun.COM 
1337836SJohn.Forte@Sun.COM #define	DIR_MATCH_ST		"*[0-9+]n"
1347836SJohn.Forte@Sun.COM #define	DIR_MATCH_SSD		"*s2"
1357836SJohn.Forte@Sun.COM 
1367836SJohn.Forte@Sun.COM #define	PROP_NOEXIST		0
1377836SJohn.Forte@Sun.COM #define	PROP_EXIST		1
1387836SJohn.Forte@Sun.COM 
1397836SJohn.Forte@Sun.COM /*	Prototypes	*/
1407836SJohn.Forte@Sun.COM static int create_map(char *, gfc_map_t *, int, int);
1417836SJohn.Forte@Sun.COM static char ctoi(char);
1427836SJohn.Forte@Sun.COM static int	lilp_map_cmp(const void*, const void*);
1437836SJohn.Forte@Sun.COM static int	devices_get_all(di_node_t, char *, char *,
1447836SJohn.Forte@Sun.COM 			struct wwn_list_struct **);
1457836SJohn.Forte@Sun.COM static char	*my_devfs_path(di_node_t);
1467836SJohn.Forte@Sun.COM static void	my_devfs_path_free(char *path);
1477836SJohn.Forte@Sun.COM static void	copy_wwn_data_to_str(char *, const uchar_t *);
1487836SJohn.Forte@Sun.COM static void	init_drv(char *, char *, char *);
1497836SJohn.Forte@Sun.COM 
1507836SJohn.Forte@Sun.COM /* static for g_dev_map_init related routines */
1517836SJohn.Forte@Sun.COM 
1527836SJohn.Forte@Sun.COM static int update_map_dev_fc_prop(impl_map_dev_prop_t **, uint32_t,
1537836SJohn.Forte@Sun.COM 	uchar_t *, uchar_t *, int, int);
1547836SJohn.Forte@Sun.COM static int update_map_dev_FCP_prop(impl_map_dev_prop_t **, uchar_t *, int, int);
1557836SJohn.Forte@Sun.COM static int handle_map_dev_FCP_prop(minor_t, la_wwn_t, impl_map_dev_prop_t **);
1567836SJohn.Forte@Sun.COM static void free_prop_list(impl_map_dev_prop_t **);
1577836SJohn.Forte@Sun.COM static void free_child_list(impl_map_dev_t **);
1587836SJohn.Forte@Sun.COM static u_longlong_t wwnConversion(uchar_t *wwn);
1597836SJohn.Forte@Sun.COM 
1607836SJohn.Forte@Sun.COM uchar_t g_switch_to_alpa[] = {
1617836SJohn.Forte@Sun.COM 	0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
1627836SJohn.Forte@Sun.COM 	0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
1637836SJohn.Forte@Sun.COM 	0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
1647836SJohn.Forte@Sun.COM 	0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
1657836SJohn.Forte@Sun.COM 	0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
1667836SJohn.Forte@Sun.COM 	0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
1677836SJohn.Forte@Sun.COM 	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
1687836SJohn.Forte@Sun.COM 	0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
1697836SJohn.Forte@Sun.COM 	0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
1707836SJohn.Forte@Sun.COM 	0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
1717836SJohn.Forte@Sun.COM 	0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
1727836SJohn.Forte@Sun.COM 	0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
1737836SJohn.Forte@Sun.COM 	0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
1747836SJohn.Forte@Sun.COM };
1757836SJohn.Forte@Sun.COM 
1767836SJohn.Forte@Sun.COM uchar_t g_sf_alpa_to_switch[] = {
1777836SJohn.Forte@Sun.COM 	0x00, 0x7d, 0x7c, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00,
1787836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x78, 0x00, 0x00, 0x00,
1797836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x00, 0x77, 0x76, 0x00, 0x00, 0x75, 0x00, 0x74,
1807836SJohn.Forte@Sun.COM 	0x73, 0x72, 0x00, 0x00, 0x00, 0x71, 0x00, 0x70, 0x6f, 0x6e,
1817836SJohn.Forte@Sun.COM 	0x00, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x00, 0x00, 0x67,
1827836SJohn.Forte@Sun.COM 	0x66, 0x65, 0x64, 0x63, 0x62, 0x00, 0x00, 0x61, 0x60, 0x00,
1837836SJohn.Forte@Sun.COM 	0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x5d,
1847836SJohn.Forte@Sun.COM 	0x5c, 0x5b, 0x00, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x00,
1857836SJohn.Forte@Sun.COM 	0x00, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x00, 0x00, 0x4e,
1867836SJohn.Forte@Sun.COM 	0x4d, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b,
1877836SJohn.Forte@Sun.COM 	0x00, 0x4a, 0x49, 0x48, 0x00, 0x47, 0x46, 0x45, 0x44, 0x43,
1887836SJohn.Forte@Sun.COM 	0x42, 0x00, 0x00, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x00,
1897836SJohn.Forte@Sun.COM 	0x00, 0x3b, 0x3a, 0x00, 0x39, 0x00, 0x00, 0x00, 0x38, 0x37,
1907836SJohn.Forte@Sun.COM 	0x36, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
1917836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x00, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
1927836SJohn.Forte@Sun.COM 	0x00, 0x31, 0x30, 0x00, 0x00, 0x2f, 0x00, 0x2e, 0x2d, 0x2c,
1937836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x00, 0x2b, 0x00, 0x2a, 0x29, 0x28, 0x00, 0x27,
1947836SJohn.Forte@Sun.COM 	0x26, 0x25, 0x24, 0x23, 0x22, 0x00, 0x00, 0x21, 0x20, 0x1f,
1957836SJohn.Forte@Sun.COM 	0x1e, 0x1d, 0x1c, 0x00, 0x00, 0x1b, 0x1a, 0x00, 0x19, 0x00,
1967836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x17, 0x16, 0x15,
1977836SJohn.Forte@Sun.COM 	0x00, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x00, 0x00, 0x0e,
1987836SJohn.Forte@Sun.COM 	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x00, 0x00, 0x08, 0x07, 0x00,
1997836SJohn.Forte@Sun.COM 	0x06, 0x00, 0x00, 0x00, 0x05, 0x04, 0x03, 0x00, 0x02, 0x00,
2007836SJohn.Forte@Sun.COM 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
2017836SJohn.Forte@Sun.COM };
2027836SJohn.Forte@Sun.COM 
2037836SJohn.Forte@Sun.COM 
2047836SJohn.Forte@Sun.COM 
2057836SJohn.Forte@Sun.COM /*
2067836SJohn.Forte@Sun.COM  * Check if device is in the map.
2077836SJohn.Forte@Sun.COM  *
2087836SJohn.Forte@Sun.COM  * PARAMS:
2097836SJohn.Forte@Sun.COM  *	map - loop map returned from fc port
2107836SJohn.Forte@Sun.COM  *	tid - device ID for private map or 24-bit alpa for fabric map
2117836SJohn.Forte@Sun.COM  *
2127836SJohn.Forte@Sun.COM  * RETURNS:
2137836SJohn.Forte@Sun.COM  *	 1 if device present in the map.
2147836SJohn.Forte@Sun.COM  *	 0 otherwise.
2157836SJohn.Forte@Sun.COM  *
2167836SJohn.Forte@Sun.COM  */
2177836SJohn.Forte@Sun.COM int
g_device_in_map(gfc_map_t * map,int tid)2187836SJohn.Forte@Sun.COM g_device_in_map(gfc_map_t *map, int tid)
2197836SJohn.Forte@Sun.COM {
2207836SJohn.Forte@Sun.COM 	int i, j;
2217836SJohn.Forte@Sun.COM 	gfc_port_dev_info_t	*dev_ptr;
2227836SJohn.Forte@Sun.COM 
2237836SJohn.Forte@Sun.COM 	dev_ptr = map->dev_addr;
2247836SJohn.Forte@Sun.COM 	if ((map->hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) ||
225*11547SBill.Gumbrell@Sun.COM 	    (map->hba_addr.port_topology == FC_TOP_FABRIC)) {
2267836SJohn.Forte@Sun.COM 		for (i = 0; i < map->count; i++, dev_ptr++) {
2277836SJohn.Forte@Sun.COM 			if (dev_ptr->
228*11547SBill.Gumbrell@Sun.COM 			    gfc_port_dev.pub_port.dev_did.port_id == tid) {
2297836SJohn.Forte@Sun.COM 				/* Does not count if WWN == 0 */
2307836SJohn.Forte@Sun.COM 				for (j = 0; j < FC_WWN_SIZE; j++)
2317836SJohn.Forte@Sun.COM 					if (dev_ptr->gfc_port_dev.pub_port.
232*11547SBill.Gumbrell@Sun.COM 					    dev_pwwn.raw_wwn[j] != 0)
2337836SJohn.Forte@Sun.COM 						return (1);
2347836SJohn.Forte@Sun.COM 			}
2357836SJohn.Forte@Sun.COM 		}
2367836SJohn.Forte@Sun.COM 	} else {
2377836SJohn.Forte@Sun.COM 		for (i = 0; i < map->count; i++, dev_ptr++) {
2387836SJohn.Forte@Sun.COM 			if (dev_ptr->gfc_port_dev.priv_port.sf_al_pa ==
239*11547SBill.Gumbrell@Sun.COM 			    (int)g_switch_to_alpa[tid]) {
2407836SJohn.Forte@Sun.COM 				/* Does not count if WWN == 0 */
2417836SJohn.Forte@Sun.COM 				for (j = 0; j < WWN_SIZE; j++)
2427836SJohn.Forte@Sun.COM 					if (dev_ptr->gfc_port_dev.priv_port.
243*11547SBill.Gumbrell@Sun.COM 					    sf_port_wwn[j] != 0)
2447836SJohn.Forte@Sun.COM 						return (1);
2457836SJohn.Forte@Sun.COM 			}
2467836SJohn.Forte@Sun.COM 		}
2477836SJohn.Forte@Sun.COM 	}
2487836SJohn.Forte@Sun.COM 	return (0);
2497836SJohn.Forte@Sun.COM }
2507836SJohn.Forte@Sun.COM 
2517836SJohn.Forte@Sun.COM /*
2527836SJohn.Forte@Sun.COM  * Inserts any missing port wwns for mpxio device paths
2537836SJohn.Forte@Sun.COM  * which are in ONLINE or STANDBY state.
2547836SJohn.Forte@Sun.COM  */
2557836SJohn.Forte@Sun.COM static int
insert_missing_pwwn(char * phys_path,struct wwn_list_struct ** wwn_list_ptr)2567836SJohn.Forte@Sun.COM insert_missing_pwwn(char *phys_path, struct wwn_list_struct **wwn_list_ptr)
2577836SJohn.Forte@Sun.COM {
258*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
259*11547SBill.Gumbrell@Sun.COM 	int	i, pathcnt, match;
260*11547SBill.Gumbrell@Sun.COM 	struct	wwn_list_struct *new_wwn, *wwn_list_s, *wwn_list_found;
261*11547SBill.Gumbrell@Sun.COM 	char	pwwn1[WWN_S_LEN];
2627836SJohn.Forte@Sun.COM 
2637836SJohn.Forte@Sun.COM 	/*
2647836SJohn.Forte@Sun.COM 	 * Now check each scsi_vhci device path to find any missed
2657836SJohn.Forte@Sun.COM 	 * port wwns and insert a new wwn list entry for the missed
2667836SJohn.Forte@Sun.COM 	 * port wwn
2677836SJohn.Forte@Sun.COM 	 */
2687836SJohn.Forte@Sun.COM 	if (g_get_pathlist(phys_path, &pathlist)) {
2697836SJohn.Forte@Sun.COM 		/* Free memory for pathlist before return */
2707836SJohn.Forte@Sun.COM 		S_FREE(pathlist.path_info);
2717836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
2727836SJohn.Forte@Sun.COM 	}
2737836SJohn.Forte@Sun.COM 
2747836SJohn.Forte@Sun.COM 	pathcnt = pathlist.path_count;
2757836SJohn.Forte@Sun.COM 	for (i = 0; i < pathcnt; i++) {
2767836SJohn.Forte@Sun.COM 		/*
2777836SJohn.Forte@Sun.COM 		 * Just search for ONLINE and STANDBY paths as
2787836SJohn.Forte@Sun.COM 		 * those should be the only missing wwn entries.
2797836SJohn.Forte@Sun.COM 		 * There is a very small window for an offline
2807836SJohn.Forte@Sun.COM 		 * to have occurred between the time we retrieved
2817836SJohn.Forte@Sun.COM 		 * the device list and a call to this function.
2827836SJohn.Forte@Sun.COM 		 * If that happens, we just won't add it to
2837836SJohn.Forte@Sun.COM 		 * the list which is probably a good thing.
2847836SJohn.Forte@Sun.COM 		 */
2857836SJohn.Forte@Sun.COM 		if (pathlist.path_info[i].path_state ==
2867836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE ||
2877836SJohn.Forte@Sun.COM 		    pathlist.path_info[i].path_state ==
2887836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_STANDBY) {
2897836SJohn.Forte@Sun.COM 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
290*11547SBill.Gumbrell@Sun.COM 			    WWN_S_LEN - 1);
2917836SJohn.Forte@Sun.COM 			pwwn1[WWN_S_LEN - 1] = '\0';
2927836SJohn.Forte@Sun.COM 			/*
2937836SJohn.Forte@Sun.COM 			 * Now search through wwn list for matching
2947836SJohn.Forte@Sun.COM 			 * device path AND pwwn
2957836SJohn.Forte@Sun.COM 			 * If it's found, continue to next path.
2967836SJohn.Forte@Sun.COM 			 * If it's not found, add it the wwn list.
2977836SJohn.Forte@Sun.COM 			 */
2987836SJohn.Forte@Sun.COM 			match = 0;
2997836SJohn.Forte@Sun.COM 
3007836SJohn.Forte@Sun.COM 			for (wwn_list_s = *wwn_list_ptr; wwn_list_s != NULL;
3017836SJohn.Forte@Sun.COM 			    wwn_list_s = wwn_list_s->wwn_next) {
3027836SJohn.Forte@Sun.COM 				if (strncmp(phys_path,
303*11547SBill.Gumbrell@Sun.COM 				    wwn_list_s->physical_path,
304*11547SBill.Gumbrell@Sun.COM 				    strlen(phys_path)) == 0) {
3057836SJohn.Forte@Sun.COM 					wwn_list_found = wwn_list_s;
3067836SJohn.Forte@Sun.COM 					if (strncmp(pwwn1,
307*11547SBill.Gumbrell@Sun.COM 					    wwn_list_s->port_wwn_s,
308*11547SBill.Gumbrell@Sun.COM 					    WWN_S_LEN) == 0) {
3097836SJohn.Forte@Sun.COM 						match++;
3107836SJohn.Forte@Sun.COM 						break;
3117836SJohn.Forte@Sun.COM 					}
3127836SJohn.Forte@Sun.COM 				}
3137836SJohn.Forte@Sun.COM 			}
3147836SJohn.Forte@Sun.COM 			if (match) {
3157836SJohn.Forte@Sun.COM 				continue;
3167836SJohn.Forte@Sun.COM 			} else {
3177836SJohn.Forte@Sun.COM 				/*
3187836SJohn.Forte@Sun.COM 				 * didn't find a match but the mpxio
3197836SJohn.Forte@Sun.COM 				 * device is in the list. Retrieve
3207836SJohn.Forte@Sun.COM 				 * the info from the wwn_list_found
3217836SJohn.Forte@Sun.COM 				 * and add it to the list.
3227836SJohn.Forte@Sun.COM 				 */
3237836SJohn.Forte@Sun.COM 				if ((new_wwn = (struct  wwn_list_struct *)
324*11547SBill.Gumbrell@Sun.COM 				    calloc(1,
325*11547SBill.Gumbrell@Sun.COM 				    sizeof (struct  wwn_list_struct)))
326*11547SBill.Gumbrell@Sun.COM 				    == NULL) {
327*11547SBill.Gumbrell@Sun.COM 					S_FREE(pathlist.path_info);
328*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
3297836SJohn.Forte@Sun.COM 				}
3307836SJohn.Forte@Sun.COM 				if ((new_wwn->physical_path = (char *)
331*11547SBill.Gumbrell@Sun.COM 				    calloc(1,
332*11547SBill.Gumbrell@Sun.COM 				    strlen(wwn_list_found->physical_path)
333*11547SBill.Gumbrell@Sun.COM 				    + 1)) == NULL) {
334*11547SBill.Gumbrell@Sun.COM 					S_FREE(pathlist.path_info);
335*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
3367836SJohn.Forte@Sun.COM 				}
3377836SJohn.Forte@Sun.COM 				if ((new_wwn->logical_path = (char *)
338*11547SBill.Gumbrell@Sun.COM 				    calloc(1,
339*11547SBill.Gumbrell@Sun.COM 				    strlen(wwn_list_found->logical_path)
340*11547SBill.Gumbrell@Sun.COM 				    + 1)) == NULL) {
341*11547SBill.Gumbrell@Sun.COM 					S_FREE(pathlist.path_info);
342*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
3437836SJohn.Forte@Sun.COM 				}
3447836SJohn.Forte@Sun.COM 
3457836SJohn.Forte@Sun.COM 				/*
3467836SJohn.Forte@Sun.COM 				 * Insert new_wwn at the beginning of the list.
3477836SJohn.Forte@Sun.COM 				 */
3487836SJohn.Forte@Sun.COM 				new_wwn->wwn_next = *wwn_list_ptr;
3497836SJohn.Forte@Sun.COM 				(*wwn_list_ptr)->wwn_prev = new_wwn;
3507836SJohn.Forte@Sun.COM 
3517836SJohn.Forte@Sun.COM 				/* set new starting ptr */
3527836SJohn.Forte@Sun.COM 				*wwn_list_ptr = new_wwn;
3537836SJohn.Forte@Sun.COM 
3547836SJohn.Forte@Sun.COM 				memcpy(new_wwn->physical_path,
3557836SJohn.Forte@Sun.COM 				    wwn_list_found->physical_path,
356*11547SBill.Gumbrell@Sun.COM 				    strlen(wwn_list_found->physical_path));
3577836SJohn.Forte@Sun.COM 				memcpy(new_wwn->logical_path,
3587836SJohn.Forte@Sun.COM 				    wwn_list_found->logical_path,
359*11547SBill.Gumbrell@Sun.COM 				    strlen(wwn_list_found->logical_path));
3607836SJohn.Forte@Sun.COM 				/*
3617836SJohn.Forte@Sun.COM 				 * Copy found node wwn data to this new entry
3627836SJohn.Forte@Sun.COM 				 * Node wwn is required for the wwn_list
3637836SJohn.Forte@Sun.COM 				 * however for mpxio devices it is not
3647836SJohn.Forte@Sun.COM 				 * relevant as it may apply to multiple
3657836SJohn.Forte@Sun.COM 				 * target controllers, so just use what
3667836SJohn.Forte@Sun.COM 				 * we already have in wwn_list_found.
3677836SJohn.Forte@Sun.COM 				 */
3687836SJohn.Forte@Sun.COM 				memcpy(new_wwn->node_wwn_s,
3697836SJohn.Forte@Sun.COM 				    wwn_list_found->node_wwn_s, WWN_S_LEN);
3707836SJohn.Forte@Sun.COM 				memcpy(new_wwn->w_node_wwn,
3717836SJohn.Forte@Sun.COM 				    wwn_list_found->w_node_wwn, WWN_SIZE);
3727836SJohn.Forte@Sun.COM 				new_wwn->device_type =
3737836SJohn.Forte@Sun.COM 				    wwn_list_found->device_type;
3747836SJohn.Forte@Sun.COM 				memcpy(new_wwn->port_wwn_s, pwwn1, WWN_S_LEN);
3757836SJohn.Forte@Sun.COM 			}
3767836SJohn.Forte@Sun.COM 		}
3777836SJohn.Forte@Sun.COM 	}
3787836SJohn.Forte@Sun.COM 	S_FREE(pathlist.path_info);
3797836SJohn.Forte@Sun.COM 	return (0);
3807836SJohn.Forte@Sun.COM }
3817836SJohn.Forte@Sun.COM 
3827836SJohn.Forte@Sun.COM /*
3837836SJohn.Forte@Sun.COM  * gets the port wwn for a scsi_vhci device using ONLINE path priority
3847836SJohn.Forte@Sun.COM  */
3857836SJohn.Forte@Sun.COM static int
get_scsi_vhci_port_wwn(char * phys_path,uchar_t * port_wwn)3867836SJohn.Forte@Sun.COM get_scsi_vhci_port_wwn(char *phys_path, uchar_t *port_wwn)
3877836SJohn.Forte@Sun.COM {
388*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
389*11547SBill.Gumbrell@Sun.COM 	int	i, pathcnt, found;
390*11547SBill.Gumbrell@Sun.COM 	char	pwwn1[WWN_S_LEN];
3917836SJohn.Forte@Sun.COM 
3927836SJohn.Forte@Sun.COM 	if (g_get_pathlist(phys_path, &pathlist)) {
3937836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
3947836SJohn.Forte@Sun.COM 	}
3957836SJohn.Forte@Sun.COM 
3967836SJohn.Forte@Sun.COM 	found = 0;
3977836SJohn.Forte@Sun.COM 	pathcnt = pathlist.path_count;
3987836SJohn.Forte@Sun.COM 	/*
3997836SJohn.Forte@Sun.COM 	 * Look for an ONLINE path first.
4007836SJohn.Forte@Sun.COM 	 * If that fails, get the STANDBY path port WWN
4017836SJohn.Forte@Sun.COM 	 * If that fails, give up
4027836SJohn.Forte@Sun.COM 	 */
4037836SJohn.Forte@Sun.COM 	for (i = 0; found == 0 && i < pathcnt; i++) {
4047836SJohn.Forte@Sun.COM 		if (pathlist.path_info[i].path_state ==
4057836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
4067836SJohn.Forte@Sun.COM 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
407*11547SBill.Gumbrell@Sun.COM 			    WWN_S_LEN - 1);
4087836SJohn.Forte@Sun.COM 			pwwn1[WWN_S_LEN - 1] = '\0';
4097836SJohn.Forte@Sun.COM 			found++;
4107836SJohn.Forte@Sun.COM 		}
4117836SJohn.Forte@Sun.COM 	}
4127836SJohn.Forte@Sun.COM 
4137836SJohn.Forte@Sun.COM 	for (i = 0; found == 0 && i < pathcnt; i++) {
4147836SJohn.Forte@Sun.COM 		if (pathlist.path_info[i].path_state ==
4157836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_STANDBY) {
4167836SJohn.Forte@Sun.COM 			(void) strncpy(pwwn1, pathlist.path_info[i].path_addr,
417*11547SBill.Gumbrell@Sun.COM 			    WWN_S_LEN - 1);
4187836SJohn.Forte@Sun.COM 			pwwn1[WWN_S_LEN - 1] = '\0';
4197836SJohn.Forte@Sun.COM 			found++;
4207836SJohn.Forte@Sun.COM 		}
4217836SJohn.Forte@Sun.COM 	}
4227836SJohn.Forte@Sun.COM 
4237836SJohn.Forte@Sun.COM 	S_FREE(pathlist.path_info);
4247836SJohn.Forte@Sun.COM 	if (found) {
4257836SJohn.Forte@Sun.COM 		return (string_to_wwn((uchar_t *)pwwn1, port_wwn));
4267836SJohn.Forte@Sun.COM 	} else {
4277836SJohn.Forte@Sun.COM 		return (-1);
4287836SJohn.Forte@Sun.COM 	}
4297836SJohn.Forte@Sun.COM }
4307836SJohn.Forte@Sun.COM 
4317836SJohn.Forte@Sun.COM /*
4327836SJohn.Forte@Sun.COM  * searches wwn_list_found for the pwwn passed in
4337836SJohn.Forte@Sun.COM  * and sets the corresponding nwwn on return.
4347836SJohn.Forte@Sun.COM  * If no match is found, -1 is returned and nwwn is not set.
4357836SJohn.Forte@Sun.COM  */
4367836SJohn.Forte@Sun.COM static int
search_wwn_entry(struct wwn_list_found_struct * wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)4377836SJohn.Forte@Sun.COM search_wwn_entry(struct wwn_list_found_struct *wwn_list_found, uchar_t *pwwn,
438*11547SBill.Gumbrell@Sun.COM     uchar_t *nwwn)
4397836SJohn.Forte@Sun.COM {
440*11547SBill.Gumbrell@Sun.COM 	struct	wwn_list_found_struct *wwn_list_s;
4417836SJohn.Forte@Sun.COM 
4427836SJohn.Forte@Sun.COM 	for (wwn_list_s = wwn_list_found; wwn_list_s != NULL;
4437836SJohn.Forte@Sun.COM 	    wwn_list_s = wwn_list_s->wwn_next) {
444*11547SBill.Gumbrell@Sun.COM 		if (memcmp(pwwn, wwn_list_s->port_wwn, WWN_SIZE) == 0) {
4457836SJohn.Forte@Sun.COM 			memcpy(nwwn, wwn_list_s->node_wwn, WWN_SIZE);
4467836SJohn.Forte@Sun.COM 			return (0);
4477836SJohn.Forte@Sun.COM 		}
4487836SJohn.Forte@Sun.COM 	}
4497836SJohn.Forte@Sun.COM 	return (-1);
4507836SJohn.Forte@Sun.COM }
4517836SJohn.Forte@Sun.COM 
4527836SJohn.Forte@Sun.COM /*
4537836SJohn.Forte@Sun.COM  * adds a nwwn, pwwn entry to the next entry in wwn_list_found list
4547836SJohn.Forte@Sun.COM  */
4557836SJohn.Forte@Sun.COM static int
add_wwn_entry(struct wwn_list_found_struct ** wwn_list_found,uchar_t * pwwn,uchar_t * nwwn)4567836SJohn.Forte@Sun.COM add_wwn_entry(struct wwn_list_found_struct **wwn_list_found, uchar_t *pwwn,
457*11547SBill.Gumbrell@Sun.COM     uchar_t *nwwn)
4587836SJohn.Forte@Sun.COM {
459*11547SBill.Gumbrell@Sun.COM 	struct wwn_list_found_struct *new_wwn, *temp_wwn_list_found = NULL;
4607836SJohn.Forte@Sun.COM 
4617836SJohn.Forte@Sun.COM 	/* Got wwns, load data in list */
4627836SJohn.Forte@Sun.COM 	if ((new_wwn = (struct  wwn_list_found_struct *)
463*11547SBill.Gumbrell@Sun.COM 	    calloc(1, sizeof (struct  wwn_list_found_struct))) == NULL) {
4647836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
4657836SJohn.Forte@Sun.COM 	}
4667836SJohn.Forte@Sun.COM 
4677836SJohn.Forte@Sun.COM 	memcpy(new_wwn->node_wwn, nwwn, WWN_SIZE);
4687836SJohn.Forte@Sun.COM 	memcpy(new_wwn->port_wwn, pwwn, WWN_SIZE);
4697836SJohn.Forte@Sun.COM 
4707836SJohn.Forte@Sun.COM 	/*
4717836SJohn.Forte@Sun.COM 	 * Insert new_wwn in the list
4727836SJohn.Forte@Sun.COM 	 */
4737836SJohn.Forte@Sun.COM 	if (*wwn_list_found != NULL) {
4747836SJohn.Forte@Sun.COM 		temp_wwn_list_found = (*wwn_list_found)->wwn_next;
4757836SJohn.Forte@Sun.COM 		(*wwn_list_found)->wwn_next = new_wwn;
4767836SJohn.Forte@Sun.COM 	} else {
4777836SJohn.Forte@Sun.COM 		*wwn_list_found = new_wwn;
4787836SJohn.Forte@Sun.COM 	}
4797836SJohn.Forte@Sun.COM 	new_wwn->wwn_next = temp_wwn_list_found;
4807836SJohn.Forte@Sun.COM 
4817836SJohn.Forte@Sun.COM 	return (0);
4827836SJohn.Forte@Sun.COM }
4837836SJohn.Forte@Sun.COM 
4847836SJohn.Forte@Sun.COM 
4857836SJohn.Forte@Sun.COM /*
4867836SJohn.Forte@Sun.COM  * Create a linked list of all the WWN's for all FC_AL disks and
4877836SJohn.Forte@Sun.COM  * tapes that are attached to this host.
4887836SJohn.Forte@Sun.COM  *
4897836SJohn.Forte@Sun.COM  * RETURN VALUES: 0 O.K.
4907836SJohn.Forte@Sun.COM  *
4917836SJohn.Forte@Sun.COM  * wwn_list pointer:
4927836SJohn.Forte@Sun.COM  *			NULL: No devices found.
4937836SJohn.Forte@Sun.COM  *			!NULL: Devices found
4947836SJohn.Forte@Sun.COM  *                      wwn_list points to a linked list of wwn's.
4957836SJohn.Forte@Sun.COM  */
4967836SJohn.Forte@Sun.COM int
g_get_wwn_list(struct wwn_list_struct ** wwn_list_ptr,int verbose)4977836SJohn.Forte@Sun.COM g_get_wwn_list(struct wwn_list_struct **wwn_list_ptr, int verbose)
4987836SJohn.Forte@Sun.COM {
499*11547SBill.Gumbrell@Sun.COM 	struct wwn_list_struct *wwn_list_p = NULL, *wwn_list_tmp_p = NULL;
500*11547SBill.Gumbrell@Sun.COM 	struct wwn_list_found_struct *wwn_list_found = NULL;
501*11547SBill.Gumbrell@Sun.COM 	int err;
502*11547SBill.Gumbrell@Sun.COM 	int al_pa;
503*11547SBill.Gumbrell@Sun.COM 	uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
504*11547SBill.Gumbrell@Sun.COM 	hrtime_t	start_time, end_time;
505*11547SBill.Gumbrell@Sun.COM 	char *env = NULL;
5067836SJohn.Forte@Sun.COM 
5077836SJohn.Forte@Sun.COM 	/* return L_NULL_WWN_LIST if wwn_list_ptr is NULL */
5087836SJohn.Forte@Sun.COM 	if (wwn_list_ptr == NULL) {
5097836SJohn.Forte@Sun.COM 		return (L_NULL_WWN_LIST);
5107836SJohn.Forte@Sun.COM 	}
5117836SJohn.Forte@Sun.COM 
5127836SJohn.Forte@Sun.COM 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
5137836SJohn.Forte@Sun.COM 		start_time = gethrtime();
5147836SJohn.Forte@Sun.COM 	}
5157836SJohn.Forte@Sun.COM 
516*11547SBill.Gumbrell@Sun.COM 	if ((err = g_devices_get_all(wwn_list_ptr)) != 0) {
5177836SJohn.Forte@Sun.COM 		return (err);
5187836SJohn.Forte@Sun.COM 	}
5197836SJohn.Forte@Sun.COM 
5207836SJohn.Forte@Sun.COM 	/*
5217836SJohn.Forte@Sun.COM 	 * retain backward compatibility with g_get_wwn_list
5227836SJohn.Forte@Sun.COM 	 * and retrieve the WWN for scsi_vhci devices in the
5237836SJohn.Forte@Sun.COM 	 * same fashion
5247836SJohn.Forte@Sun.COM 	 * Note that for scsi_vhci devices, the wwn fields are
5257836SJohn.Forte@Sun.COM 	 * not relevant but in the previous versions
5267836SJohn.Forte@Sun.COM 	 * we loaded the wwns so...
5277836SJohn.Forte@Sun.COM 	 */
5287836SJohn.Forte@Sun.COM 	wwn_list_p = *wwn_list_ptr;
5297836SJohn.Forte@Sun.COM 	while (wwn_list_p != NULL) {
530*11547SBill.Gumbrell@Sun.COM 		if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
531*11547SBill.Gumbrell@Sun.COM 			/* get port wwn of first ONLINE, STANDBY */
532*11547SBill.Gumbrell@Sun.COM 			if ((get_scsi_vhci_port_wwn(wwn_list_p->physical_path,
533*11547SBill.Gumbrell@Sun.COM 			    port_wwn)) == 0) {
534*11547SBill.Gumbrell@Sun.COM 				if ((search_wwn_entry(wwn_list_found, port_wwn,
535*11547SBill.Gumbrell@Sun.COM 				    node_wwn)) != 0) {
536*11547SBill.Gumbrell@Sun.COM 					if ((err =
537*11547SBill.Gumbrell@Sun.COM 					    get_wwns(wwn_list_p->physical_path,
538*11547SBill.Gumbrell@Sun.COM 					    port_wwn,
539*11547SBill.Gumbrell@Sun.COM 					    node_wwn, &al_pa,
540*11547SBill.Gumbrell@Sun.COM 					    &wwn_list_found)) != 0) {
541*11547SBill.Gumbrell@Sun.COM 						g_free_wwn_list_found(
542*11547SBill.Gumbrell@Sun.COM 						    &wwn_list_found);
543*11547SBill.Gumbrell@Sun.COM 						return (err);
544*11547SBill.Gumbrell@Sun.COM 					}
545*11547SBill.Gumbrell@Sun.COM 				}
546*11547SBill.Gumbrell@Sun.COM 			} else {
547*11547SBill.Gumbrell@Sun.COM 				/* Use g_get_wwn as a last resort */
548*11547SBill.Gumbrell@Sun.COM 				if ((err = g_get_wwn(wwn_list_p->physical_path,
549*11547SBill.Gumbrell@Sun.COM 				    port_wwn, node_wwn, &al_pa, 0)) != 0) {
550*11547SBill.Gumbrell@Sun.COM 					/*
551*11547SBill.Gumbrell@Sun.COM 					 * this is a bad WWN.
552*11547SBill.Gumbrell@Sun.COM 					 * remove it from the wwn_list.
553*11547SBill.Gumbrell@Sun.COM 					 *
554*11547SBill.Gumbrell@Sun.COM 					 * After removing the bad WWN,
555*11547SBill.Gumbrell@Sun.COM 					 * wwn_list_p should point to the next
556*11547SBill.Gumbrell@Sun.COM 					 * node in the list.
557*11547SBill.Gumbrell@Sun.COM 					 */
558*11547SBill.Gumbrell@Sun.COM 					if ((wwn_list_p->wwn_prev == NULL) &&
559*11547SBill.Gumbrell@Sun.COM 					    (wwn_list_p->wwn_next == NULL)) {
560*11547SBill.Gumbrell@Sun.COM 						*wwn_list_ptr = NULL;
561*11547SBill.Gumbrell@Sun.COM 						free(wwn_list_p);
562*11547SBill.Gumbrell@Sun.COM 						g_free_wwn_list_found(
563*11547SBill.Gumbrell@Sun.COM 						    &wwn_list_found);
564*11547SBill.Gumbrell@Sun.COM 						return (L_NO_DEVICES_FOUND);
565*11547SBill.Gumbrell@Sun.COM 					} else if (
566*11547SBill.Gumbrell@Sun.COM 					    wwn_list_p->wwn_prev == NULL) {
567*11547SBill.Gumbrell@Sun.COM 						*wwn_list_ptr =
568*11547SBill.Gumbrell@Sun.COM 						    wwn_list_p->wwn_next;
569*11547SBill.Gumbrell@Sun.COM 						free(wwn_list_p);
570*11547SBill.Gumbrell@Sun.COM 						wwn_list_p = *wwn_list_ptr;
571*11547SBill.Gumbrell@Sun.COM 						wwn_list_p->wwn_prev = NULL;
572*11547SBill.Gumbrell@Sun.COM 					} else if (
573*11547SBill.Gumbrell@Sun.COM 					    wwn_list_p->wwn_next == NULL) {
574*11547SBill.Gumbrell@Sun.COM 						wwn_list_p->wwn_prev->wwn_next =
575*11547SBill.Gumbrell@Sun.COM 						    NULL;
576*11547SBill.Gumbrell@Sun.COM 						free(wwn_list_p);
577*11547SBill.Gumbrell@Sun.COM 						wwn_list_p = NULL;
578*11547SBill.Gumbrell@Sun.COM 					} else {
579*11547SBill.Gumbrell@Sun.COM 						wwn_list_tmp_p =
580*11547SBill.Gumbrell@Sun.COM 						    wwn_list_p->wwn_next;
581*11547SBill.Gumbrell@Sun.COM 						wwn_list_p->wwn_prev->wwn_next =
582*11547SBill.Gumbrell@Sun.COM 						    wwn_list_p->wwn_next;
583*11547SBill.Gumbrell@Sun.COM 						wwn_list_p->wwn_next->wwn_prev =
584*11547SBill.Gumbrell@Sun.COM 						    wwn_list_p->wwn_prev;
585*11547SBill.Gumbrell@Sun.COM 						free(wwn_list_p);
586*11547SBill.Gumbrell@Sun.COM 						wwn_list_p = wwn_list_tmp_p;
587*11547SBill.Gumbrell@Sun.COM 					}
588*11547SBill.Gumbrell@Sun.COM 					continue;
589*11547SBill.Gumbrell@Sun.COM 				}
5907836SJohn.Forte@Sun.COM 			}
591*11547SBill.Gumbrell@Sun.COM 			copy_wwn_data_to_str(wwn_list_p->node_wwn_s, node_wwn);
592*11547SBill.Gumbrell@Sun.COM 			copy_wwn_data_to_str(wwn_list_p->port_wwn_s, port_wwn);
593*11547SBill.Gumbrell@Sun.COM 			memcpy(wwn_list_p->w_node_wwn, node_wwn, WWN_SIZE);
5947836SJohn.Forte@Sun.COM 		}
595*11547SBill.Gumbrell@Sun.COM 		wwn_list_p = wwn_list_p->wwn_next;
5967836SJohn.Forte@Sun.COM 	}
5977836SJohn.Forte@Sun.COM 	g_free_wwn_list_found(&wwn_list_found);
5987836SJohn.Forte@Sun.COM 
5997836SJohn.Forte@Sun.COM 	/*
6007836SJohn.Forte@Sun.COM 	 * Now go through the list one more time to add entries for
6017836SJohn.Forte@Sun.COM 	 * any missing port wwns.
6027836SJohn.Forte@Sun.COM 	 * This allows a search on port wwn for any paths which are
6037836SJohn.Forte@Sun.COM 	 * ONLINE or STANDBY. We don't care about OFFLINE as those won't
6047836SJohn.Forte@Sun.COM 	 * and should not show up in the list
6057836SJohn.Forte@Sun.COM 	 */
6067836SJohn.Forte@Sun.COM 	for (wwn_list_p = *wwn_list_ptr; wwn_list_p != NULL;
6077836SJohn.Forte@Sun.COM 	    wwn_list_p = wwn_list_p->wwn_next) {
608*11547SBill.Gumbrell@Sun.COM 		if (strstr(wwn_list_p->physical_path, SCSI_VHCI) != NULL) {
609*11547SBill.Gumbrell@Sun.COM 			if ((err = insert_missing_pwwn(
610*11547SBill.Gumbrell@Sun.COM 			    wwn_list_p->physical_path, wwn_list_ptr)) != 0)
611*11547SBill.Gumbrell@Sun.COM 				return (err);
612*11547SBill.Gumbrell@Sun.COM 		}
6137836SJohn.Forte@Sun.COM 	}
6147836SJohn.Forte@Sun.COM 
6157836SJohn.Forte@Sun.COM 	if (env != NULL) {
6167836SJohn.Forte@Sun.COM 		end_time = gethrtime();
6177836SJohn.Forte@Sun.COM 		fprintf(stdout, "      g_get_wwn_list: "
618*11547SBill.Gumbrell@Sun.COM 		    "\t\tTime = %lld millisec\n",
619*11547SBill.Gumbrell@Sun.COM 		    (end_time - start_time)/1000000);
6207836SJohn.Forte@Sun.COM 	}
6217836SJohn.Forte@Sun.COM 	return (0);
6227836SJohn.Forte@Sun.COM 
6237836SJohn.Forte@Sun.COM }
6247836SJohn.Forte@Sun.COM 
6257836SJohn.Forte@Sun.COM int
g_devices_get_all(struct wwn_list_struct ** wwn_list_ptr)6267836SJohn.Forte@Sun.COM g_devices_get_all(struct wwn_list_struct **wwn_list_ptr)
6277836SJohn.Forte@Sun.COM {
628*11547SBill.Gumbrell@Sun.COM 	struct wwn_list_struct *tape_ptr = NULL;
629*11547SBill.Gumbrell@Sun.COM 	struct wwn_list_struct *tmp;
630*11547SBill.Gumbrell@Sun.COM 	int err;
631*11547SBill.Gumbrell@Sun.COM 	di_node_t root;
632*11547SBill.Gumbrell@Sun.COM 	hrtime_t	start_time, end_time;
633*11547SBill.Gumbrell@Sun.COM 	char *env = NULL;
6347836SJohn.Forte@Sun.COM 
6357836SJohn.Forte@Sun.COM 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
6367836SJohn.Forte@Sun.COM 		start_time = gethrtime();
6377836SJohn.Forte@Sun.COM 	}
6387836SJohn.Forte@Sun.COM 
6397836SJohn.Forte@Sun.COM 	/*
6407836SJohn.Forte@Sun.COM 	 * Try to prime di_drv_first_node()
6417836SJohn.Forte@Sun.COM 	 * If there are no nodes bound, di_drv_first_node()
6427836SJohn.Forte@Sun.COM 	 * will return nothing.
6437836SJohn.Forte@Sun.COM 	 */
6447836SJohn.Forte@Sun.COM 	init_drv(DEV_TAPE_DIR, DIR_MATCH_ST, SLSH_DRV_NAME_ST);
6457836SJohn.Forte@Sun.COM 	init_drv(DEV_RDIR, DIR_MATCH_SSD, SLSH_DRV_NAME_SSD);
6467836SJohn.Forte@Sun.COM 
6477836SJohn.Forte@Sun.COM 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
6487836SJohn.Forte@Sun.COM 		return (L_DEV_SNAPSHOT_FAILED);
6497836SJohn.Forte@Sun.COM 	}
6507836SJohn.Forte@Sun.COM 
6517836SJohn.Forte@Sun.COM 	if (env != NULL) {
6527836SJohn.Forte@Sun.COM 		end_time = gethrtime();
6537836SJohn.Forte@Sun.COM 		fprintf(stdout, "      di_init - /:  "
654*11547SBill.Gumbrell@Sun.COM 		    "\t\tTime = %lld millisec\n",
655*11547SBill.Gumbrell@Sun.COM 		    (end_time - start_time)/1000000);
6567836SJohn.Forte@Sun.COM 	}
6577836SJohn.Forte@Sun.COM 
6587836SJohn.Forte@Sun.COM 	if (env != NULL) {
6597836SJohn.Forte@Sun.COM 		start_time = gethrtime();
6607836SJohn.Forte@Sun.COM 	}
6617836SJohn.Forte@Sun.COM 
6627836SJohn.Forte@Sun.COM 	if ((err = devices_get_all(root, SSD_DRVR_NAME, SSD_MINOR_NAME,
663*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr)) != 0) {
6647836SJohn.Forte@Sun.COM 		if (err != L_NO_DEVICES_FOUND) {
6657836SJohn.Forte@Sun.COM 			di_fini(root);
6667836SJohn.Forte@Sun.COM 			g_free_wwn_list(&tape_ptr);
6677836SJohn.Forte@Sun.COM 			g_free_wwn_list(wwn_list_ptr);
6687836SJohn.Forte@Sun.COM 			return (err);
6697836SJohn.Forte@Sun.COM 		}
6707836SJohn.Forte@Sun.COM 	}
6717836SJohn.Forte@Sun.COM 
6727836SJohn.Forte@Sun.COM 	if (env != NULL) {
6737836SJohn.Forte@Sun.COM 		end_time = gethrtime();
6747836SJohn.Forte@Sun.COM 		fprintf(stdout, "      devices_get_all - ssd:  "
675*11547SBill.Gumbrell@Sun.COM 		    "\t\tTime = %lld millisec\n",
676*11547SBill.Gumbrell@Sun.COM 		    (end_time - start_time)/1000000);
6777836SJohn.Forte@Sun.COM 	}
6787836SJohn.Forte@Sun.COM 
6797836SJohn.Forte@Sun.COM 	if (env != NULL) {
6807836SJohn.Forte@Sun.COM 		start_time = gethrtime();
6817836SJohn.Forte@Sun.COM 	}
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM 	if ((err = devices_get_all(root, ST_DRVR_NAME, ST_MINOR_NAME,
684*11547SBill.Gumbrell@Sun.COM 	    &tape_ptr)) != 0) {
6857836SJohn.Forte@Sun.COM 		di_fini(root);
6867836SJohn.Forte@Sun.COM 		if (err != L_NO_DEVICES_FOUND) {
6877836SJohn.Forte@Sun.COM 			g_free_wwn_list(&tape_ptr);
6887836SJohn.Forte@Sun.COM 			g_free_wwn_list(wwn_list_ptr);
6897836SJohn.Forte@Sun.COM 			return (err);
6907836SJohn.Forte@Sun.COM 		} else {
6917836SJohn.Forte@Sun.COM 			/*
6927836SJohn.Forte@Sun.COM 			 * if *wwn_list_ptr == NULL
6937836SJohn.Forte@Sun.COM 			 * we have disks but no tapes
6947836SJohn.Forte@Sun.COM 			 * Just return
6957836SJohn.Forte@Sun.COM 			 */
6967836SJohn.Forte@Sun.COM 			if (*wwn_list_ptr != NULL) {
6977836SJohn.Forte@Sun.COM 				return (0);
6987836SJohn.Forte@Sun.COM 			} else {
6997836SJohn.Forte@Sun.COM 				/*
7007836SJohn.Forte@Sun.COM 				 * No disks or tapes
7017836SJohn.Forte@Sun.COM 				 */
7027836SJohn.Forte@Sun.COM 				g_free_wwn_list(&tape_ptr);
7037836SJohn.Forte@Sun.COM 				g_free_wwn_list(wwn_list_ptr);
7047836SJohn.Forte@Sun.COM 				return (err);
7057836SJohn.Forte@Sun.COM 			}
7067836SJohn.Forte@Sun.COM 		}
7077836SJohn.Forte@Sun.COM 	}
7087836SJohn.Forte@Sun.COM 
7097836SJohn.Forte@Sun.COM 	if (env != NULL) {
7107836SJohn.Forte@Sun.COM 		end_time = gethrtime();
7117836SJohn.Forte@Sun.COM 		fprintf(stdout, "      devices_get_all - st: "
712*11547SBill.Gumbrell@Sun.COM 		    "\t\tTime = %lld millisec\n",
713*11547SBill.Gumbrell@Sun.COM 		    (end_time - start_time)/1000000);
7147836SJohn.Forte@Sun.COM 	}
7157836SJohn.Forte@Sun.COM 
7167836SJohn.Forte@Sun.COM 	/* Now link the two together */
7177836SJohn.Forte@Sun.COM 	if (*wwn_list_ptr != NULL) { /* We have both disks and tapes */
7187836SJohn.Forte@Sun.COM 		/* Walk to the end of it */
7197836SJohn.Forte@Sun.COM 		for (tmp = *wwn_list_ptr; tmp->wwn_next != NULL;
720*11547SBill.Gumbrell@Sun.COM 		    tmp = tmp->wwn_next)
721*11547SBill.Gumbrell@Sun.COM 			;
7227836SJohn.Forte@Sun.COM 		tmp->wwn_next = tape_ptr;
7237836SJohn.Forte@Sun.COM 		tape_ptr->wwn_prev = tmp;
7247836SJohn.Forte@Sun.COM 		di_fini(root);
7257836SJohn.Forte@Sun.COM 		return (0);
7267836SJohn.Forte@Sun.COM 	}
7277836SJohn.Forte@Sun.COM 
7287836SJohn.Forte@Sun.COM 	/* else we have no disks */
7297836SJohn.Forte@Sun.COM 	*wwn_list_ptr = tape_ptr;
7307836SJohn.Forte@Sun.COM 	di_fini(root);
7317836SJohn.Forte@Sun.COM 	return (0);
7327836SJohn.Forte@Sun.COM }
7337836SJohn.Forte@Sun.COM 
7347836SJohn.Forte@Sun.COM void
g_free_wwn_list_found(struct wwn_list_found_struct ** wwn_list_found)7357836SJohn.Forte@Sun.COM g_free_wwn_list_found(struct wwn_list_found_struct **wwn_list_found) {
7367836SJohn.Forte@Sun.COM 	WWN_list_found	    *next = NULL;
7377836SJohn.Forte@Sun.COM 
7387836SJohn.Forte@Sun.COM 	/* return if wwn_list_found is NULL */
7397836SJohn.Forte@Sun.COM 	if (wwn_list_found == NULL) {
7407836SJohn.Forte@Sun.COM 		return;
7417836SJohn.Forte@Sun.COM 	}
7427836SJohn.Forte@Sun.COM 	for (; *wwn_list_found != NULL; *wwn_list_found = next) {
7437836SJohn.Forte@Sun.COM 		next = (*wwn_list_found)->wwn_next;
7447836SJohn.Forte@Sun.COM 		g_destroy_data(*wwn_list_found);
7457836SJohn.Forte@Sun.COM 		*wwn_list_found = NULL;
7467836SJohn.Forte@Sun.COM 	}
7477836SJohn.Forte@Sun.COM }
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM void
g_free_wwn_list(struct wwn_list_struct ** wwn_list)7507836SJohn.Forte@Sun.COM g_free_wwn_list(struct wwn_list_struct **wwn_list)
7517836SJohn.Forte@Sun.COM {
752*11547SBill.Gumbrell@Sun.COM 	WWN_list	*next = NULL;
7537836SJohn.Forte@Sun.COM 
7547836SJohn.Forte@Sun.COM 	/* return if wwn_list is NULL */
7557836SJohn.Forte@Sun.COM 	if (wwn_list == NULL) {
7567836SJohn.Forte@Sun.COM 		return;
7577836SJohn.Forte@Sun.COM 	}
7587836SJohn.Forte@Sun.COM 
7597836SJohn.Forte@Sun.COM 	for (; *wwn_list != NULL; *wwn_list = next) {
7607836SJohn.Forte@Sun.COM 		next = (*wwn_list)->wwn_next;
7617836SJohn.Forte@Sun.COM 		if ((*wwn_list)->physical_path != NULL)
7627836SJohn.Forte@Sun.COM 			(void) g_destroy_data((*wwn_list)->physical_path);
7637836SJohn.Forte@Sun.COM 		if ((*wwn_list)->logical_path != NULL)
7647836SJohn.Forte@Sun.COM 			(void) g_destroy_data((*wwn_list)->logical_path);
7657836SJohn.Forte@Sun.COM 		(void) g_destroy_data(*wwn_list);
7667836SJohn.Forte@Sun.COM 	}
7677836SJohn.Forte@Sun.COM 	wwn_list = NULL;
7687836SJohn.Forte@Sun.COM }
7697836SJohn.Forte@Sun.COM 
7707836SJohn.Forte@Sun.COM 
7717836SJohn.Forte@Sun.COM 
7727836SJohn.Forte@Sun.COM 
7737836SJohn.Forte@Sun.COM void
g_sort_wwn_list(struct wwn_list_struct ** wwn_list)7747836SJohn.Forte@Sun.COM g_sort_wwn_list(struct wwn_list_struct **wwn_list)
7757836SJohn.Forte@Sun.COM {
7767836SJohn.Forte@Sun.COM 	int			i, n;
7777836SJohn.Forte@Sun.COM 	struct wwn_list_struct	**wwn_list_array;
7787836SJohn.Forte@Sun.COM 	struct wwn_list_struct	*wwn_list_ptr;
7797836SJohn.Forte@Sun.COM 	struct wwn_list_struct	**wwn_list_array_ptr1;
7807836SJohn.Forte@Sun.COM 	struct wwn_list_struct	**wwn_list_array_ptr2;
7817836SJohn.Forte@Sun.COM 
7827836SJohn.Forte@Sun.COM 	/*
7837836SJohn.Forte@Sun.COM 	 * Count the number of wwn_list in the list
7847836SJohn.Forte@Sun.COM 	 */
7857836SJohn.Forte@Sun.COM 	for (n = 0,  wwn_list_ptr = *wwn_list;
7867836SJohn.Forte@Sun.COM 	    wwn_list_ptr != NULL;
7877836SJohn.Forte@Sun.COM 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
7887836SJohn.Forte@Sun.COM 		n++;
7897836SJohn.Forte@Sun.COM 	}
7907836SJohn.Forte@Sun.COM 	if (n <= 1) {
7917836SJohn.Forte@Sun.COM 		return;
7927836SJohn.Forte@Sun.COM 	}
7937836SJohn.Forte@Sun.COM 
7947836SJohn.Forte@Sun.COM 	/*
7957836SJohn.Forte@Sun.COM 	 * Allocate a simple wwn_list array and fill it in
7967836SJohn.Forte@Sun.COM 	 */
7977836SJohn.Forte@Sun.COM 	wwn_list_array = (struct wwn_list_struct **)
7987836SJohn.Forte@Sun.COM 	    g_zalloc((n+1) * sizeof (struct wwn_list_struct *));
7997836SJohn.Forte@Sun.COM 
8007836SJohn.Forte@Sun.COM 	wwn_list_array_ptr1 = wwn_list_array;
8017836SJohn.Forte@Sun.COM 	for (wwn_list_ptr = *wwn_list;
8027836SJohn.Forte@Sun.COM 	    wwn_list_ptr != NULL;
8037836SJohn.Forte@Sun.COM 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
8047836SJohn.Forte@Sun.COM 		*wwn_list_array_ptr1++ = wwn_list_ptr;
8057836SJohn.Forte@Sun.COM 	}
8067836SJohn.Forte@Sun.COM 	*wwn_list_array_ptr1 = NULL;
8077836SJohn.Forte@Sun.COM 
8087836SJohn.Forte@Sun.COM 	/*
8097836SJohn.Forte@Sun.COM 	 * Sort the wwn_list array
8107836SJohn.Forte@Sun.COM 	 */
8117836SJohn.Forte@Sun.COM 	qsort((void *) wwn_list_array, n,
8127836SJohn.Forte@Sun.COM 	    sizeof (struct wwn_list_struct *), wwn_list_name_compare);
8137836SJohn.Forte@Sun.COM 
8147836SJohn.Forte@Sun.COM 	/*
8157836SJohn.Forte@Sun.COM 	 * Rebuild the linked list wwn_list structure
8167836SJohn.Forte@Sun.COM 	 */
8177836SJohn.Forte@Sun.COM 	wwn_list_array_ptr1 = wwn_list_array;
8187836SJohn.Forte@Sun.COM 	*wwn_list = *wwn_list_array_ptr1;
8197836SJohn.Forte@Sun.COM 	wwn_list_array_ptr2 = wwn_list_array_ptr1 + 1;
8207836SJohn.Forte@Sun.COM 	(*wwn_list_array_ptr1)->wwn_prev = NULL;
8217836SJohn.Forte@Sun.COM 	for (i = 0; i < n - 1; i++) {
822*11547SBill.Gumbrell@Sun.COM 		(*wwn_list_array_ptr2)->wwn_prev = *wwn_list_array_ptr1;
823*11547SBill.Gumbrell@Sun.COM 		(*wwn_list_array_ptr1++)->wwn_next = *wwn_list_array_ptr2++;
8247836SJohn.Forte@Sun.COM 	}
8257836SJohn.Forte@Sun.COM 	(*wwn_list_array_ptr1)->wwn_next = NULL;
8267836SJohn.Forte@Sun.COM 
8277836SJohn.Forte@Sun.COM 	/*
8287836SJohn.Forte@Sun.COM 	 * Clean up
8297836SJohn.Forte@Sun.COM 	 */
8307836SJohn.Forte@Sun.COM 	(void) g_destroy_data((void *)wwn_list_array);
8317836SJohn.Forte@Sun.COM }
8327836SJohn.Forte@Sun.COM 
8337836SJohn.Forte@Sun.COM int
wwn_list_name_compare(const void * arg1,const void * arg2)8347836SJohn.Forte@Sun.COM wwn_list_name_compare(const void *arg1, const void *arg2)
8357836SJohn.Forte@Sun.COM {
8367836SJohn.Forte@Sun.COM 	char	*s1, *s2;
8377836SJohn.Forte@Sun.COM 	int	n1, n2;
8387836SJohn.Forte@Sun.COM 	char	*p1, *p2;
8397836SJohn.Forte@Sun.COM 
8407836SJohn.Forte@Sun.COM 	s1 = (*((struct wwn_list_struct **)arg1))->logical_path;
8417836SJohn.Forte@Sun.COM 	s2 = (*((struct wwn_list_struct **)arg2))->logical_path;
8427836SJohn.Forte@Sun.COM 	for (;;) {
8437836SJohn.Forte@Sun.COM 		if (*s1 == 0 || *s2 == 0)
8447836SJohn.Forte@Sun.COM 			break;
8457836SJohn.Forte@Sun.COM 		if ((isdigit(*s1) && isdigit(*s2))) {
8467836SJohn.Forte@Sun.COM 			n1 = strtol(s1, &p1, 10);
8477836SJohn.Forte@Sun.COM 			n2 = strtol(s2, &p2, 10);
8487836SJohn.Forte@Sun.COM 			if (n1 != n2) {
8497836SJohn.Forte@Sun.COM 				return (n1 - n2);
8507836SJohn.Forte@Sun.COM 			}
8517836SJohn.Forte@Sun.COM 			s1 = p1;
8527836SJohn.Forte@Sun.COM 			s2 = p2;
8537836SJohn.Forte@Sun.COM 		} else if (*s1 != *s2) {
8547836SJohn.Forte@Sun.COM 			break;
8557836SJohn.Forte@Sun.COM 		} else {
8567836SJohn.Forte@Sun.COM 			s1++;
8577836SJohn.Forte@Sun.COM 			s2++;
8587836SJohn.Forte@Sun.COM 		}
8597836SJohn.Forte@Sun.COM 	}
8607836SJohn.Forte@Sun.COM 	return (*s1 - *s2);
8617836SJohn.Forte@Sun.COM }
8627836SJohn.Forte@Sun.COM 
8637836SJohn.Forte@Sun.COM /*
8647836SJohn.Forte@Sun.COM  * Get the limited map for FC4 devices.
8657836SJohn.Forte@Sun.COM  * This function is specific to FC4
8667836SJohn.Forte@Sun.COM  * devices and doesn't work for FC (leadville) devices.
8677836SJohn.Forte@Sun.COM  *
8687836SJohn.Forte@Sun.COM  * RETURN VALUES:
8697836SJohn.Forte@Sun.COM  *	0	 O.K.
8707836SJohn.Forte@Sun.COM  *	non-zero otherwise
8717836SJohn.Forte@Sun.COM  *
8727836SJohn.Forte@Sun.COM  * lilpmap *map_ptr:
8737836SJohn.Forte@Sun.COM  *		NULL: No devices found
8747836SJohn.Forte@Sun.COM  *		!NULL: if devices found
8757836SJohn.Forte@Sun.COM  */
8767836SJohn.Forte@Sun.COM int
g_get_limited_map(char * path,struct lilpmap * map_ptr,int verbose)8777836SJohn.Forte@Sun.COM g_get_limited_map(char *path, struct lilpmap *map_ptr, int verbose)
8787836SJohn.Forte@Sun.COM {
879*11547SBill.Gumbrell@Sun.COM 	int	fd, i;
880*11547SBill.Gumbrell@Sun.COM 	char	drvr_path[MAXPATHLEN];
881*11547SBill.Gumbrell@Sun.COM 	struct	stat	stbuf;
8827836SJohn.Forte@Sun.COM 
8837836SJohn.Forte@Sun.COM 
8847836SJohn.Forte@Sun.COM 	/* initialize map */
8857836SJohn.Forte@Sun.COM 	(void) memset(map_ptr, 0, sizeof (struct lilpmap));
8867836SJohn.Forte@Sun.COM 
8877836SJohn.Forte@Sun.COM 	(void) strcpy(drvr_path, path);
8887836SJohn.Forte@Sun.COM 	/*
8897836SJohn.Forte@Sun.COM 	 * Get the path to the :devctl driver
8907836SJohn.Forte@Sun.COM 	 *
8917836SJohn.Forte@Sun.COM 	 * This assumes the path looks something like this:
8927836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0:1
8937836SJohn.Forte@Sun.COM 	 * or
8947836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0
8957836SJohn.Forte@Sun.COM 	 * or
8967836SJohn.Forte@Sun.COM 	 * a 1 level PCI type driver
8977836SJohn.Forte@Sun.COM 	 */
8987836SJohn.Forte@Sun.COM 	if (stat(drvr_path, &stbuf) < 0) {
8997836SJohn.Forte@Sun.COM 		return (L_LSTAT_ERROR);
9007836SJohn.Forte@Sun.COM 	}
9017836SJohn.Forte@Sun.COM 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
9027836SJohn.Forte@Sun.COM 		/* append a port. Just try 0 since they did not give us one */
9037836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, ":0");
9047836SJohn.Forte@Sun.COM 	}
9057836SJohn.Forte@Sun.COM 
9067836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_limited_map: Geting drive map from:"
907*11547SBill.Gumbrell@Sun.COM 	    " %s\n", drvr_path);
9087836SJohn.Forte@Sun.COM 
9097836SJohn.Forte@Sun.COM 	/* open controller */
9107836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
9117836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
9127836SJohn.Forte@Sun.COM 
9137836SJohn.Forte@Sun.COM 	if (ioctl(fd, FCIO_GETMAP, map_ptr) != 0) {
9147836SJohn.Forte@Sun.COM 		I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
9157836SJohn.Forte@Sun.COM 		(void) close(fd);
9167836SJohn.Forte@Sun.COM 		return (L_FCIO_GETMAP_IOCTL_FAIL);
9177836SJohn.Forte@Sun.COM 	}
9187836SJohn.Forte@Sun.COM 	(void) close(fd);
9197836SJohn.Forte@Sun.COM 
9207836SJohn.Forte@Sun.COM 	/*
9217836SJohn.Forte@Sun.COM 	 * Check for reasonableness.
9227836SJohn.Forte@Sun.COM 	 */
9237836SJohn.Forte@Sun.COM 	if ((map_ptr->lilp_length > 126) || (map_ptr->lilp_magic != 0x1107)) {
9247836SJohn.Forte@Sun.COM 		return (L_INVALID_LOOP_MAP);
9257836SJohn.Forte@Sun.COM 	}
9267836SJohn.Forte@Sun.COM 	for (i = 0; i < (uint_t)map_ptr->lilp_length; i++) {
9277836SJohn.Forte@Sun.COM 		if (map_ptr->lilp_list[i] > 0xef) {
9287836SJohn.Forte@Sun.COM 			return (L_INVALID_LOOP_MAP);
9297836SJohn.Forte@Sun.COM 		}
9307836SJohn.Forte@Sun.COM 	}
9317836SJohn.Forte@Sun.COM 
9327836SJohn.Forte@Sun.COM 	return (0);
9337836SJohn.Forte@Sun.COM }
9347836SJohn.Forte@Sun.COM 
9357836SJohn.Forte@Sun.COM 
9367836SJohn.Forte@Sun.COM /*
9377836SJohn.Forte@Sun.COM  * For leadville specific HBA's ONLY.
9387836SJohn.Forte@Sun.COM  * Get the host specific parameters,
9397836SJohn.Forte@Sun.COM  * al_pa, hard address, node/port WWN etc.
9407836SJohn.Forte@Sun.COM  *
9417836SJohn.Forte@Sun.COM  * OUTPUT:
9427836SJohn.Forte@Sun.COM  *	fc_port_dev_t structure.
9437836SJohn.Forte@Sun.COM  *
9447836SJohn.Forte@Sun.COM  * RETURNS:
9457836SJohn.Forte@Sun.COM  *	0	if  OK
9467836SJohn.Forte@Sun.COM  *	non-zero in case of error.
9477836SJohn.Forte@Sun.COM  */
9487836SJohn.Forte@Sun.COM int
g_get_host_params(char * host_path,fc_port_dev_t * host_val,int verbose)9497836SJohn.Forte@Sun.COM g_get_host_params(char *host_path, fc_port_dev_t *host_val, int verbose)
9507836SJohn.Forte@Sun.COM {
951*11547SBill.Gumbrell@Sun.COM 	int		err;
952*11547SBill.Gumbrell@Sun.COM 	int		fd;
953*11547SBill.Gumbrell@Sun.COM 	int		dev_type;
954*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
9557836SJohn.Forte@Sun.COM 
9567836SJohn.Forte@Sun.COM 	/* return invalid path if host_path is NULL */
9577836SJohn.Forte@Sun.COM 	if (host_path == NULL) {
9587836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
9597836SJohn.Forte@Sun.COM 	}
9607836SJohn.Forte@Sun.COM 	/* return invalid arg if host_val is NULL */
9617836SJohn.Forte@Sun.COM 	if (host_val == NULL) {
9627836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
9637836SJohn.Forte@Sun.COM 	}
9647836SJohn.Forte@Sun.COM 
9657836SJohn.Forte@Sun.COM 	dev_type = g_get_path_type(host_path);
9667836SJohn.Forte@Sun.COM 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
9677836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
9687836SJohn.Forte@Sun.COM 	}
9697836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(host_path, O_NDELAY | O_RDONLY)) == -1) {
9707836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
9717836SJohn.Forte@Sun.COM 	}
9727836SJohn.Forte@Sun.COM 
9737836SJohn.Forte@Sun.COM 	/* initialize structure */
9747836SJohn.Forte@Sun.COM 	(void) memset(host_val, 0, sizeof (struct fc_port_dev));
9757836SJohn.Forte@Sun.COM 
9767836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
9777836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_READ;
9787836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = (caddr_t)host_val;
9797836SJohn.Forte@Sun.COM 	fcio.fcio_olen = sizeof (fc_port_dev_t);
9807836SJohn.Forte@Sun.COM 
9817836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
9827836SJohn.Forte@Sun.COM 		I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
9837836SJohn.Forte@Sun.COM 		(void) close(fd);
9847836SJohn.Forte@Sun.COM 		return (L_FCIO_GET_HOST_PARAMS_FAIL);
9857836SJohn.Forte@Sun.COM 	}
9867836SJohn.Forte@Sun.COM 	(void) close(fd);
9877836SJohn.Forte@Sun.COM 
9887836SJohn.Forte@Sun.COM 	/* get the inquiry information for the leadville HBA. */
9897836SJohn.Forte@Sun.COM 	if ((err = get_fca_inq_dtype(host_path, host_val->dev_pwwn,
990*11547SBill.Gumbrell@Sun.COM 	    &host_val->dev_dtype)) != 0) {
9917836SJohn.Forte@Sun.COM 		return (err);
9927836SJohn.Forte@Sun.COM 	}
9937836SJohn.Forte@Sun.COM 	return (0);
9947836SJohn.Forte@Sun.COM }
9957836SJohn.Forte@Sun.COM 
9967836SJohn.Forte@Sun.COM 
9977836SJohn.Forte@Sun.COM 
9987836SJohn.Forte@Sun.COM /*
9997836SJohn.Forte@Sun.COM  * Issue FCIO ioctls to the port(fp) driver.
10007836SJohn.Forte@Sun.COM  * FCIO ioctl needs to be retried when it
10017836SJohn.Forte@Sun.COM  * is returned with an EINVAL error, wait
10027836SJohn.Forte@Sun.COM  * time between retries should be atleast
10037836SJohn.Forte@Sun.COM  * WAIT_FCIO_IOCTL (too much of a time to wait!!)
10047836SJohn.Forte@Sun.COM  *
10057836SJohn.Forte@Sun.COM  * OUTPUT:
10067836SJohn.Forte@Sun.COM  *	fcio_t structure
10077836SJohn.Forte@Sun.COM  *
10087836SJohn.Forte@Sun.COM  * RETURNS:
10097836SJohn.Forte@Sun.COM  *	0	 if O.K.
10107836SJohn.Forte@Sun.COM  *	non-zero otherwise.
10117836SJohn.Forte@Sun.COM  */
10127836SJohn.Forte@Sun.COM int
g_issue_fcio_ioctl(int fd,fcio_t * fcio,int verbose)10137836SJohn.Forte@Sun.COM g_issue_fcio_ioctl(int fd, fcio_t *fcio, int verbose)
10147836SJohn.Forte@Sun.COM {
1015*11547SBill.Gumbrell@Sun.COM 	int	ntries;
10167836SJohn.Forte@Sun.COM 
10177836SJohn.Forte@Sun.COM 	for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) {
10187836SJohn.Forte@Sun.COM 		if (ioctl(fd, FCIO_CMD, fcio) != 0) {
10197836SJohn.Forte@Sun.COM 			if ((errno == EAGAIN) &&
1020*11547SBill.Gumbrell@Sun.COM 			    (ntries+1 < RETRY_FCIO_IOCTL)) {
10217836SJohn.Forte@Sun.COM 				/* wait WAIT_FCIO_IOCTL */
10227836SJohn.Forte@Sun.COM 				(void) usleep(WAIT_FCIO_IOCTL);
10237836SJohn.Forte@Sun.COM 				continue;
10247836SJohn.Forte@Sun.COM 			}
10257836SJohn.Forte@Sun.COM 			I_DPRINTF("FCIO ioctl failed.\n"
1026*11547SBill.Gumbrell@Sun.COM 			    "Error: %s. fc_error = %d (0x%x)\n",
1027*11547SBill.Gumbrell@Sun.COM 			    strerror(errno), fcio->fcio_errno,
1028*11547SBill.Gumbrell@Sun.COM 			    fcio->fcio_errno);
10297836SJohn.Forte@Sun.COM 			if (errno == EINVAL) {
10307836SJohn.Forte@Sun.COM 				if (fcio->fcio_errno == FC_TOOMANY) {
10317836SJohn.Forte@Sun.COM 					return (L_INVALID_DEVICE_COUNT);
10327836SJohn.Forte@Sun.COM 				} else {
10337836SJohn.Forte@Sun.COM 					return (errno);
10347836SJohn.Forte@Sun.COM 				}
10357836SJohn.Forte@Sun.COM 			}
10367836SJohn.Forte@Sun.COM 			/*
10377836SJohn.Forte@Sun.COM 			 * When port is offlined, qlc
10387836SJohn.Forte@Sun.COM 			 * returns the FC_OFFLINE error and errno
10397836SJohn.Forte@Sun.COM 			 * is set to EIO.
10407836SJohn.Forte@Sun.COM 			 * We do want to ignore this error,
10417836SJohn.Forte@Sun.COM 			 * especially when an enclosure is
10427836SJohn.Forte@Sun.COM 			 * removed from the loop.
10437836SJohn.Forte@Sun.COM 			 */
10447836SJohn.Forte@Sun.COM 			if (fcio->fcio_errno == FC_OFFLINE)
10457836SJohn.Forte@Sun.COM 				break;
10467836SJohn.Forte@Sun.COM 			return (-1);
10477836SJohn.Forte@Sun.COM 		}
10487836SJohn.Forte@Sun.COM 		break;
10497836SJohn.Forte@Sun.COM 	}
10507836SJohn.Forte@Sun.COM 
10517836SJohn.Forte@Sun.COM 	return (0);
10527836SJohn.Forte@Sun.COM }
10537836SJohn.Forte@Sun.COM 
10547836SJohn.Forte@Sun.COM /*
10557836SJohn.Forte@Sun.COM  * This function issues the FCP_TGT_INQUIRY ioctl to
10567836SJohn.Forte@Sun.COM  * the fcp module
10577836SJohn.Forte@Sun.COM  *
10587836SJohn.Forte@Sun.COM  * OUTPUT:
10597836SJohn.Forte@Sun.COM  *	fcp_ioctl structure in fcp_data is filled in by fcp
10607836SJohn.Forte@Sun.COM  *
10617836SJohn.Forte@Sun.COM  * RETURN VALUES :
10627836SJohn.Forte@Sun.COM  *	0 on Success
10637836SJohn.Forte@Sun.COM  *	Non-zero otherwise
10647836SJohn.Forte@Sun.COM  */
10657836SJohn.Forte@Sun.COM static int
g_issue_fcp_ioctl(int fd,struct fcp_ioctl * fcp_data,int verbose)10667836SJohn.Forte@Sun.COM g_issue_fcp_ioctl(int fd, struct fcp_ioctl *fcp_data, int verbose)
10677836SJohn.Forte@Sun.COM {
10687836SJohn.Forte@Sun.COM 	int 			num_tries = 0;
10697836SJohn.Forte@Sun.COM 	struct device_data	*dev_data = NULL;
10707836SJohn.Forte@Sun.COM 
10717836SJohn.Forte@Sun.COM 	/*
10727836SJohn.Forte@Sun.COM 	 * Issue the ioctl to FCP
10737836SJohn.Forte@Sun.COM 	 * The retries are required because the driver may
10747836SJohn.Forte@Sun.COM 	 * need some time to respond at times.
10757836SJohn.Forte@Sun.COM 	 */
10767836SJohn.Forte@Sun.COM 	while (num_tries++ < RETRY_FCP_IOCTL) {
10777836SJohn.Forte@Sun.COM 		/* if ioctl fails it is an error from Solaris operation. */
10787836SJohn.Forte@Sun.COM 		if (ioctl(fd, FCP_TGT_INQUIRY, fcp_data) == -1) {
10797836SJohn.Forte@Sun.COM 			if (errno == EAGAIN) {
10807836SJohn.Forte@Sun.COM 				(void) usleep(WAIT_FCP_IOCTL);
10817836SJohn.Forte@Sun.COM 				continue;
10827836SJohn.Forte@Sun.COM 			} else {
10837836SJohn.Forte@Sun.COM 				break;
10847836SJohn.Forte@Sun.COM 			}
10857836SJohn.Forte@Sun.COM 		}
10867836SJohn.Forte@Sun.COM 		dev_data = (struct device_data *)((void *)(fcp_data->list));
10877836SJohn.Forte@Sun.COM 		if (dev_data->dev_status == 0) {
10887836SJohn.Forte@Sun.COM 			return (0);
10897836SJohn.Forte@Sun.COM 		}
10907836SJohn.Forte@Sun.COM 
10917836SJohn.Forte@Sun.COM 		if (dev_data->dev_status == EAGAIN) {
10927836SJohn.Forte@Sun.COM 			(void) usleep(WAIT_FCP_IOCTL);
10937836SJohn.Forte@Sun.COM 			continue;
10947836SJohn.Forte@Sun.COM 		} else {
10957836SJohn.Forte@Sun.COM 			dev_data->dev0_type = DTYPE_UNKNOWN;
10967836SJohn.Forte@Sun.COM 			return (0);
10977836SJohn.Forte@Sun.COM 		}
10987836SJohn.Forte@Sun.COM 	}
10997836SJohn.Forte@Sun.COM 
11007836SJohn.Forte@Sun.COM 	return (L_FCP_TGT_INQUIRY_FAIL);
11017836SJohn.Forte@Sun.COM }
11027836SJohn.Forte@Sun.COM 
11037836SJohn.Forte@Sun.COM /*
11047836SJohn.Forte@Sun.COM  * Get the number of devices and also
11057836SJohn.Forte@Sun.COM  * a list of devices accessible through
11067836SJohn.Forte@Sun.COM  * the device's port as specified by path.
11077836SJohn.Forte@Sun.COM  * The calling function * is responsible for freeing the dev_list.
11087836SJohn.Forte@Sun.COM  *
11097836SJohn.Forte@Sun.COM  * Acquires inq_dtype from g_get_inq_dtype() and
11107836SJohn.Forte@Sun.COM  * stores into dev_dtype field of fc_port_dev.
11117836SJohn.Forte@Sun.COM  *
11127836SJohn.Forte@Sun.COM  * For fabric devices call FCIO_DEV_LOGIN (if necessary) to execute port login
11137836SJohn.Forte@Sun.COM  * and get inq dtype.
11147836SJohn.Forte@Sun.COM  *
11157836SJohn.Forte@Sun.COM  * dev_list:
11167836SJohn.Forte@Sun.COM  *	NULL:	  No devices found, in case of an error
11177836SJohn.Forte@Sun.COM  *	Non-NULL: Devices found.
11187836SJohn.Forte@Sun.COM  * ndevs:
11197836SJohn.Forte@Sun.COM  *	set to the number of devices
11207836SJohn.Forte@Sun.COM  *	accessible through the port.
11217836SJohn.Forte@Sun.COM  *
11227836SJohn.Forte@Sun.COM  * RETURNS:
11237836SJohn.Forte@Sun.COM  *	0	 if O.K.
11247836SJohn.Forte@Sun.COM  *	non-zero otherwise
11257836SJohn.Forte@Sun.COM  */
11267836SJohn.Forte@Sun.COM int
g_get_dev_list(char * path,fc_port_dev_t ** dev_list,int * ndevs)11277836SJohn.Forte@Sun.COM g_get_dev_list(char *path, fc_port_dev_t **dev_list, int *ndevs)
11287836SJohn.Forte@Sun.COM {
1129*11547SBill.Gumbrell@Sun.COM 	int		num_devices = 0;
1130*11547SBill.Gumbrell@Sun.COM 	int		i, err, ulp_failure = 0, new_count = 0;
1131*11547SBill.Gumbrell@Sun.COM 	int		dev_type;
1132*11547SBill.Gumbrell@Sun.COM 	int		fd;
1133*11547SBill.Gumbrell@Sun.COM 	char		fcapath[MAXPATHLEN];
1134*11547SBill.Gumbrell@Sun.COM 	char		*char_ptr;
1135*11547SBill.Gumbrell@Sun.COM 	struct	stat	stbuf;
1136*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
1137*11547SBill.Gumbrell@Sun.COM 	uint32_t	port_top;
1138*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	*dlist;
11397836SJohn.Forte@Sun.COM 
11407836SJohn.Forte@Sun.COM 	*dev_list = dlist = NULL;
11417836SJohn.Forte@Sun.COM 	(void) strcpy(fcapath, path);
11427836SJohn.Forte@Sun.COM 	/*
11437836SJohn.Forte@Sun.COM 	 * Get the path to the :devctl driver
11447836SJohn.Forte@Sun.COM 	 *
11457836SJohn.Forte@Sun.COM 	 * This assumes the path looks something like this:
11467836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
11477836SJohn.Forte@Sun.COM 	 * or
11487836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
11497836SJohn.Forte@Sun.COM 	 * or
11507836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
11517836SJohn.Forte@Sun.COM 	 * or
11527836SJohn.Forte@Sun.COM 	 * a 1 level PCI type driver but still :devctl
11537836SJohn.Forte@Sun.COM 	 */
11547836SJohn.Forte@Sun.COM 	if (strstr(fcapath, DRV_NAME_SSD) || strstr(fcapath, SES_NAME)) {
11557836SJohn.Forte@Sun.COM 		if ((char_ptr = strrchr(fcapath, '/')) == NULL) {
11567836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
11577836SJohn.Forte@Sun.COM 		}
11587836SJohn.Forte@Sun.COM 		*char_ptr = '\0';   /* Terminate sting  */
11597836SJohn.Forte@Sun.COM 		/* append controller */
11607836SJohn.Forte@Sun.COM 		(void) strcat(fcapath, FC_CTLR);
11617836SJohn.Forte@Sun.COM 	} else {
11627836SJohn.Forte@Sun.COM 		if (stat(fcapath, &stbuf) < 0) {
11637836SJohn.Forte@Sun.COM 			return (L_LSTAT_ERROR);
11647836SJohn.Forte@Sun.COM 		}
11657836SJohn.Forte@Sun.COM 		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
11667836SJohn.Forte@Sun.COM 			/* append controller */
11677836SJohn.Forte@Sun.COM 			(void) strcat(fcapath, FC_CTLR);
11687836SJohn.Forte@Sun.COM 		}
11697836SJohn.Forte@Sun.COM 	}
11707836SJohn.Forte@Sun.COM 	dev_type = g_get_path_type(fcapath);
11717836SJohn.Forte@Sun.COM 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
11727836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
11737836SJohn.Forte@Sun.COM 	}
11747836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
11757836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
11767836SJohn.Forte@Sun.COM 	}
11777836SJohn.Forte@Sun.COM 
11787836SJohn.Forte@Sun.COM 	/*
11797836SJohn.Forte@Sun.COM 	 * Get the device list from port driver
11807836SJohn.Forte@Sun.COM 	 */
11817836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
11827836SJohn.Forte@Sun.COM 	fcio.fcio_olen = sizeof (num_devices);
11837836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_READ;
11847836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = (caddr_t)&num_devices;
11857836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
11867836SJohn.Forte@Sun.COM 		I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
11877836SJohn.Forte@Sun.COM 		(void) close(fd);
11887836SJohn.Forte@Sun.COM 		return (L_FCIO_GET_NUM_DEVS_FAIL);
11897836SJohn.Forte@Sun.COM 	}
11907836SJohn.Forte@Sun.COM 	if (num_devices == 0) {
11917836SJohn.Forte@Sun.COM 		*ndevs = 0;
11927836SJohn.Forte@Sun.COM 		(void) close(fd);
11937836SJohn.Forte@Sun.COM 		return (L_NO_DEVICES_FOUND);
11947836SJohn.Forte@Sun.COM 	}
11957836SJohn.Forte@Sun.COM 
11967836SJohn.Forte@Sun.COM 	if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1197*11547SBill.Gumbrell@Sun.COM 	    sizeof (fc_port_dev_t))) == NULL) {
11987836SJohn.Forte@Sun.COM 		(void) close(fd);
11997836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
12007836SJohn.Forte@Sun.COM 	}
12017836SJohn.Forte@Sun.COM 	bzero((caddr_t)&fcio, sizeof (fcio));
12027836SJohn.Forte@Sun.COM 	/* Get the device list */
12037836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_GET_DEV_LIST;
12047836SJohn.Forte@Sun.COM 	/* Information read operation */
12057836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_READ;
12067836SJohn.Forte@Sun.COM 	fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
12077836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = (caddr_t)dlist;
12087836SJohn.Forte@Sun.COM 	/* new device count */
12097836SJohn.Forte@Sun.COM 	fcio.fcio_alen = sizeof (new_count);
12107836SJohn.Forte@Sun.COM 	fcio.fcio_abuf = (caddr_t)&new_count;
12117836SJohn.Forte@Sun.COM 	if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1212*11547SBill.Gumbrell@Sun.COM 		if (err == L_INVALID_DEVICE_COUNT) {
1213*11547SBill.Gumbrell@Sun.COM 			/*
1214*11547SBill.Gumbrell@Sun.COM 			 * original buffer was small so allocate buffer
1215*11547SBill.Gumbrell@Sun.COM 			 * with a new count and retry.
1216*11547SBill.Gumbrell@Sun.COM 			 */
1217*11547SBill.Gumbrell@Sun.COM 			free(dlist);
1218*11547SBill.Gumbrell@Sun.COM 			num_devices = new_count;
1219*11547SBill.Gumbrell@Sun.COM 			new_count = 0;
1220*11547SBill.Gumbrell@Sun.COM 			if ((dlist = (fc_port_dev_t *)calloc(num_devices,
1221*11547SBill.Gumbrell@Sun.COM 			    sizeof (fc_port_dev_t))) == NULL) {
1222*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
1223*11547SBill.Gumbrell@Sun.COM 				return (L_MALLOC_FAILED);
1224*11547SBill.Gumbrell@Sun.COM 			}
1225*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
1226*11547SBill.Gumbrell@Sun.COM 			/* Information read operation */
1227*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_xfer = FCIO_XFER_READ;
1228*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_obuf = (caddr_t)dlist;
1229*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
1230*11547SBill.Gumbrell@Sun.COM 			/* new device count */
1231*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_alen = sizeof (new_count);
1232*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_abuf = (caddr_t)&new_count;
1233*11547SBill.Gumbrell@Sun.COM 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
1234*11547SBill.Gumbrell@Sun.COM 				if (err == L_INVALID_DEVICE_COUNT) {
1235*11547SBill.Gumbrell@Sun.COM 					/*
1236*11547SBill.Gumbrell@Sun.COM 					 * No more retry. There may be severe
1237*11547SBill.Gumbrell@Sun.COM 					 * hardware problem so return error
1238*11547SBill.Gumbrell@Sun.COM 					 * here.
1239*11547SBill.Gumbrell@Sun.COM 					 */
1240*11547SBill.Gumbrell@Sun.COM 					I_DPRINTF(" Device count was %d"
1241*11547SBill.Gumbrell@Sun.COM 					    " should have been %d\n",
1242*11547SBill.Gumbrell@Sun.COM 					    num_devices, new_count);
1243*11547SBill.Gumbrell@Sun.COM 				} else {
1244*11547SBill.Gumbrell@Sun.COM 					I_DPRINTF(
1245*11547SBill.Gumbrell@Sun.COM 					    " FCIO_GET_DEV_LIST ioctl failed.");
1246*11547SBill.Gumbrell@Sun.COM 					err = L_FCIO_GET_DEV_LIST_FAIL;
1247*11547SBill.Gumbrell@Sun.COM 				}
1248*11547SBill.Gumbrell@Sun.COM 				free(dlist);
1249*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
1250*11547SBill.Gumbrell@Sun.COM 				return (err);
1251*11547SBill.Gumbrell@Sun.COM 			}
1252*11547SBill.Gumbrell@Sun.COM 		} else {
1253*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
1254*11547SBill.Gumbrell@Sun.COM 			free(dlist);
12557836SJohn.Forte@Sun.COM 			(void) close(fd);
1256*11547SBill.Gumbrell@Sun.COM 			return (L_FCIO_GET_DEV_LIST_FAIL);
12577836SJohn.Forte@Sun.COM 		}
12587836SJohn.Forte@Sun.COM 	}
12597836SJohn.Forte@Sun.COM 
12607836SJohn.Forte@Sun.COM 	/*
12617836SJohn.Forte@Sun.COM 	 * if new count is smaller than the original number from
12627836SJohn.Forte@Sun.COM 	 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
12637836SJohn.Forte@Sun.COM 	 * and continue.
12647836SJohn.Forte@Sun.COM 	 */
12657836SJohn.Forte@Sun.COM 	if (new_count < num_devices) {
12667836SJohn.Forte@Sun.COM 		if (new_count == 0) {
12677836SJohn.Forte@Sun.COM 			*ndevs = 0;
12687836SJohn.Forte@Sun.COM 			(void) close(fd);
12697836SJohn.Forte@Sun.COM 			S_FREE(dlist);
12707836SJohn.Forte@Sun.COM 			return (L_NO_DEVICES_FOUND);
12717836SJohn.Forte@Sun.COM 		}
12727836SJohn.Forte@Sun.COM 		num_devices = new_count;
12737836SJohn.Forte@Sun.COM 		if ((dlist = (fc_port_dev_t *)realloc(dlist,
1274*11547SBill.Gumbrell@Sun.COM 		    (new_count * sizeof (fc_port_dev_t))))
1275*11547SBill.Gumbrell@Sun.COM 		    == NULL) {
12767836SJohn.Forte@Sun.COM 			S_FREE(dlist);
12777836SJohn.Forte@Sun.COM 			(void) close(fd);
12787836SJohn.Forte@Sun.COM 			return (L_MALLOC_FAILED);
12797836SJohn.Forte@Sun.COM 		}
12807836SJohn.Forte@Sun.COM 	}
12817836SJohn.Forte@Sun.COM 
12827836SJohn.Forte@Sun.COM 	*dev_list = dlist;
12837836SJohn.Forte@Sun.COM 	*ndevs = num_devices;
12847836SJohn.Forte@Sun.COM 
12857836SJohn.Forte@Sun.COM 	/* close here since fcapath will be passed to other routines. */
12867836SJohn.Forte@Sun.COM 	(void) close(fd);
12877836SJohn.Forte@Sun.COM 
12887836SJohn.Forte@Sun.COM 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
12897836SJohn.Forte@Sun.COM 		free(*dev_list);
12907836SJohn.Forte@Sun.COM 		*dev_list = NULL;
12917836SJohn.Forte@Sun.COM 		return (err);
12927836SJohn.Forte@Sun.COM 	}
12937836SJohn.Forte@Sun.COM 
12947836SJohn.Forte@Sun.COM 	/* Get the inq_dtype for each device on dev list. */
12957836SJohn.Forte@Sun.COM 	for (i = 0; i < num_devices; i++, dlist++) {
12967836SJohn.Forte@Sun.COM 		/* Get the inq_dtype for each device. */
12977836SJohn.Forte@Sun.COM 		if ((err = g_get_inq_dtype(fcapath, dlist->dev_pwwn,
1298*11547SBill.Gumbrell@Sun.COM 		    &dlist->dev_dtype)) != 0) {
12997836SJohn.Forte@Sun.COM 			/*
13007836SJohn.Forte@Sun.COM 			 * if g_get_inq_dtype failed on g_dev_login
13017836SJohn.Forte@Sun.COM 			 * or g_issue_fcp_ioctl, continue to the next
13027836SJohn.Forte@Sun.COM 			 * dev on dlist.
13037836SJohn.Forte@Sun.COM 			 * L_GET_DEV_LIST_ULP_FAILURE is returned
13047836SJohn.Forte@Sun.COM 			 * after processing the whole dlist.
13057836SJohn.Forte@Sun.COM 			 */
13067836SJohn.Forte@Sun.COM 			if ((err == L_FCIO_DEV_LOGIN_FAIL) ||
1307*11547SBill.Gumbrell@Sun.COM 			    (err == L_FCP_TGT_INQUIRY_FAIL)) {
13087836SJohn.Forte@Sun.COM 				ulp_failure = 1;
13097836SJohn.Forte@Sun.COM 				dlist->dev_dtype = GFC_ERR_INQ_DTYPE;
13107836SJohn.Forte@Sun.COM 			} else {
13117836SJohn.Forte@Sun.COM 				(void) free(*dev_list);
13127836SJohn.Forte@Sun.COM 				*dev_list = NULL;
13137836SJohn.Forte@Sun.COM 				return (err);
13147836SJohn.Forte@Sun.COM 			}
13157836SJohn.Forte@Sun.COM 		}
13167836SJohn.Forte@Sun.COM 	}
13177836SJohn.Forte@Sun.COM 
13187836SJohn.Forte@Sun.COM 	if (ulp_failure) {
13197836SJohn.Forte@Sun.COM 		return (L_GET_DEV_LIST_ULP_FAILURE);
13207836SJohn.Forte@Sun.COM 	} else {
13217836SJohn.Forte@Sun.COM 		return (0);
13227836SJohn.Forte@Sun.COM 	}
13237836SJohn.Forte@Sun.COM }
13247836SJohn.Forte@Sun.COM 
13257836SJohn.Forte@Sun.COM 
13267836SJohn.Forte@Sun.COM /* Constant used by g_get_inq_dtype() */
13277836SJohn.Forte@Sun.COM #define	FCP_PATH	"/devices/pseudo/fcp@0:fcp"
13287836SJohn.Forte@Sun.COM 
13297836SJohn.Forte@Sun.COM /*
13307836SJohn.Forte@Sun.COM  * Gets the inq_dtype for devices on the fabric FC driver
13317836SJohn.Forte@Sun.COM  * through an ioctl to the FCP module.
13327836SJohn.Forte@Sun.COM  *
13337836SJohn.Forte@Sun.COM  * OUTPUT:
13347836SJohn.Forte@Sun.COM  *	inq_dtype is set to the dtype on success
13357836SJohn.Forte@Sun.COM  *
13367836SJohn.Forte@Sun.COM  * RETURN VALUES:
13377836SJohn.Forte@Sun.COM  *	0 on Success
13387836SJohn.Forte@Sun.COM  *	Non-zero on error
13397836SJohn.Forte@Sun.COM  */
13407836SJohn.Forte@Sun.COM int
g_get_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)13417836SJohn.Forte@Sun.COM g_get_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
13427836SJohn.Forte@Sun.COM {
13437836SJohn.Forte@Sun.COM 	int			dev_type, fd;
13447836SJohn.Forte@Sun.COM 	int			err, fcp_fd;
13457836SJohn.Forte@Sun.COM 	uint32_t		state;
13467836SJohn.Forte@Sun.COM 	uint32_t		port_top = 0;
13477836SJohn.Forte@Sun.COM 	struct fcp_ioctl	fcp_data;
13487836SJohn.Forte@Sun.COM 	struct device_data	inq_data;
13497836SJohn.Forte@Sun.COM 	struct stat		sbuf;
13507836SJohn.Forte@Sun.COM 
13517836SJohn.Forte@Sun.COM 	dev_type = g_get_path_type(fcapath);
13527836SJohn.Forte@Sun.COM 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
13537836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
13547836SJohn.Forte@Sun.COM 	}
13557836SJohn.Forte@Sun.COM 
13567836SJohn.Forte@Sun.COM 	if ((err = g_get_fca_port_topology(fcapath, &port_top, 0)) != 0) {
13577836SJohn.Forte@Sun.COM 		return (err);
13587836SJohn.Forte@Sun.COM 	}
13597836SJohn.Forte@Sun.COM 
13607836SJohn.Forte@Sun.COM 	if ((port_top == FC_TOP_FABRIC) || (port_top == FC_TOP_PUBLIC_LOOP)) {
13617836SJohn.Forte@Sun.COM 		/*
13627836SJohn.Forte@Sun.COM 		 * if there is an error on getting port state we will
13637836SJohn.Forte@Sun.COM 		 * continue to login.
13647836SJohn.Forte@Sun.COM 		 * state can be either of
13657836SJohn.Forte@Sun.COM 		 * PORT_DEVICE_INVALID, PORT_DEVICE_VALID,
13667836SJohn.Forte@Sun.COM 		 * PORT_DEVICE_LOGGED_IN.  Trying port login
13677836SJohn.Forte@Sun.COM 		 * unless already logged in.
13687836SJohn.Forte@Sun.COM 		 * It will be examined if there is an adverse
13697836SJohn.Forte@Sun.COM 		 * effect on invalid state device.
13707836SJohn.Forte@Sun.COM 		 */
13717836SJohn.Forte@Sun.COM 		if (((err = g_get_dev_port_state(fcapath, pwwn, &state))
1372*11547SBill.Gumbrell@Sun.COM 		    != 0) || (state != PORT_DEVICE_LOGGED_IN)) {
13737836SJohn.Forte@Sun.COM 			/* do port login to fabric device.  */
13747836SJohn.Forte@Sun.COM 			if ((err = g_dev_login(fcapath, pwwn)) != 0) {
13757836SJohn.Forte@Sun.COM 				return (err);
13767836SJohn.Forte@Sun.COM 			}
13777836SJohn.Forte@Sun.COM 		}
13787836SJohn.Forte@Sun.COM 	}
13797836SJohn.Forte@Sun.COM 
13807836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1)
13817836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
13827836SJohn.Forte@Sun.COM 
13837836SJohn.Forte@Sun.COM 	if (fstat(fd, &sbuf) == -1) {
13847836SJohn.Forte@Sun.COM 		(void) close(fd);
13857836SJohn.Forte@Sun.COM 		return (L_FSTAT_ERROR);
13867836SJohn.Forte@Sun.COM 	}
13877836SJohn.Forte@Sun.COM 
13887836SJohn.Forte@Sun.COM 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
13897836SJohn.Forte@Sun.COM 		(void) close(fd);
13907836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
13917836SJohn.Forte@Sun.COM 	}
13927836SJohn.Forte@Sun.COM 
13937836SJohn.Forte@Sun.COM 	/* Get the minor number for an fp instance */
13947836SJohn.Forte@Sun.COM 	fcp_data.fp_minor = minor(sbuf.st_rdev);
13957836SJohn.Forte@Sun.COM 
13967836SJohn.Forte@Sun.COM 	fcp_data.listlen = 1;
13977836SJohn.Forte@Sun.COM 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
13987836SJohn.Forte@Sun.COM 	fcp_data.list = (caddr_t)&inq_data;
13997836SJohn.Forte@Sun.COM 
14007836SJohn.Forte@Sun.COM 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
14017836SJohn.Forte@Sun.COM 		close(fd);
14027836SJohn.Forte@Sun.COM 		close(fcp_fd);
14037836SJohn.Forte@Sun.COM 		return (err);
14047836SJohn.Forte@Sun.COM 	}
14057836SJohn.Forte@Sun.COM 	*inq_dtype = inq_data.dev0_type;
14067836SJohn.Forte@Sun.COM 
14077836SJohn.Forte@Sun.COM 	close(fd);
14087836SJohn.Forte@Sun.COM 	close(fcp_fd);
14097836SJohn.Forte@Sun.COM 
14107836SJohn.Forte@Sun.COM 	return (err);
14117836SJohn.Forte@Sun.COM }
14127836SJohn.Forte@Sun.COM 
14137836SJohn.Forte@Sun.COM /*
14147836SJohn.Forte@Sun.COM  * Gets the inq_dtype for devices on the fabric FC driver
14157836SJohn.Forte@Sun.COM  * through an ioctl to the FCP module.
14167836SJohn.Forte@Sun.COM  *
14177836SJohn.Forte@Sun.COM  * This is exactly same as g_get_inq_dtype except that it does not do
14187836SJohn.Forte@Sun.COM  * g_dev_login(). That is for the case when the FCA tries to get its own
14197836SJohn.Forte@Sun.COM  * inq_dtype and in such a case, it cannot PLOGI into itself.
14207836SJohn.Forte@Sun.COM  *
14217836SJohn.Forte@Sun.COM  * OUTPUT:
14227836SJohn.Forte@Sun.COM  *	inq_dtype is set to the dtype on success
14237836SJohn.Forte@Sun.COM  *
14247836SJohn.Forte@Sun.COM  * RETURN VALUES:
14257836SJohn.Forte@Sun.COM  *	0 on Success
14267836SJohn.Forte@Sun.COM  *	Non-zero on error
14277836SJohn.Forte@Sun.COM  */
14287836SJohn.Forte@Sun.COM static int
get_fca_inq_dtype(char * fcapath,la_wwn_t pwwn,uchar_t * inq_dtype)14297836SJohn.Forte@Sun.COM get_fca_inq_dtype(char *fcapath, la_wwn_t pwwn, uchar_t *inq_dtype)
14307836SJohn.Forte@Sun.COM {
14317836SJohn.Forte@Sun.COM 	int			dev_type, fd;
14327836SJohn.Forte@Sun.COM 	int			err, fcp_fd;
14337836SJohn.Forte@Sun.COM 	struct fcp_ioctl	fcp_data;
14347836SJohn.Forte@Sun.COM 	struct device_data	inq_data;
14357836SJohn.Forte@Sun.COM 	struct stat		sbuf;
14367836SJohn.Forte@Sun.COM 
14377836SJohn.Forte@Sun.COM 	dev_type = g_get_path_type(fcapath);
14387836SJohn.Forte@Sun.COM 	if ((dev_type == 0) || !(dev_type & FC_GEN_XPORT)) {
14397836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
14407836SJohn.Forte@Sun.COM 	}
14417836SJohn.Forte@Sun.COM 
14427836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(fcapath, O_NDELAY | O_RDONLY)) == -1) {
14437836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
14447836SJohn.Forte@Sun.COM 	}
14457836SJohn.Forte@Sun.COM 
14467836SJohn.Forte@Sun.COM 	if (fstat(fd, &sbuf) == -1) {
14477836SJohn.Forte@Sun.COM 		(void) close(fd);
14487836SJohn.Forte@Sun.COM 		return (L_FSTAT_ERROR);
14497836SJohn.Forte@Sun.COM 	}
14507836SJohn.Forte@Sun.COM 
14517836SJohn.Forte@Sun.COM 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
14527836SJohn.Forte@Sun.COM 		(void) close(fd);
14537836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
14547836SJohn.Forte@Sun.COM 	}
14557836SJohn.Forte@Sun.COM 
14567836SJohn.Forte@Sun.COM 	/* Get the minor number for an fp instance */
14577836SJohn.Forte@Sun.COM 	fcp_data.fp_minor = minor(sbuf.st_rdev);
14587836SJohn.Forte@Sun.COM 
14597836SJohn.Forte@Sun.COM 	fcp_data.listlen = 1;
14607836SJohn.Forte@Sun.COM 	inq_data.dev_pwwn = pwwn;	/* The port WWN as passed */
14617836SJohn.Forte@Sun.COM 	fcp_data.list = (caddr_t)&inq_data;
14627836SJohn.Forte@Sun.COM 
14637836SJohn.Forte@Sun.COM 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
14647836SJohn.Forte@Sun.COM 		close(fd);
14657836SJohn.Forte@Sun.COM 		close(fcp_fd);
14667836SJohn.Forte@Sun.COM 		return (err);
14677836SJohn.Forte@Sun.COM 	}
14687836SJohn.Forte@Sun.COM 	*inq_dtype = inq_data.dev0_type;
14697836SJohn.Forte@Sun.COM 
14707836SJohn.Forte@Sun.COM 	close(fd);
14717836SJohn.Forte@Sun.COM 	close(fcp_fd);
14727836SJohn.Forte@Sun.COM 
14737836SJohn.Forte@Sun.COM 	return (0);
14747836SJohn.Forte@Sun.COM }
14757836SJohn.Forte@Sun.COM 
14767836SJohn.Forte@Sun.COM /*
14777836SJohn.Forte@Sun.COM  * This function returns the traditional g_get_dev_map. Device list
14787836SJohn.Forte@Sun.COM  * and local hba seperate.
14797836SJohn.Forte@Sun.COM  */
14807836SJohn.Forte@Sun.COM int
g_get_dev_map(char * path,gfc_map_t * map_ptr,int verbose)14817836SJohn.Forte@Sun.COM g_get_dev_map(char *path, gfc_map_t *map_ptr, int verbose)
14827836SJohn.Forte@Sun.COM {
14837836SJohn.Forte@Sun.COM 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_STANDARD));
14847836SJohn.Forte@Sun.COM }
14857836SJohn.Forte@Sun.COM 
14867836SJohn.Forte@Sun.COM /*
14877836SJohn.Forte@Sun.COM  * This function returns the device map with local hba in physical
14887836SJohn.Forte@Sun.COM  * order.  Note: Physical order is only returned properly for
14897836SJohn.Forte@Sun.COM  * private loop. local hba is also included seperate
14907836SJohn.Forte@Sun.COM  */
14917836SJohn.Forte@Sun.COM int
g_get_lilp_map(char * path,gfc_map_t * map_ptr,int verbose)14927836SJohn.Forte@Sun.COM g_get_lilp_map(char *path, gfc_map_t *map_ptr, int verbose)
14937836SJohn.Forte@Sun.COM {
14947836SJohn.Forte@Sun.COM 	return (create_map(path, map_ptr, verbose, MAP_FORMAT_LILP));
14957836SJohn.Forte@Sun.COM }
14967836SJohn.Forte@Sun.COM 
14977836SJohn.Forte@Sun.COM /*
14987836SJohn.Forte@Sun.COM  * Gets device map from nexus driver
14997836SJohn.Forte@Sun.COM  *
15007836SJohn.Forte@Sun.COM  * PARAMS:
15017836SJohn.Forte@Sun.COM  *	path -	must be the physical path to a device
15027836SJohn.Forte@Sun.COM  *	map  -	loop map returned from fc port.
15037836SJohn.Forte@Sun.COM  *	verbose - options.
15047836SJohn.Forte@Sun.COM  *
15057836SJohn.Forte@Sun.COM  * LOGIC:
15067836SJohn.Forte@Sun.COM  *	1. check the validity of path via g_get_path_type.
15077836SJohn.Forte@Sun.COM  *	2. If FC path, get the topology of the path via
15087836SJohn.Forte@Sun.COM  *		g_get_fca_port_topology.
15097836SJohn.Forte@Sun.COM  *
15107836SJohn.Forte@Sun.COM  *	3. If FC type(Leadville statck)
15117836SJohn.Forte@Sun.COM  *		g_get_dev_list to get the device node list of fc_port_dev_t.
15127836SJohn.Forte@Sun.COM  *		g_get_host_params to get the fca port node of fc_port_dev_t.
15137836SJohn.Forte@Sun.COM  *
15147836SJohn.Forte@Sun.COM  *		Case of fabric or public loop topology
15157836SJohn.Forte@Sun.COM  *			Check if the port id > 0xffff.
15167836SJohn.Forte@Sun.COM  *			Move device node and fca port node to
15177836SJohn.Forte@Sun.COM  *			gfc_map structure via gfc_port_dev_info_t
15187836SJohn.Forte@Sun.COM  *			pub_port union.
15197836SJohn.Forte@Sun.COM  *			Issue g_get_inq_dtype to get FCP inquiry data
15207836SJohn.Forte@Sun.COM  *			and store it into gfc_port_dev_info_t.
15217836SJohn.Forte@Sun.COM  *
15227836SJohn.Forte@Sun.COM  *		Case of private loop topology
15237836SJohn.Forte@Sun.COM  *			Check if the port id < 0xff.
15247836SJohn.Forte@Sun.COM  *			Move device node and fca port node to
15257836SJohn.Forte@Sun.COM  *			gfc_map structure via gfc_port_dev_info_t
15267836SJohn.Forte@Sun.COM  *			priv_port union.
15277836SJohn.Forte@Sun.COM  *			Issue g_get_inq_dtype to get FCP inquiry data
15287836SJohn.Forte@Sun.COM  *			and store it into gfc_port_dev_info_t.
15297836SJohn.Forte@Sun.COM  *
15307836SJohn.Forte@Sun.COM  *	   else FC4 type(socal/sf or ifp stack)
15317836SJohn.Forte@Sun.COM  *		SFIOCGMAP ioctl to get the device and hba nodes of
15327836SJohn.Forte@Sun.COM  *			sf_addr_pair_t.
15337836SJohn.Forte@Sun.COM  *
15347836SJohn.Forte@Sun.COM  *
15357836SJohn.Forte@Sun.COM  * RETURNS:
15367836SJohn.Forte@Sun.COM  *	0	: if OK
15377836SJohn.Forte@Sun.COM  *	non-zero: otherwise
15387836SJohn.Forte@Sun.COM  */
15397836SJohn.Forte@Sun.COM int
create_map(char * path,gfc_map_t * map_ptr,int verbose,int map_type)15407836SJohn.Forte@Sun.COM create_map(char *path, gfc_map_t *map_ptr, int verbose, int map_type)
15417836SJohn.Forte@Sun.COM {
1542*11547SBill.Gumbrell@Sun.COM 	int		fd, i, j, num_devices = 0, err, pathcnt = 1;
1543*11547SBill.Gumbrell@Sun.COM 	char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
1544*11547SBill.Gumbrell@Sun.COM 	char		*char_ptr;
1545*11547SBill.Gumbrell@Sun.COM 	struct stat	stbuf;
1546*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	*dev_list, *dlistptr;
1547*11547SBill.Gumbrell@Sun.COM 	uint32_t	hba_port_top = 0;
1548*11547SBill.Gumbrell@Sun.COM 	uint_t		dev_type;
1549*11547SBill.Gumbrell@Sun.COM 	sf_al_map_t	sf_map;
1550*11547SBill.Gumbrell@Sun.COM 	gfc_port_dev_info_t	*dev_ptr;
1551*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	fp_hba_port;
1552*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
1553*11547SBill.Gumbrell@Sun.COM 	int		p_on = 0, p_st = 0;
15547836SJohn.Forte@Sun.COM 
15557836SJohn.Forte@Sun.COM 	/* return invalid path if path is NULL */
15567836SJohn.Forte@Sun.COM 	if (path == NULL) {
15577836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
15587836SJohn.Forte@Sun.COM 	}
15597836SJohn.Forte@Sun.COM 	/* return invalid arg if map_ptr is NULL */
15607836SJohn.Forte@Sun.COM 	if (map_ptr == NULL) {
15617836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
15627836SJohn.Forte@Sun.COM 	}
15637836SJohn.Forte@Sun.COM 
15647836SJohn.Forte@Sun.COM 	map_ptr->dev_addr = NULL;
15657836SJohn.Forte@Sun.COM 	map_ptr->count = 0;
15667836SJohn.Forte@Sun.COM 	(void) strcpy(drvr_path, path);
15677836SJohn.Forte@Sun.COM 	/*
15687836SJohn.Forte@Sun.COM 	 * Get the path to the :devctl driver
15697836SJohn.Forte@Sun.COM 	 *
15707836SJohn.Forte@Sun.COM 	 * This assumes the path looks something like this:
15717836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
15727836SJohn.Forte@Sun.COM 	 * or
15737836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
15747836SJohn.Forte@Sun.COM 	 * or
15757836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
15767836SJohn.Forte@Sun.COM 	 * or
15777836SJohn.Forte@Sun.COM 	 * a 1 level PCI type driver but still :devctl
15787836SJohn.Forte@Sun.COM 	 */
15797836SJohn.Forte@Sun.COM 	if (strstr(path, SCSI_VHCI)) {
15807836SJohn.Forte@Sun.COM 		(void) strcpy(drvr_path0, path);
15817836SJohn.Forte@Sun.COM 		if (g_get_pathlist(drvr_path0, &pathlist)) {
15827836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
15837836SJohn.Forte@Sun.COM 		}
15847836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
15857836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
15867836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
15877836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
15887836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
1589*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_ONLINE) {
15907836SJohn.Forte@Sun.COM 					p_on = i;
15917836SJohn.Forte@Sun.COM 					break;
15927836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
1593*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_STANDBY) {
15947836SJohn.Forte@Sun.COM 					p_st = i;
15957836SJohn.Forte@Sun.COM 				}
15967836SJohn.Forte@Sun.COM 			}
15977836SJohn.Forte@Sun.COM 		}
15987836SJohn.Forte@Sun.COM 		if (pathlist.path_info[p_on].path_state ==
15997836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
16007836SJohn.Forte@Sun.COM 			/* on_line path */
16017836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
1602*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_hba);
16037836SJohn.Forte@Sun.COM 		} else {
16047836SJohn.Forte@Sun.COM 			/* standby or path0 */
16057836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
1606*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_hba);
16077836SJohn.Forte@Sun.COM 		}
16087836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
16097836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, FC_CTLR);
16107836SJohn.Forte@Sun.COM 	} else {
16117836SJohn.Forte@Sun.COM 		(void) strcpy(drvr_path, path);
16127836SJohn.Forte@Sun.COM 		if (strstr(drvr_path, DRV_NAME_SSD) ||
1613*11547SBill.Gumbrell@Sun.COM 		    strstr(drvr_path, SES_NAME) ||
1614*11547SBill.Gumbrell@Sun.COM 		    strstr(drvr_path, DRV_NAME_ST)) {
16157836SJohn.Forte@Sun.COM 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
16167836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
16177836SJohn.Forte@Sun.COM 			}
16187836SJohn.Forte@Sun.COM 			*char_ptr = '\0';   /* Terminate sting  */
16197836SJohn.Forte@Sun.COM 			/* append controller */
16207836SJohn.Forte@Sun.COM 			(void) strcat(drvr_path, FC_CTLR);
16217836SJohn.Forte@Sun.COM 		} else {
16227836SJohn.Forte@Sun.COM 			if (stat(drvr_path, &stbuf) < 0) {
16237836SJohn.Forte@Sun.COM 				return (L_LSTAT_ERROR);
16247836SJohn.Forte@Sun.COM 			}
16257836SJohn.Forte@Sun.COM 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
16267836SJohn.Forte@Sun.COM 				/* append controller */
16277836SJohn.Forte@Sun.COM 				(void) strcat(drvr_path, FC_CTLR);
16287836SJohn.Forte@Sun.COM 			}
16297836SJohn.Forte@Sun.COM 		}
16307836SJohn.Forte@Sun.COM 	}
16317836SJohn.Forte@Sun.COM 
16327836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_dev_map: Geting drive map from:"
1633*11547SBill.Gumbrell@Sun.COM 	    " %s\n", drvr_path);
16347836SJohn.Forte@Sun.COM 
16357836SJohn.Forte@Sun.COM 	dev_type = g_get_path_type(drvr_path);
16367836SJohn.Forte@Sun.COM 	if ((dev_type == 0) || !(dev_type & XPORT_MASK)) {
16377836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
16387836SJohn.Forte@Sun.COM 	}
16397836SJohn.Forte@Sun.COM 
16407836SJohn.Forte@Sun.COM 	/* get fiber topology */
16417836SJohn.Forte@Sun.COM 	if ((err = g_get_fca_port_topology(drvr_path,
1642*11547SBill.Gumbrell@Sun.COM 	    &hba_port_top, verbose)) != 0) {
16437836SJohn.Forte@Sun.COM 		return (err);
16447836SJohn.Forte@Sun.COM 	}
16457836SJohn.Forte@Sun.COM 
16467836SJohn.Forte@Sun.COM 	/* for FC devices. */
16477836SJohn.Forte@Sun.COM 	if (dev_type & FC_FCA_MASK) {
16487836SJohn.Forte@Sun.COM 		/*
16497836SJohn.Forte@Sun.COM 		 * if g_get_dev_list fails with L_NO_DEVICES_FOUND
16507836SJohn.Forte@Sun.COM 		 * we still want to call g_get_host_params to try to find the
16517836SJohn.Forte@Sun.COM 		 * HBA.  If we do not see any HBAs on the loop, the
16527836SJohn.Forte@Sun.COM 		 * g_get_host_params will fail when it trys to issue the target
16537836SJohn.Forte@Sun.COM 		 * inquiry ioctl.  In this case, we would still like to return
16547836SJohn.Forte@Sun.COM 		 * L_NO_DEVICES_FOUND.
16557836SJohn.Forte@Sun.COM 		 *
16567836SJohn.Forte@Sun.COM 		 * If g_get_dev_list fails with L_NO_DEVICES_FOUND and
16577836SJohn.Forte@Sun.COM 		 * g_get_host_params fails, the function returns
16587836SJohn.Forte@Sun.COM 		 * L_NO_DEVICES_FOUND
16597836SJohn.Forte@Sun.COM 		 */
16607836SJohn.Forte@Sun.COM 		if ((err = g_get_dev_list(drvr_path, &dev_list,
1661*11547SBill.Gumbrell@Sun.COM 		    &num_devices)) != 0) {
16627836SJohn.Forte@Sun.COM 			/*
16637836SJohn.Forte@Sun.COM 			 * g_get_dev_map doesn't allow ulp failure
16647836SJohn.Forte@Sun.COM 			 * to continue thus we need to free dev_list
16657836SJohn.Forte@Sun.COM 			 * here.
16667836SJohn.Forte@Sun.COM 			 */
16677836SJohn.Forte@Sun.COM 			if (err == L_GET_DEV_LIST_ULP_FAILURE) {
16687836SJohn.Forte@Sun.COM 				(void) free(dev_list);
16697836SJohn.Forte@Sun.COM 			}
16707836SJohn.Forte@Sun.COM 			if (err != L_NO_DEVICES_FOUND) {
16717836SJohn.Forte@Sun.COM 				return (err);
16727836SJohn.Forte@Sun.COM 			}
16737836SJohn.Forte@Sun.COM 		}
16747836SJohn.Forte@Sun.COM 
16757836SJohn.Forte@Sun.COM 		/* Get local HBA information */
16767836SJohn.Forte@Sun.COM 		if ((err = g_get_host_params(drvr_path, &fp_hba_port,
1677*11547SBill.Gumbrell@Sun.COM 		    verbose)) != 0) {
16787836SJohn.Forte@Sun.COM 			(void) free(dev_list);
16797836SJohn.Forte@Sun.COM 			if (num_devices == 0)
16807836SJohn.Forte@Sun.COM 				return (L_NO_DEVICES_FOUND);
16817836SJohn.Forte@Sun.COM 			else
16827836SJohn.Forte@Sun.COM 				return (err);
16837836SJohn.Forte@Sun.COM 		}
16847836SJohn.Forte@Sun.COM 
16857836SJohn.Forte@Sun.COM 		/* If devices, other than local HBA are found	*/
16867836SJohn.Forte@Sun.COM 		/* allocate space for them in the gfc_map.	*/
16877836SJohn.Forte@Sun.COM 		if (num_devices > 0) {
16887836SJohn.Forte@Sun.COM 
16897836SJohn.Forte@Sun.COM 			/* If map type is on MAP_FORMAT_LILP we need	*/
16907836SJohn.Forte@Sun.COM 			/* to add space for the local HBA		*/
16917836SJohn.Forte@Sun.COM 			if (map_type == MAP_FORMAT_LILP) {
16927836SJohn.Forte@Sun.COM 				map_ptr->count = ++num_devices;
16937836SJohn.Forte@Sun.COM 			} else {
16947836SJohn.Forte@Sun.COM 				map_ptr->count = num_devices;
16957836SJohn.Forte@Sun.COM 			}
16967836SJohn.Forte@Sun.COM 
16977836SJohn.Forte@Sun.COM 			if ((map_ptr->dev_addr = (gfc_port_dev_info_t *)
16987836SJohn.Forte@Sun.COM 			    calloc(map_ptr->count,
1699*11547SBill.Gumbrell@Sun.COM 			    sizeof (gfc_port_dev_info_t))) == NULL) {
1700*11547SBill.Gumbrell@Sun.COM 				(void) free(dev_list);
1701*11547SBill.Gumbrell@Sun.COM 				return (L_MALLOC_FAILED);
17027836SJohn.Forte@Sun.COM 			}
17037836SJohn.Forte@Sun.COM 		}
17047836SJohn.Forte@Sun.COM 
17057836SJohn.Forte@Sun.COM 		/* If we want the lilp map then we need to do a little	*/
17067836SJohn.Forte@Sun.COM 		/* work here.  The lilp map contains the local hba in	*/
17077836SJohn.Forte@Sun.COM 		/* the dev_addr.  Once this has been added qsort the	*/
17087836SJohn.Forte@Sun.COM 		/* dev_addr array so it's in physical order.		*/
17097836SJohn.Forte@Sun.COM 		/* The lilp map will contain the local hba in the	*/
17107836SJohn.Forte@Sun.COM 		/* dev_addr array only when num_devices > 0		*/
17117836SJohn.Forte@Sun.COM 		if (map_type == MAP_FORMAT_LILP && num_devices > 0) {
17127836SJohn.Forte@Sun.COM 
17137836SJohn.Forte@Sun.COM 			/* First we need to allocate one additional	*/
17147836SJohn.Forte@Sun.COM 			/* device to the dev_addr structure, for the 	*/
17157836SJohn.Forte@Sun.COM 			/* local hba					*/
17167836SJohn.Forte@Sun.COM 			if ((dev_list = (fc_port_dev_t *)realloc(dev_list,
1717*11547SBill.Gumbrell@Sun.COM 			    (num_devices * sizeof (fc_port_dev_t))))
1718*11547SBill.Gumbrell@Sun.COM 			    == NULL) {
17197836SJohn.Forte@Sun.COM 				S_FREE(dev_list);
17207836SJohn.Forte@Sun.COM 				(void) free(map_ptr->dev_addr);
17217836SJohn.Forte@Sun.COM 				map_ptr->dev_addr = NULL;
17227836SJohn.Forte@Sun.COM 				return (L_MALLOC_FAILED);
17237836SJohn.Forte@Sun.COM 			}
17247836SJohn.Forte@Sun.COM 
17257836SJohn.Forte@Sun.COM 			/* Next, copy the local hba into this new loc.	*/
17267836SJohn.Forte@Sun.COM 			if (memcpy(dev_list+(num_devices-1), &fp_hba_port,
1727*11547SBill.Gumbrell@Sun.COM 			    sizeof (fc_port_dev_t)) == NULL) {
17287836SJohn.Forte@Sun.COM 				(void) free(dev_list);
17297836SJohn.Forte@Sun.COM 				(void) free(map_ptr->dev_addr);
17307836SJohn.Forte@Sun.COM 				map_ptr->dev_addr = NULL;
17317836SJohn.Forte@Sun.COM 				return (L_MEMCPY_FAILED);
17327836SJohn.Forte@Sun.COM 			}
17337836SJohn.Forte@Sun.COM 
17347836SJohn.Forte@Sun.COM 			/* Now sort by physical location		*/
17357836SJohn.Forte@Sun.COM 			qsort((void*)dev_list, num_devices,
1736*11547SBill.Gumbrell@Sun.COM 			    sizeof (fc_port_dev_t), lilp_map_cmp);
17377836SJohn.Forte@Sun.COM 		}
17387836SJohn.Forte@Sun.COM 
17397836SJohn.Forte@Sun.COM 		dlistptr = dev_list;
17407836SJohn.Forte@Sun.COM 		dev_ptr = map_ptr->dev_addr;
17417836SJohn.Forte@Sun.COM 
17427836SJohn.Forte@Sun.COM 		switch (hba_port_top) {
17437836SJohn.Forte@Sun.COM 		case FC_TOP_FABRIC:
17447836SJohn.Forte@Sun.COM 		case FC_TOP_PUBLIC_LOOP:
17457836SJohn.Forte@Sun.COM 			if (fp_hba_port.dev_did.port_id <= 0xffff) {
17467836SJohn.Forte@Sun.COM 				(void) free(dlistptr);
17477836SJohn.Forte@Sun.COM 				(void) free(map_ptr->dev_addr);
17487836SJohn.Forte@Sun.COM 				map_ptr->dev_addr = NULL;
17497836SJohn.Forte@Sun.COM 				return (L_INVALID_FABRIC_ADDRESS);
17507836SJohn.Forte@Sun.COM 			} else {
17517836SJohn.Forte@Sun.COM 				map_ptr->hba_addr.port_topology = hba_port_top;
17527836SJohn.Forte@Sun.COM 				map_ptr->hba_addr.gfc_port_dev.pub_port =
1753*11547SBill.Gumbrell@Sun.COM 				    fp_hba_port;
17547836SJohn.Forte@Sun.COM 			}
17557836SJohn.Forte@Sun.COM 			for (i = 0; i < num_devices; i++, dev_ptr++,
1756*11547SBill.Gumbrell@Sun.COM 			    dev_list++) {
17577836SJohn.Forte@Sun.COM 				if (dev_list->dev_did.port_id <= 0xffff) {
17587836SJohn.Forte@Sun.COM 					(void) free(dlistptr);
17597836SJohn.Forte@Sun.COM 					(void) free(map_ptr->dev_addr);
17607836SJohn.Forte@Sun.COM 					map_ptr->dev_addr = NULL;
17617836SJohn.Forte@Sun.COM 					return (L_INVALID_FABRIC_ADDRESS);
17627836SJohn.Forte@Sun.COM 				} else {
17637836SJohn.Forte@Sun.COM 					dev_ptr->port_topology = hba_port_top;
17647836SJohn.Forte@Sun.COM 					dev_ptr->gfc_port_dev.pub_port =
1765*11547SBill.Gumbrell@Sun.COM 					    *dev_list;
17667836SJohn.Forte@Sun.COM 				}
17677836SJohn.Forte@Sun.COM 			}
17687836SJohn.Forte@Sun.COM 			break;
17697836SJohn.Forte@Sun.COM 		case FC_TOP_PRIVATE_LOOP:
17707836SJohn.Forte@Sun.COM 			/*
17717836SJohn.Forte@Sun.COM 			 * Map the (new->old) structures here.
17727836SJohn.Forte@Sun.COM 			 * Checking (i < SF_NUM_ENTRIES_IN_MAP) just to
17737836SJohn.Forte@Sun.COM 			 * make sure that we don't overrun the map structure
17747836SJohn.Forte@Sun.COM 			 * since it can hold data for upto 126 devices.
17757836SJohn.Forte@Sun.COM 			 */
17767836SJohn.Forte@Sun.COM 			if (fp_hba_port.dev_did.port_id > 0xff) {
17777836SJohn.Forte@Sun.COM 				(void) free(dlistptr);
17787836SJohn.Forte@Sun.COM 				(void) free(map_ptr->dev_addr);
17797836SJohn.Forte@Sun.COM 				map_ptr->dev_addr = NULL;
17807836SJohn.Forte@Sun.COM 				return (L_INVALID_PRIVATE_LOOP_ADDRESS);
17817836SJohn.Forte@Sun.COM 			} else {
17827836SJohn.Forte@Sun.COM 				map_ptr->hba_addr.port_topology = hba_port_top;
17837836SJohn.Forte@Sun.COM 				map_ptr->hba_addr.gfc_port_dev.
1784*11547SBill.Gumbrell@Sun.COM 				    priv_port.sf_al_pa =
1785*11547SBill.Gumbrell@Sun.COM 				    (uchar_t)fp_hba_port.dev_did.port_id;
17867836SJohn.Forte@Sun.COM 				map_ptr->hba_addr.gfc_port_dev.
1787*11547SBill.Gumbrell@Sun.COM 				    priv_port.sf_hard_address = (uchar_t)
1788*11547SBill.Gumbrell@Sun.COM 				    fp_hba_port.dev_hard_addr.hard_addr;
17897836SJohn.Forte@Sun.COM 				for (j = 0; j < FC_WWN_SIZE; j++) {
17907836SJohn.Forte@Sun.COM 					map_ptr->hba_addr.gfc_port_dev.
1791*11547SBill.Gumbrell@Sun.COM 					    priv_port.sf_node_wwn[j] =
1792*11547SBill.Gumbrell@Sun.COM 					    fp_hba_port.dev_nwwn.raw_wwn[j];
17937836SJohn.Forte@Sun.COM 					map_ptr->hba_addr.gfc_port_dev.
1794*11547SBill.Gumbrell@Sun.COM 					    priv_port.sf_port_wwn[j] =
1795*11547SBill.Gumbrell@Sun.COM 					    fp_hba_port.dev_pwwn.raw_wwn[j];
17967836SJohn.Forte@Sun.COM 				}
17977836SJohn.Forte@Sun.COM 				map_ptr->hba_addr.gfc_port_dev.
1798*11547SBill.Gumbrell@Sun.COM 				    priv_port.sf_inq_dtype =
1799*11547SBill.Gumbrell@Sun.COM 				    fp_hba_port.dev_dtype;
18007836SJohn.Forte@Sun.COM 			}
18017836SJohn.Forte@Sun.COM 
18027836SJohn.Forte@Sun.COM 			for (i = 0; (i < num_devices &&
1803*11547SBill.Gumbrell@Sun.COM 			    i < SF_NUM_ENTRIES_IN_MAP);
1804*11547SBill.Gumbrell@Sun.COM 			    i++, dev_ptr++, dev_list++) {
18057836SJohn.Forte@Sun.COM 				/*
18067836SJohn.Forte@Sun.COM 				 * Out of 24 bits of port_id, copy only
18077836SJohn.Forte@Sun.COM 				 * 8 bits to al_pa. This works okay for
18087836SJohn.Forte@Sun.COM 				 * devices that're on a private loop.
18097836SJohn.Forte@Sun.COM 				 */
18107836SJohn.Forte@Sun.COM 				if (dev_list->dev_did.port_id > 0xff) {
18117836SJohn.Forte@Sun.COM 					(void) free(dlistptr);
18127836SJohn.Forte@Sun.COM 					(void) free(map_ptr->dev_addr);
18137836SJohn.Forte@Sun.COM 					map_ptr->dev_addr = NULL;
18147836SJohn.Forte@Sun.COM 					return (L_INVALID_PRIVATE_LOOP_ADDRESS);
18157836SJohn.Forte@Sun.COM 				}
18167836SJohn.Forte@Sun.COM 				dev_ptr->port_topology = hba_port_top;
18177836SJohn.Forte@Sun.COM 				dev_ptr->gfc_port_dev.priv_port.sf_al_pa
1818*11547SBill.Gumbrell@Sun.COM 				    = (uchar_t)dev_list->dev_did.port_id;
1819*11547SBill.Gumbrell@Sun.COM 
1820*11547SBill.Gumbrell@Sun.COM 			/* Code refactorization is needed for C style */
1821*11547SBill.Gumbrell@Sun.COM 			dev_ptr->gfc_port_dev.priv_port.sf_hard_address
1822*11547SBill.Gumbrell@Sun.COM 			    = (uchar_t)dev_list->dev_hard_addr.hard_addr;
1823*11547SBill.Gumbrell@Sun.COM 
18247836SJohn.Forte@Sun.COM 				for (j = 0; j < FC_WWN_SIZE; j++) {
1825*11547SBill.Gumbrell@Sun.COM 
1826*11547SBill.Gumbrell@Sun.COM 			dev_ptr->gfc_port_dev.priv_port.sf_node_wwn[j] =
1827*11547SBill.Gumbrell@Sun.COM 			    dev_list->dev_nwwn.raw_wwn[j];
1828*11547SBill.Gumbrell@Sun.COM 			dev_ptr->gfc_port_dev.priv_port.sf_port_wwn[j] =
1829*11547SBill.Gumbrell@Sun.COM 			    dev_list->dev_pwwn.raw_wwn[j];
1830*11547SBill.Gumbrell@Sun.COM 
18317836SJohn.Forte@Sun.COM 				}
18327836SJohn.Forte@Sun.COM 				dev_ptr->gfc_port_dev.priv_port.sf_inq_dtype =
1833*11547SBill.Gumbrell@Sun.COM 				    dev_list->dev_dtype;
18347836SJohn.Forte@Sun.COM 			}
18357836SJohn.Forte@Sun.COM 			break;
18367836SJohn.Forte@Sun.COM 		case FC_TOP_PT_PT:
18377836SJohn.Forte@Sun.COM 			(void) free(dlistptr);
18387836SJohn.Forte@Sun.COM 			(void) free(map_ptr->dev_addr);
18397836SJohn.Forte@Sun.COM 			map_ptr->dev_addr = NULL;
18407836SJohn.Forte@Sun.COM 			return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
18417836SJohn.Forte@Sun.COM 		default:
18427836SJohn.Forte@Sun.COM 			(void) free(dlistptr);
18437836SJohn.Forte@Sun.COM 			(void) free(map_ptr->dev_addr);
18447836SJohn.Forte@Sun.COM 			map_ptr->dev_addr = NULL;
18457836SJohn.Forte@Sun.COM 			return (L_UNEXPECTED_FC_TOPOLOGY);
18467836SJohn.Forte@Sun.COM 		}	/* End of switch on port_topology */
18477836SJohn.Forte@Sun.COM 		(void) free(dlistptr);
18487836SJohn.Forte@Sun.COM 
18497836SJohn.Forte@Sun.COM 	} else {	/* sf and fc4/pci devices */
18507836SJohn.Forte@Sun.COM 		if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
18517836SJohn.Forte@Sun.COM 			return (errno);
18527836SJohn.Forte@Sun.COM 		/* initialize map */
18537836SJohn.Forte@Sun.COM 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
18547836SJohn.Forte@Sun.COM 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
18557836SJohn.Forte@Sun.COM 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
18567836SJohn.Forte@Sun.COM 			(void) close(fd);
18577836SJohn.Forte@Sun.COM 			return (L_SFIOCGMAP_IOCTL_FAIL);
18587836SJohn.Forte@Sun.COM 		}
18597836SJohn.Forte@Sun.COM 		/* Check for reasonableness. */
18607836SJohn.Forte@Sun.COM 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
18617836SJohn.Forte@Sun.COM 			(void) close(fd);
18627836SJohn.Forte@Sun.COM 			return (L_INVALID_LOOP_MAP);
18637836SJohn.Forte@Sun.COM 		}
18647836SJohn.Forte@Sun.COM 		if (sf_map.sf_count == 0) {
18657836SJohn.Forte@Sun.COM 			(void) close(fd);
18667836SJohn.Forte@Sun.COM 			return (L_NO_DEVICES_FOUND);
18677836SJohn.Forte@Sun.COM 		}
18687836SJohn.Forte@Sun.COM 
18697836SJohn.Forte@Sun.COM 		map_ptr->count = sf_map.sf_count;
18707836SJohn.Forte@Sun.COM 		if ((map_ptr->dev_addr =
1871*11547SBill.Gumbrell@Sun.COM 		    (gfc_port_dev_info_t *)calloc(map_ptr->count,
1872*11547SBill.Gumbrell@Sun.COM 		    sizeof (gfc_port_dev_info_t))) == NULL) {
18737836SJohn.Forte@Sun.COM 			(void) close(fd);
18747836SJohn.Forte@Sun.COM 			return (L_MALLOC_FAILED);
18757836SJohn.Forte@Sun.COM 		}
18767836SJohn.Forte@Sun.COM 		dev_ptr = map_ptr->dev_addr;
18777836SJohn.Forte@Sun.COM 		for (i = 0; i < sf_map.sf_count; i++, dev_ptr++) {
18787836SJohn.Forte@Sun.COM 			if (sf_map.sf_addr_pair[i].sf_al_pa > 0xef) {
18797836SJohn.Forte@Sun.COM 				(void) free(map_ptr->dev_addr);
18807836SJohn.Forte@Sun.COM 				map_ptr->dev_addr = NULL;
18817836SJohn.Forte@Sun.COM 				(void) close(fd);
18827836SJohn.Forte@Sun.COM 				return (L_INVALID_LOOP_MAP);
18837836SJohn.Forte@Sun.COM 			}
18847836SJohn.Forte@Sun.COM 			dev_ptr->port_topology = hba_port_top;
18857836SJohn.Forte@Sun.COM 			dev_ptr->gfc_port_dev.priv_port =
1886*11547SBill.Gumbrell@Sun.COM 			    sf_map.sf_addr_pair[i];
18877836SJohn.Forte@Sun.COM 		}
18887836SJohn.Forte@Sun.COM 		map_ptr->hba_addr.port_topology = hba_port_top;
18897836SJohn.Forte@Sun.COM 		map_ptr->hba_addr.gfc_port_dev.priv_port =
1890*11547SBill.Gumbrell@Sun.COM 		    sf_map.sf_hba_addr;
18917836SJohn.Forte@Sun.COM 		(void) close(fd);
18927836SJohn.Forte@Sun.COM 	}
18937836SJohn.Forte@Sun.COM 
18947836SJohn.Forte@Sun.COM 	return (0);
18957836SJohn.Forte@Sun.COM }
18967836SJohn.Forte@Sun.COM 
18977836SJohn.Forte@Sun.COM /*
18987836SJohn.Forte@Sun.COM  * This function consturct FC proerty list using map_dev_fc_prop_list.
18997836SJohn.Forte@Sun.COM  *
19007836SJohn.Forte@Sun.COM  * port WWN, node WWN, port addr and hard addr properties is constructed.
19017836SJohn.Forte@Sun.COM  *
19027836SJohn.Forte@Sun.COM  * return 0 if OK.
19037836SJohn.Forte@Sun.COM  * otherwise returns error code.
19047836SJohn.Forte@Sun.COM  */
19057836SJohn.Forte@Sun.COM 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)1906*11547SBill.Gumbrell@Sun.COM update_map_dev_fc_prop(impl_map_dev_prop_t **prop_list, uint32_t map_topo,
1907*11547SBill.Gumbrell@Sun.COM     uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr)
19087836SJohn.Forte@Sun.COM {
19097836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t	*prop_ptr, *pl_start = NULL, *pl_end = NULL;
19107836SJohn.Forte@Sun.COM 	uchar_t *port_wwn_data, *node_wwn_data;
19117836SJohn.Forte@Sun.COM 	int *port_addr_data, *hard_addr_data;
19127836SJohn.Forte@Sun.COM 
19137836SJohn.Forte@Sun.COM 	/* consrtruct port addr property. */
1914*11547SBill.Gumbrell@Sun.COM 	if ((map_topo == FC_TOP_FABRIC) || (map_topo == FC_TOP_PUBLIC_LOOP)) {
19157836SJohn.Forte@Sun.COM 		if (port_addr <= 0xffff) {
1916*11547SBill.Gumbrell@Sun.COM 			return (L_INVALID_FABRIC_ADDRESS);
19177836SJohn.Forte@Sun.COM 		}
19187836SJohn.Forte@Sun.COM 	} else if (map_topo == FC_TOP_PRIVATE_LOOP) {
19197836SJohn.Forte@Sun.COM 		if (port_addr > 0xff) {
1920*11547SBill.Gumbrell@Sun.COM 			return (L_INVALID_PRIVATE_LOOP_ADDRESS);
19217836SJohn.Forte@Sun.COM 		}
19227836SJohn.Forte@Sun.COM 	}
19237836SJohn.Forte@Sun.COM 
19247836SJohn.Forte@Sun.COM 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1925*11547SBill.Gumbrell@Sun.COM 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
19267836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19277836SJohn.Forte@Sun.COM 	}
19287836SJohn.Forte@Sun.COM 	(void) strncpy(prop_ptr->prop_name, PORT_ADDR_PROP,
1929*11547SBill.Gumbrell@Sun.COM 	    strlen(PORT_ADDR_PROP));
19307836SJohn.Forte@Sun.COM 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
19317836SJohn.Forte@Sun.COM 
19327836SJohn.Forte@Sun.COM 	if ((port_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
19337836SJohn.Forte@Sun.COM 		free(prop_ptr);
19347836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19357836SJohn.Forte@Sun.COM 	}
19367836SJohn.Forte@Sun.COM 	*port_addr_data = port_addr;
19377836SJohn.Forte@Sun.COM 	prop_ptr->prop_data = port_addr_data;
19387836SJohn.Forte@Sun.COM 
19397836SJohn.Forte@Sun.COM 	pl_start = pl_end = prop_ptr;
19407836SJohn.Forte@Sun.COM 
19417836SJohn.Forte@Sun.COM 	/* consrtruct port WWN property. */
19427836SJohn.Forte@Sun.COM 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1943*11547SBill.Gumbrell@Sun.COM 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
19447836SJohn.Forte@Sun.COM 		free_prop_list(&pl_start);
19457836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19467836SJohn.Forte@Sun.COM 	}
19477836SJohn.Forte@Sun.COM 	(void) strncpy(prop_ptr->prop_name, PORT_WWN_PROP,
1948*11547SBill.Gumbrell@Sun.COM 	    strlen(PORT_WWN_PROP));
19497836SJohn.Forte@Sun.COM 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
19507836SJohn.Forte@Sun.COM 
1951*11547SBill.Gumbrell@Sun.COM 	if ((port_wwn_data = (uchar_t *)calloc(1, FC_WWN_SIZE)) == NULL) {
19527836SJohn.Forte@Sun.COM 		free_prop_list(&pl_start);
19537836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19547836SJohn.Forte@Sun.COM 	}
19557836SJohn.Forte@Sun.COM 	memcpy(port_wwn_data, port_wwn, FC_WWN_SIZE);
19567836SJohn.Forte@Sun.COM 	prop_ptr->prop_data = port_wwn_data;
19577836SJohn.Forte@Sun.COM 	prop_ptr->prop_size = FC_WWN_SIZE;
19587836SJohn.Forte@Sun.COM 	pl_end->next = prop_ptr;
19597836SJohn.Forte@Sun.COM 	pl_end = prop_ptr;
19607836SJohn.Forte@Sun.COM 
19617836SJohn.Forte@Sun.COM 	/* consrtruct node WWN property. */
19627836SJohn.Forte@Sun.COM 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1963*11547SBill.Gumbrell@Sun.COM 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
19647836SJohn.Forte@Sun.COM 		free_prop_list(&pl_start);
19657836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19667836SJohn.Forte@Sun.COM 	}
19677836SJohn.Forte@Sun.COM 	(void) strncpy(prop_ptr->prop_name, NODE_WWN_PROP,
1968*11547SBill.Gumbrell@Sun.COM 	    strlen(NODE_WWN_PROP));
19697836SJohn.Forte@Sun.COM 	prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
19707836SJohn.Forte@Sun.COM 
19717836SJohn.Forte@Sun.COM 	if ((node_wwn_data = (uchar_t *)calloc(
1972*11547SBill.Gumbrell@Sun.COM 	    1, FC_WWN_SIZE)) == NULL) {
19737836SJohn.Forte@Sun.COM 		free_prop_list(&pl_start);
19747836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19757836SJohn.Forte@Sun.COM 	}
19767836SJohn.Forte@Sun.COM 	memcpy(node_wwn_data, node_wwn, FC_WWN_SIZE);
19777836SJohn.Forte@Sun.COM 	prop_ptr->prop_data = node_wwn_data;
19787836SJohn.Forte@Sun.COM 	prop_ptr->prop_size = FC_WWN_SIZE;
19797836SJohn.Forte@Sun.COM 	pl_end->next = prop_ptr;
19807836SJohn.Forte@Sun.COM 	pl_end = prop_ptr;
19817836SJohn.Forte@Sun.COM 
19827836SJohn.Forte@Sun.COM 	/* consrtruct hard addr property. */
19837836SJohn.Forte@Sun.COM 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
1984*11547SBill.Gumbrell@Sun.COM 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
19857836SJohn.Forte@Sun.COM 		free_prop_list(&pl_start);
19867836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19877836SJohn.Forte@Sun.COM 	}
19887836SJohn.Forte@Sun.COM 	(void) strncpy(prop_ptr->prop_name, HARD_ADDR_PROP,
1989*11547SBill.Gumbrell@Sun.COM 	    strlen(HARD_ADDR_PROP));
19907836SJohn.Forte@Sun.COM 	prop_ptr->prop_type = GFC_PROP_TYPE_INT;
19917836SJohn.Forte@Sun.COM 
1992*11547SBill.Gumbrell@Sun.COM 	if ((hard_addr_data = (int *)calloc(1, sizeof (int))) == NULL) {
19937836SJohn.Forte@Sun.COM 		free_prop_list(&pl_start);
19947836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
19957836SJohn.Forte@Sun.COM 	}
19967836SJohn.Forte@Sun.COM 	*hard_addr_data = hard_addr;
19977836SJohn.Forte@Sun.COM 	prop_ptr->prop_data = hard_addr_data;
19987836SJohn.Forte@Sun.COM 	pl_end->next = prop_ptr;
19997836SJohn.Forte@Sun.COM 	pl_end = prop_ptr;
20007836SJohn.Forte@Sun.COM 
20017836SJohn.Forte@Sun.COM 	if (*prop_list == NULL) {
20027836SJohn.Forte@Sun.COM 		*prop_list = pl_start;
20037836SJohn.Forte@Sun.COM 	} else {
20047836SJohn.Forte@Sun.COM 		pl_end->next = (*prop_list)->next;
20057836SJohn.Forte@Sun.COM 		*prop_list = pl_start;
20067836SJohn.Forte@Sun.COM 	}
20077836SJohn.Forte@Sun.COM 
20087836SJohn.Forte@Sun.COM 	return (0);
20097836SJohn.Forte@Sun.COM }
20107836SJohn.Forte@Sun.COM 
20117836SJohn.Forte@Sun.COM /*
20127836SJohn.Forte@Sun.COM  * This function consturct FCP inq dtype propery.
20137836SJohn.Forte@Sun.COM  * if inq_dtype is null the property is constrcted with err info.
20147836SJohn.Forte@Sun.COM  *
20157836SJohn.Forte@Sun.COM  * L_MALLOC_FAILED is the only possible error.
20167836SJohn.Forte@Sun.COM  */
20177836SJohn.Forte@Sun.COM static int
update_map_dev_FCP_prop(impl_map_dev_prop_t ** prop_list,uchar_t * inq_dtype,int err,int exist)2018*11547SBill.Gumbrell@Sun.COM update_map_dev_FCP_prop(impl_map_dev_prop_t **prop_list,
2019*11547SBill.Gumbrell@Sun.COM     uchar_t *inq_dtype, int err, int exist)
20207836SJohn.Forte@Sun.COM {
20217836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t	*prop_ptr, *old_prop_ptr;
20227836SJohn.Forte@Sun.COM 	uchar_t *inq_dtype_data;
20237836SJohn.Forte@Sun.COM 
20247836SJohn.Forte@Sun.COM 	if ((prop_ptr = (impl_map_dev_prop_t *)calloc(
2025*11547SBill.Gumbrell@Sun.COM 	    1, sizeof (impl_map_dev_prop_t))) == NULL) {
20267836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
20277836SJohn.Forte@Sun.COM 	}
20287836SJohn.Forte@Sun.COM 
20297836SJohn.Forte@Sun.COM 	(void) strncpy(prop_ptr->prop_name, INQ_DTYPE_PROP,
2030*11547SBill.Gumbrell@Sun.COM 	    strlen(INQ_DTYPE_PROP));
20317836SJohn.Forte@Sun.COM 
20327836SJohn.Forte@Sun.COM 	if (inq_dtype == NULL) {
20337836SJohn.Forte@Sun.COM 		prop_ptr->prop_data = NULL;
20347836SJohn.Forte@Sun.COM 		prop_ptr->prop_error = err;
20357836SJohn.Forte@Sun.COM 	} else {
20367836SJohn.Forte@Sun.COM 		if ((inq_dtype_data = (uchar_t *)calloc(
2037*11547SBill.Gumbrell@Sun.COM 		    1, sizeof (uchar_t))) == NULL) {
20387836SJohn.Forte@Sun.COM 			free(prop_ptr);
20397836SJohn.Forte@Sun.COM 			return (L_MALLOC_FAILED);
20407836SJohn.Forte@Sun.COM 		}
20417836SJohn.Forte@Sun.COM 		memcpy(inq_dtype_data, inq_dtype, sizeof (uchar_t));
20427836SJohn.Forte@Sun.COM 		prop_ptr->prop_data = inq_dtype_data;
20437836SJohn.Forte@Sun.COM 		prop_ptr->prop_type = GFC_PROP_TYPE_BYTES;
20447836SJohn.Forte@Sun.COM 		prop_ptr->prop_size = sizeof (uchar_t);
20457836SJohn.Forte@Sun.COM 	}
20467836SJohn.Forte@Sun.COM 
20477836SJohn.Forte@Sun.COM 	if (*prop_list == NULL) {
20487836SJohn.Forte@Sun.COM 		*prop_list = prop_ptr;
20497836SJohn.Forte@Sun.COM 	} else {
20507836SJohn.Forte@Sun.COM 		if (exist == PROP_EXIST) {
20517836SJohn.Forte@Sun.COM 			prop_ptr->next = (*prop_list)->next;
20527836SJohn.Forte@Sun.COM 			old_prop_ptr = *prop_list;
20537836SJohn.Forte@Sun.COM 			*prop_list = prop_ptr;
20547836SJohn.Forte@Sun.COM 			free((uchar_t *)(old_prop_ptr->prop_data));
20557836SJohn.Forte@Sun.COM 			old_prop_ptr->prop_data = NULL;
20567836SJohn.Forte@Sun.COM 			S_FREE(old_prop_ptr);
20577836SJohn.Forte@Sun.COM 		} else {
20587836SJohn.Forte@Sun.COM 			prop_ptr->next = *prop_list;
20597836SJohn.Forte@Sun.COM 			*prop_list = prop_ptr;
20607836SJohn.Forte@Sun.COM 		}
20617836SJohn.Forte@Sun.COM 	}
20627836SJohn.Forte@Sun.COM 
20637836SJohn.Forte@Sun.COM 	return (0);
20647836SJohn.Forte@Sun.COM }
20657836SJohn.Forte@Sun.COM 
20667836SJohn.Forte@Sun.COM /*
20677836SJohn.Forte@Sun.COM  * This function calls FCP_TGT_INQUIRY via g_issue_fcp_ioctl()
20687836SJohn.Forte@Sun.COM  * to get the inq_dtype of input device and calls update_map_dev_FCP_prop().
20697836SJohn.Forte@Sun.COM  * inq_dtype is set to NULL and pass error code if inq_dtype data is not
20707836SJohn.Forte@Sun.COM  * requried.
20717836SJohn.Forte@Sun.COM  *
20727836SJohn.Forte@Sun.COM  * return error from update_map_dev_FCP_prop().
20737836SJohn.Forte@Sun.COM  */
20747836SJohn.Forte@Sun.COM static int
handle_map_dev_FCP_prop(minor_t fp_xport_minor,la_wwn_t port_wwn,impl_map_dev_prop_t ** prop_list)2075*11547SBill.Gumbrell@Sun.COM handle_map_dev_FCP_prop(minor_t fp_xport_minor, la_wwn_t port_wwn,
2076*11547SBill.Gumbrell@Sun.COM     impl_map_dev_prop_t **prop_list)
20777836SJohn.Forte@Sun.COM {
20787836SJohn.Forte@Sun.COM 	struct device_data	inq_data;
20797836SJohn.Forte@Sun.COM 	int 			fcp_fd, err;
20807836SJohn.Forte@Sun.COM 	struct fcp_ioctl	fcp_data;
20817836SJohn.Forte@Sun.COM 	uchar_t			inq_dtype;
20827836SJohn.Forte@Sun.COM 
20837836SJohn.Forte@Sun.COM 	if ((fcp_fd = g_object_open(FCP_PATH, O_RDONLY)) == -1) {
20847836SJohn.Forte@Sun.COM 		update_map_dev_FCP_prop(prop_list, NULL,
2085*11547SBill.Gumbrell@Sun.COM 		    L_OPEN_PATH_FAIL, PROP_NOEXIST);
20867836SJohn.Forte@Sun.COM 	}
20877836SJohn.Forte@Sun.COM 
20887836SJohn.Forte@Sun.COM 	/* Get the minor number for an fp instance */
20897836SJohn.Forte@Sun.COM 	fcp_data.fp_minor = fp_xport_minor;
20907836SJohn.Forte@Sun.COM 
20917836SJohn.Forte@Sun.COM 	/* Get FCP prop for the hba first. */
20927836SJohn.Forte@Sun.COM 	fcp_data.listlen = 1;
20937836SJohn.Forte@Sun.COM 	inq_data.dev_pwwn = port_wwn;
20947836SJohn.Forte@Sun.COM 	fcp_data.list = (caddr_t)&inq_data;
20957836SJohn.Forte@Sun.COM 
20967836SJohn.Forte@Sun.COM 	if (err = g_issue_fcp_ioctl(fcp_fd, &fcp_data, 0)) {
20977836SJohn.Forte@Sun.COM 		/* if ioctl error then set the prop_error.	*/
2098*11547SBill.Gumbrell@Sun.COM 		if ((err = update_map_dev_FCP_prop(
2099*11547SBill.Gumbrell@Sun.COM 		    prop_list, NULL, err, PROP_NOEXIST)) != 0) {
2100*11547SBill.Gumbrell@Sun.COM 			return (err);
2101*11547SBill.Gumbrell@Sun.COM 		}
21027836SJohn.Forte@Sun.COM 	} else {
2103*11547SBill.Gumbrell@Sun.COM 		inq_dtype = inq_data.dev0_type;
2104*11547SBill.Gumbrell@Sun.COM 		if ((err = update_map_dev_FCP_prop(
2105*11547SBill.Gumbrell@Sun.COM 		    prop_list, &inq_dtype, 0, PROP_NOEXIST)) != 0) {
2106*11547SBill.Gumbrell@Sun.COM 			return (err);
2107*11547SBill.Gumbrell@Sun.COM 		}
21087836SJohn.Forte@Sun.COM 	}
21097836SJohn.Forte@Sun.COM 
21107836SJohn.Forte@Sun.COM 	return (0);
21117836SJohn.Forte@Sun.COM }
21127836SJohn.Forte@Sun.COM 
21137836SJohn.Forte@Sun.COM /*
21147836SJohn.Forte@Sun.COM  * Construct device map tree from nexus driver
21157836SJohn.Forte@Sun.COM  *
21167836SJohn.Forte@Sun.COM  * PARAMS:
21177836SJohn.Forte@Sun.COM  *	path -	must be the physical path to a device
21187836SJohn.Forte@Sun.COM  *	l_err  - ptr to an error code.  Set when NULL is returned.
21197836SJohn.Forte@Sun.COM  *	flag -  device map fomat and property type.
21207836SJohn.Forte@Sun.COM  *
21217836SJohn.Forte@Sun.COM  * LOGIC:
21227836SJohn.Forte@Sun.COM  *	1. check the validity of path via g_get_path_type.
21237836SJohn.Forte@Sun.COM  *	2. If FC path, get the topology of the path via
21247836SJohn.Forte@Sun.COM  *		g_get_fca_port_topology.
21257836SJohn.Forte@Sun.COM  *
21267836SJohn.Forte@Sun.COM  *	3. If FC type(Leadville statck)
21277836SJohn.Forte@Sun.COM  *		FCIO_GET_DEV_LIST to get the device node list of fc_port_dev_t.
21287836SJohn.Forte@Sun.COM  *		FCIO_GET_HOST_PARAMS to get the fca port node of fc_port_dev_t.
21297836SJohn.Forte@Sun.COM  *
21307836SJohn.Forte@Sun.COM  *		root of tree is set with host_params info
21317836SJohn.Forte@Sun.COM  *			FC propery is set.
21327836SJohn.Forte@Sun.COM  *			FCP property is set if reqyested through flag.
21337836SJohn.Forte@Sun.COM  *				Issue g_issue_fcp_ioctl to get FCP inquiry data
21347836SJohn.Forte@Sun.COM  *		consruruct list of children via dev_list.
21357836SJohn.Forte@Sun.COM  *			FC property is set.
21367836SJohn.Forte@Sun.COM  *			FCP property is set if reqyested through flag.
21377836SJohn.Forte@Sun.COM  *				Issue FCIO_DEV_LOGIN if it is fabric device.
21387836SJohn.Forte@Sun.COM  *				Issue g_issue_fcp_ioctl to get FCP inquiry data.
21397836SJohn.Forte@Sun.COM  *
21407836SJohn.Forte@Sun.COM  *	   else FC4 type(socal/sf or ifp stack)
21417836SJohn.Forte@Sun.COM  *		SFIOCGMAP ioctl to get the device and hba nodes of
21427836SJohn.Forte@Sun.COM  *			sf_addr_pair_t.
21437836SJohn.Forte@Sun.COM  *		FCIO_GETMAP ioctl to get hba port info.
21447836SJohn.Forte@Sun.COM  *		consturct map and child tree list and
21457836SJohn.Forte@Sun.COM  *		set the properties as private loop devices.
21467836SJohn.Forte@Sun.COM  *
21477836SJohn.Forte@Sun.COM  * RETURNS:
21487836SJohn.Forte@Sun.COM  *	ptr to map is returned if OK.
21497836SJohn.Forte@Sun.COM  *	NULL and l_err is set otherwise.
21507836SJohn.Forte@Sun.COM  */
21517836SJohn.Forte@Sun.COM gfc_dev_t
g_dev_map_init(char * path,int * l_err,int flag)21527836SJohn.Forte@Sun.COM g_dev_map_init(char *path, int *l_err, int flag)
21537836SJohn.Forte@Sun.COM {
2154*11547SBill.Gumbrell@Sun.COM 	int		fd, i, num_devices = 0, err, pathcnt = 1, new_count = 0;
2155*11547SBill.Gumbrell@Sun.COM 	char		drvr_path[MAXPATHLEN], drvr_path0[MAXPATHLEN];
2156*11547SBill.Gumbrell@Sun.COM 	char		*char_ptr, *nexus_path;
2157*11547SBill.Gumbrell@Sun.COM 	struct stat	stbuf;
2158*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	*dev_list = NULL, *dlist;
2159*11547SBill.Gumbrell@Sun.COM 	uint32_t	hba_port_top, state;
2160*11547SBill.Gumbrell@Sun.COM 	uint_t		path_type;
2161*11547SBill.Gumbrell@Sun.COM 	sf_al_map_t	sf_map;
2162*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	fp_hba_port;
2163*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
2164*11547SBill.Gumbrell@Sun.COM 	int		p_on = 0, p_st = 0, hba_alpa_found = 0, nexus_fd;
2165*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
2166*11547SBill.Gumbrell@Sun.COM 	struct lilpmap	limited_map;
2167*11547SBill.Gumbrell@Sun.COM 	impl_map_dev_t	*impl_map, *impl_dev;
2168*11547SBill.Gumbrell@Sun.COM 	impl_map_dev_t	*mdl_start = NULL, *mdl_end = NULL;
2169*11547SBill.Gumbrell@Sun.COM 	struct stat	sbuf;
21707836SJohn.Forte@Sun.COM 
21717836SJohn.Forte@Sun.COM 	if (l_err == NULL) {
21727836SJohn.Forte@Sun.COM 		return (NULL);
21737836SJohn.Forte@Sun.COM 	}
21747836SJohn.Forte@Sun.COM 
21757836SJohn.Forte@Sun.COM 	if (path == NULL) {
21767836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_PATH;
21777836SJohn.Forte@Sun.COM 		return (NULL);
21787836SJohn.Forte@Sun.COM 	}
21797836SJohn.Forte@Sun.COM 
21807836SJohn.Forte@Sun.COM 	*l_err = 0;
21817836SJohn.Forte@Sun.COM 
21827836SJohn.Forte@Sun.COM 	(void) strcpy(drvr_path, path);
21837836SJohn.Forte@Sun.COM 	/*
21847836SJohn.Forte@Sun.COM 	 * Get the path to the :devctl driver
21857836SJohn.Forte@Sun.COM 	 *
21867836SJohn.Forte@Sun.COM 	 * This assumes the path looks something like this:
21877836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
21887836SJohn.Forte@Sun.COM 	 * or
21897836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
21907836SJohn.Forte@Sun.COM 	 * or
21917836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
21927836SJohn.Forte@Sun.COM 	 * or
21937836SJohn.Forte@Sun.COM 	 * a 1 level PCI type driver but still :devctl
21947836SJohn.Forte@Sun.COM 	 */
21957836SJohn.Forte@Sun.COM 	if (strstr(path, SCSI_VHCI)) {
21967836SJohn.Forte@Sun.COM 		(void) strcpy(drvr_path0, path);
21977836SJohn.Forte@Sun.COM 		if (g_get_pathlist(drvr_path0, &pathlist)) {
21987836SJohn.Forte@Sun.COM 			*l_err = L_INVALID_PATH;
21997836SJohn.Forte@Sun.COM 			return (NULL);
22007836SJohn.Forte@Sun.COM 		}
22017836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
22027836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
22037836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
22047836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
22057836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
2206*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_ONLINE) {
22077836SJohn.Forte@Sun.COM 					p_on = i;
22087836SJohn.Forte@Sun.COM 					break;
22097836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
2210*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_STANDBY) {
22117836SJohn.Forte@Sun.COM 					p_st = i;
22127836SJohn.Forte@Sun.COM 				}
22137836SJohn.Forte@Sun.COM 			}
22147836SJohn.Forte@Sun.COM 		}
22157836SJohn.Forte@Sun.COM 		if (pathlist.path_info[p_on].path_state ==
22167836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
22177836SJohn.Forte@Sun.COM 			/* on_line path */
22187836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
2219*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_hba);
22207836SJohn.Forte@Sun.COM 		} else {
22217836SJohn.Forte@Sun.COM 			/* standby or path0 */
22227836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
2223*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_hba);
22247836SJohn.Forte@Sun.COM 		}
22257836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
22267836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, FC_CTLR);
22277836SJohn.Forte@Sun.COM 	} else {
22287836SJohn.Forte@Sun.COM 		(void) strcpy(drvr_path, path);
22297836SJohn.Forte@Sun.COM 		if (strstr(drvr_path, DRV_NAME_SSD) ||
2230*11547SBill.Gumbrell@Sun.COM 		    strstr(drvr_path, SES_NAME) ||
2231*11547SBill.Gumbrell@Sun.COM 		    strstr(drvr_path, DRV_NAME_ST)) {
22327836SJohn.Forte@Sun.COM 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
22337836SJohn.Forte@Sun.COM 				*l_err = L_INVALID_PATH;
22347836SJohn.Forte@Sun.COM 				return (NULL);
22357836SJohn.Forte@Sun.COM 			}
22367836SJohn.Forte@Sun.COM 			*char_ptr = '\0';   /* Terminate sting  */
22377836SJohn.Forte@Sun.COM 			/* append controller */
22387836SJohn.Forte@Sun.COM 			(void) strcat(drvr_path, FC_CTLR);
22397836SJohn.Forte@Sun.COM 		} else {
22407836SJohn.Forte@Sun.COM 			if (stat(drvr_path, &stbuf) < 0) {
22417836SJohn.Forte@Sun.COM 				*l_err = L_LSTAT_ERROR;
22427836SJohn.Forte@Sun.COM 				return (NULL);
22437836SJohn.Forte@Sun.COM 			}
22447836SJohn.Forte@Sun.COM 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
22457836SJohn.Forte@Sun.COM 				/* append controller */
22467836SJohn.Forte@Sun.COM 				(void) strcat(drvr_path, FC_CTLR);
22477836SJohn.Forte@Sun.COM 			}
22487836SJohn.Forte@Sun.COM 		}
22497836SJohn.Forte@Sun.COM 	}
22507836SJohn.Forte@Sun.COM 
22517836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_dev_map_init: Geting drive map from:"
2252*11547SBill.Gumbrell@Sun.COM 	    " %s\n", drvr_path);
22537836SJohn.Forte@Sun.COM 
22547836SJohn.Forte@Sun.COM 	path_type = g_get_path_type(drvr_path);
22557836SJohn.Forte@Sun.COM 	if ((path_type == 0) || !(path_type & XPORT_MASK)) {
22567836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_PATH_TYPE;
22577836SJohn.Forte@Sun.COM 		return (NULL);
22587836SJohn.Forte@Sun.COM 	}
22597836SJohn.Forte@Sun.COM 
22607836SJohn.Forte@Sun.COM 	/* get fiber topology */
22617836SJohn.Forte@Sun.COM 	if ((err = g_get_fca_port_topology(drvr_path,
2262*11547SBill.Gumbrell@Sun.COM 	    &hba_port_top, 0)) != 0) {
22637836SJohn.Forte@Sun.COM 		*l_err = err;
22647836SJohn.Forte@Sun.COM 		return (NULL);
22657836SJohn.Forte@Sun.COM 	}
22667836SJohn.Forte@Sun.COM 
22677836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1) {
22687836SJohn.Forte@Sun.COM 		*l_err = errno;
22697836SJohn.Forte@Sun.COM 		return (NULL);
22707836SJohn.Forte@Sun.COM 	}
22717836SJohn.Forte@Sun.COM 
22727836SJohn.Forte@Sun.COM 	/* for FC devices. */
22737836SJohn.Forte@Sun.COM 	if (path_type & FC_FCA_MASK) {
22747836SJohn.Forte@Sun.COM 		/* get the number of device first. */
2275*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_cmd = FCIO_GET_NUM_DEVS;
2276*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_olen = sizeof (num_devices);
2277*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_xfer = FCIO_XFER_READ;
2278*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_obuf = (caddr_t)&num_devices;
2279*11547SBill.Gumbrell@Sun.COM 		if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2280*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF(" FCIO_GET_NUM_DEVS ioctl failed.\n");
2281*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2282*11547SBill.Gumbrell@Sun.COM 			*l_err = L_FCIO_GET_NUM_DEVS_FAIL;
2283*11547SBill.Gumbrell@Sun.COM 			return (NULL);
22847836SJohn.Forte@Sun.COM 		}
2285*11547SBill.Gumbrell@Sun.COM 		if (num_devices != 0) {
22867836SJohn.Forte@Sun.COM 			if ((dev_list = (fc_port_dev_t *)calloc(num_devices,
2287*11547SBill.Gumbrell@Sun.COM 			    sizeof (fc_port_dev_t))) == NULL) {
2288*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2289*11547SBill.Gumbrell@Sun.COM 				*l_err = L_MALLOC_FAILED;
2290*11547SBill.Gumbrell@Sun.COM 				return (NULL);
22917836SJohn.Forte@Sun.COM 			}
2292*11547SBill.Gumbrell@Sun.COM 
2293*11547SBill.Gumbrell@Sun.COM 			bzero((caddr_t)&fcio, sizeof (fcio));
2294*11547SBill.Gumbrell@Sun.COM 			/* Get the device list */
22957836SJohn.Forte@Sun.COM 			fcio.fcio_cmd = FCIO_GET_DEV_LIST;
22967836SJohn.Forte@Sun.COM 			/* Information read operation */
22977836SJohn.Forte@Sun.COM 			fcio.fcio_xfer = FCIO_XFER_READ;
2298*11547SBill.Gumbrell@Sun.COM 			fcio.fcio_olen = num_devices * sizeof (fc_port_dev_t);
22997836SJohn.Forte@Sun.COM 			fcio.fcio_obuf = (caddr_t)dev_list;
23007836SJohn.Forte@Sun.COM 			/* new device count */
23017836SJohn.Forte@Sun.COM 			fcio.fcio_alen = sizeof (new_count);
23027836SJohn.Forte@Sun.COM 			fcio.fcio_abuf = (caddr_t)&new_count;
23037836SJohn.Forte@Sun.COM 			if ((err = g_issue_fcio_ioctl(fd, &fcio, 0)) != 0) {
2304*11547SBill.Gumbrell@Sun.COM 				if (err == L_INVALID_DEVICE_COUNT) {
2305*11547SBill.Gumbrell@Sun.COM 					/*
2306*11547SBill.Gumbrell@Sun.COM 					 * original buffer was small so allocate
2307*11547SBill.Gumbrell@Sun.COM 					 * buffer with a new count and retry.
2308*11547SBill.Gumbrell@Sun.COM 					 */
2309*11547SBill.Gumbrell@Sun.COM 					free(dev_list);
2310*11547SBill.Gumbrell@Sun.COM 					num_devices = new_count;
2311*11547SBill.Gumbrell@Sun.COM 					new_count = 0;
2312*11547SBill.Gumbrell@Sun.COM 					if ((dev_list = (fc_port_dev_t *)
2313*11547SBill.Gumbrell@Sun.COM 					    calloc(num_devices,
2314*11547SBill.Gumbrell@Sun.COM 					    sizeof (fc_port_dev_t))) == NULL) {
2315*11547SBill.Gumbrell@Sun.COM 						(void) close(fd);
2316*11547SBill.Gumbrell@Sun.COM 						*l_err = L_MALLOC_FAILED;
2317*11547SBill.Gumbrell@Sun.COM 						return (NULL);
2318*11547SBill.Gumbrell@Sun.COM 					}
2319*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_cmd = FCIO_GET_DEV_LIST;
2320*11547SBill.Gumbrell@Sun.COM 					/* Information read operation */
2321*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_xfer = FCIO_XFER_READ;
2322*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_obuf = (caddr_t)dev_list;
2323*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_olen = num_devices *
2324*11547SBill.Gumbrell@Sun.COM 					    sizeof (fc_port_dev_t);
2325*11547SBill.Gumbrell@Sun.COM 					/* new device count */
2326*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_alen = sizeof (new_count);
2327*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_abuf = (caddr_t)&new_count;
2328*11547SBill.Gumbrell@Sun.COM 					if ((err = g_issue_fcio_ioctl(fd, &fcio,
2329*11547SBill.Gumbrell@Sun.COM 					    0)) != 0) {
2330*11547SBill.Gumbrell@Sun.COM 						if (err ==
2331*11547SBill.Gumbrell@Sun.COM 						    L_INVALID_DEVICE_COUNT) {
2332*11547SBill.Gumbrell@Sun.COM 							/*
2333*11547SBill.Gumbrell@Sun.COM 							 * No more retry. There
2334*11547SBill.Gumbrell@Sun.COM 							 * may be severe
2335*11547SBill.Gumbrell@Sun.COM 							 * hardware problem so
2336*11547SBill.Gumbrell@Sun.COM 							 * return error here.
2337*11547SBill.Gumbrell@Sun.COM 							 */
2338*11547SBill.Gumbrell@Sun.COM 							I_DPRINTF(" Device"
2339*11547SBill.Gumbrell@Sun.COM 							    " count was %d"
2340*11547SBill.Gumbrell@Sun.COM 							    " should have been"
2341*11547SBill.Gumbrell@Sun.COM 							    " %d\n",
2342*11547SBill.Gumbrell@Sun.COM 							    num_devices,
2343*11547SBill.Gumbrell@Sun.COM 							    new_count);
2344*11547SBill.Gumbrell@Sun.COM 							free(dev_list);
2345*11547SBill.Gumbrell@Sun.COM 							(void) close(fd);
2346*11547SBill.Gumbrell@Sun.COM 
2347*11547SBill.Gumbrell@Sun.COM 						*l_err = L_INVALID_DEVICE_COUNT;
2348*11547SBill.Gumbrell@Sun.COM 
2349*11547SBill.Gumbrell@Sun.COM 							return (NULL);
2350*11547SBill.Gumbrell@Sun.COM 						} else {
2351*11547SBill.Gumbrell@Sun.COM 
2352*11547SBill.Gumbrell@Sun.COM 				/* Code refactorization is needed for C style */
23537836SJohn.Forte@Sun.COM 				I_DPRINTF(" FCIO_GET_DEV_LIST ioctl failed.");
2354*11547SBill.Gumbrell@Sun.COM 
2355*11547SBill.Gumbrell@Sun.COM 							free(dev_list);
2356*11547SBill.Gumbrell@Sun.COM 							(void) close(fd);
2357*11547SBill.Gumbrell@Sun.COM 
2358*11547SBill.Gumbrell@Sun.COM 					*l_err = L_FCIO_GET_DEV_LIST_FAIL;
2359*11547SBill.Gumbrell@Sun.COM 
2360*11547SBill.Gumbrell@Sun.COM 							return (NULL);
2361*11547SBill.Gumbrell@Sun.COM 						}
2362*11547SBill.Gumbrell@Sun.COM 					}
2363*11547SBill.Gumbrell@Sun.COM 				}
23647836SJohn.Forte@Sun.COM 			}
23657836SJohn.Forte@Sun.COM 		}
23667836SJohn.Forte@Sun.COM 
23677836SJohn.Forte@Sun.COM 		/*
23687836SJohn.Forte@Sun.COM 		 * if new count is smaller than the original number from
23697836SJohn.Forte@Sun.COM 		 * FCIO_GET_NUM_DEVS, adjust new count and buffer size
23707836SJohn.Forte@Sun.COM 		 * and continue.
23717836SJohn.Forte@Sun.COM 		 */
2372*11547SBill.Gumbrell@Sun.COM 		if (new_count < num_devices) {
2373*11547SBill.Gumbrell@Sun.COM 			num_devices = new_count;
2374*11547SBill.Gumbrell@Sun.COM 			if (new_count > 0) {
2375*11547SBill.Gumbrell@Sun.COM 				if ((dev_list = (fc_port_dev_t *)
2376*11547SBill.Gumbrell@Sun.COM 				    realloc(dev_list,
2377*11547SBill.Gumbrell@Sun.COM 				    (new_count * sizeof (fc_port_dev_t))))
2378*11547SBill.Gumbrell@Sun.COM 				    == NULL) {
2379*11547SBill.Gumbrell@Sun.COM 					S_FREE(dev_list);
2380*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2381*11547SBill.Gumbrell@Sun.COM 					*l_err = L_MALLOC_FAILED;
2382*11547SBill.Gumbrell@Sun.COM 					return (NULL);
2383*11547SBill.Gumbrell@Sun.COM 				}
2384*11547SBill.Gumbrell@Sun.COM 			}
23857836SJohn.Forte@Sun.COM 		}
23867836SJohn.Forte@Sun.COM 
23877836SJohn.Forte@Sun.COM 		/* get the host param info */
2388*11547SBill.Gumbrell@Sun.COM 		(void) memset(&fp_hba_port, 0, sizeof (struct fc_port_dev));
2389*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_cmd = FCIO_GET_HOST_PARAMS;
2390*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_xfer = FCIO_XFER_READ;
2391*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_obuf = (caddr_t)&fp_hba_port;
2392*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_olen = sizeof (fc_port_dev_t);
2393*11547SBill.Gumbrell@Sun.COM 
2394*11547SBill.Gumbrell@Sun.COM 		if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2395*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF(" FCIO_GET_HOST_PARAMS ioctl failed.\n");
2396*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2397*11547SBill.Gumbrell@Sun.COM 			if (num_devices == 0) {
2398*11547SBill.Gumbrell@Sun.COM 				*l_err = L_NO_DEVICES_FOUND;
2399*11547SBill.Gumbrell@Sun.COM 			} else {
2400*11547SBill.Gumbrell@Sun.COM 				free(dev_list);
2401*11547SBill.Gumbrell@Sun.COM 				*l_err = L_FCIO_GET_HOST_PARAMS_FAIL;
2402*11547SBill.Gumbrell@Sun.COM 			}
2403*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2404*11547SBill.Gumbrell@Sun.COM 			return (NULL);
24057836SJohn.Forte@Sun.COM 		}
24067836SJohn.Forte@Sun.COM 
24077836SJohn.Forte@Sun.COM 		/* If we want the lilp map then we need to do a little	*/
24087836SJohn.Forte@Sun.COM 		/* work here.  The lilp map contains the local hba in	*/
24097836SJohn.Forte@Sun.COM 		/* the dev_addr.  Once this has been added qsort the	*/
24107836SJohn.Forte@Sun.COM 		/* dev_addr array so it's in physical order.		*/
2411*11547SBill.Gumbrell@Sun.COM 		if ((flag & MAP_FORMAT_LILP) == MAP_FORMAT_LILP) {
2412*11547SBill.Gumbrell@Sun.COM 			/* First we need to allocate one additional	*/
2413*11547SBill.Gumbrell@Sun.COM 			/* device to the dev_addr structure, for the 	*/
2414*11547SBill.Gumbrell@Sun.COM 			/* local hba					*/
2415*11547SBill.Gumbrell@Sun.COM 			if (num_devices > 0) {
2416*11547SBill.Gumbrell@Sun.COM 				if ((dev_list = (fc_port_dev_t *)
2417*11547SBill.Gumbrell@Sun.COM 				    realloc(dev_list,
2418*11547SBill.Gumbrell@Sun.COM 				    (++num_devices *
2419*11547SBill.Gumbrell@Sun.COM 				    sizeof (fc_port_dev_t)))) == NULL) {
2420*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2421*11547SBill.Gumbrell@Sun.COM 					/*
2422*11547SBill.Gumbrell@Sun.COM 					 * In case dev_list is not null free
2423*11547SBill.Gumbrell@Sun.COM 					 * it.
2424*11547SBill.Gumbrell@Sun.COM 					 */
2425*11547SBill.Gumbrell@Sun.COM 					S_FREE(dev_list);
2426*11547SBill.Gumbrell@Sun.COM 					*l_err =  L_MALLOC_FAILED;
2427*11547SBill.Gumbrell@Sun.COM 					return (NULL);
2428*11547SBill.Gumbrell@Sun.COM 				}
2429*11547SBill.Gumbrell@Sun.COM 
2430*11547SBill.Gumbrell@Sun.COM 				/*
2431*11547SBill.Gumbrell@Sun.COM 				 * Next, copy the local hba into this new
2432*11547SBill.Gumbrell@Sun.COM 				 * loc.
2433*11547SBill.Gumbrell@Sun.COM 				 */
2434*11547SBill.Gumbrell@Sun.COM 				if (memcpy(dev_list+(num_devices-1),
2435*11547SBill.Gumbrell@Sun.COM 				    &fp_hba_port,
2436*11547SBill.Gumbrell@Sun.COM 				    sizeof (fc_port_dev_t)) == NULL) {
2437*11547SBill.Gumbrell@Sun.COM 					(void) free(dev_list);
2438*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2439*11547SBill.Gumbrell@Sun.COM 					*l_err =  L_MEMCPY_FAILED;
2440*11547SBill.Gumbrell@Sun.COM 					return (NULL);
2441*11547SBill.Gumbrell@Sun.COM 				}
2442*11547SBill.Gumbrell@Sun.COM 
2443*11547SBill.Gumbrell@Sun.COM 				/* Now sort by physical location */
2444*11547SBill.Gumbrell@Sun.COM 				qsort((void*)dev_list, num_devices,
2445*11547SBill.Gumbrell@Sun.COM 				    sizeof (fc_port_dev_t), lilp_map_cmp);
2446*11547SBill.Gumbrell@Sun.COM 			}
24477836SJohn.Forte@Sun.COM 		}
24487836SJohn.Forte@Sun.COM 
24497836SJohn.Forte@Sun.COM 
24507836SJohn.Forte@Sun.COM 		/* We have dev list info and host param info.	*/
24517836SJohn.Forte@Sun.COM 		/* Now constructs map tree with these info.	*/
24527836SJohn.Forte@Sun.COM 		/* First consturct the root of the map tree	*/
24537836SJohn.Forte@Sun.COM 		/* with host param.				*/
2454*11547SBill.Gumbrell@Sun.COM 		if ((impl_map = (impl_map_dev_t *)calloc(
2455*11547SBill.Gumbrell@Sun.COM 		    1, sizeof (impl_map_dev_t))) == NULL) {
2456*11547SBill.Gumbrell@Sun.COM 			(void) free(dev_list);
2457*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2458*11547SBill.Gumbrell@Sun.COM 			*l_err = L_MALLOC_FAILED;
2459*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2460*11547SBill.Gumbrell@Sun.COM 		}
2461*11547SBill.Gumbrell@Sun.COM 		impl_map->flag = flag;
2462*11547SBill.Gumbrell@Sun.COM 		impl_map->topo = hba_port_top;
24637836SJohn.Forte@Sun.COM 
24647836SJohn.Forte@Sun.COM 		/* consturct hba property list.	*/
2465*11547SBill.Gumbrell@Sun.COM 		if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
24667836SJohn.Forte@Sun.COM 		    hba_port_top, fp_hba_port.dev_pwwn.raw_wwn,
24677836SJohn.Forte@Sun.COM 		    fp_hba_port.dev_nwwn.raw_wwn, fp_hba_port.dev_did.port_id,
24687836SJohn.Forte@Sun.COM 		    fp_hba_port.dev_hard_addr.hard_addr)) != 0) {
24697836SJohn.Forte@Sun.COM 			(void) free(dev_list);
24707836SJohn.Forte@Sun.COM 			(void) close(fd);
24717836SJohn.Forte@Sun.COM 			g_dev_map_fini(impl_map);
24727836SJohn.Forte@Sun.COM 			*l_err = err;
24737836SJohn.Forte@Sun.COM 			return (NULL);
2474*11547SBill.Gumbrell@Sun.COM 		}
2475*11547SBill.Gumbrell@Sun.COM 
2476*11547SBill.Gumbrell@Sun.COM 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2477*11547SBill.Gumbrell@Sun.COM 			if (fstat(fd, &sbuf) == -1) {
2478*11547SBill.Gumbrell@Sun.COM 				(void) free(dev_list);
2479*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2480*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2481*11547SBill.Gumbrell@Sun.COM 				*l_err = L_FSTAT_ERROR;
2482*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2483*11547SBill.Gumbrell@Sun.COM 			}
2484*11547SBill.Gumbrell@Sun.COM 			if ((err = handle_map_dev_FCP_prop(minor(sbuf.st_rdev),
2485*11547SBill.Gumbrell@Sun.COM 			    fp_hba_port.dev_pwwn, &impl_map->prop_list)) != 0) {
2486*11547SBill.Gumbrell@Sun.COM 				(void) free(dev_list);
2487*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2488*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2489*11547SBill.Gumbrell@Sun.COM 				*l_err = err;
2490*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2491*11547SBill.Gumbrell@Sun.COM 			}
24927836SJohn.Forte@Sun.COM 		}
2493*11547SBill.Gumbrell@Sun.COM 
2494*11547SBill.Gumbrell@Sun.COM 		/* consturct child for each device and	*/
2495*11547SBill.Gumbrell@Sun.COM 		/* set device property list.		*/
2496*11547SBill.Gumbrell@Sun.COM 		dlist = dev_list;
2497*11547SBill.Gumbrell@Sun.COM 		for (i = 0; i < num_devices; i++, dlist++) {
2498*11547SBill.Gumbrell@Sun.COM 			if ((impl_dev = (impl_map_dev_t *)calloc(
2499*11547SBill.Gumbrell@Sun.COM 			    1, sizeof (impl_map_dev_t))) == NULL) {
2500*11547SBill.Gumbrell@Sun.COM 				(void) free(dev_list);
2501*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2502*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2503*11547SBill.Gumbrell@Sun.COM 				*l_err = L_MALLOC_FAILED;
2504*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2505*11547SBill.Gumbrell@Sun.COM 			}
2506*11547SBill.Gumbrell@Sun.COM 			/* set the map as parent */
2507*11547SBill.Gumbrell@Sun.COM 			impl_dev->parent = impl_map;
2508*11547SBill.Gumbrell@Sun.COM 			if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2509*11547SBill.Gumbrell@Sun.COM 			    hba_port_top, dlist->dev_pwwn.raw_wwn,
2510*11547SBill.Gumbrell@Sun.COM 			    dlist->dev_nwwn.raw_wwn, dlist->dev_did.port_id,
2511*11547SBill.Gumbrell@Sun.COM 			    dlist->dev_hard_addr.hard_addr)) != 0) {
2512*11547SBill.Gumbrell@Sun.COM 				(void) free(dev_list);
2513*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2514*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2515*11547SBill.Gumbrell@Sun.COM 				*l_err = err;
2516*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2517*11547SBill.Gumbrell@Sun.COM 			}
2518*11547SBill.Gumbrell@Sun.COM 			if (i == 0) {
2519*11547SBill.Gumbrell@Sun.COM 				mdl_start = mdl_end = impl_dev;
2520*11547SBill.Gumbrell@Sun.COM 			} else {
2521*11547SBill.Gumbrell@Sun.COM 				mdl_end->next = impl_dev;
2522*11547SBill.Gumbrell@Sun.COM 				mdl_end = impl_dev;
2523*11547SBill.Gumbrell@Sun.COM 			}
2524*11547SBill.Gumbrell@Sun.COM 			if ((flag & MAP_XPORT_PROP_ONLY) !=
2525*11547SBill.Gumbrell@Sun.COM 			    MAP_XPORT_PROP_ONLY) {
2526*11547SBill.Gumbrell@Sun.COM 			if (((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
2527*11547SBill.Gumbrell@Sun.COM 			    (hba_port_top == FC_TOP_FABRIC)) &&
2528*11547SBill.Gumbrell@Sun.COM 			    (memcmp(fp_hba_port.dev_pwwn.raw_wwn,
2529*11547SBill.Gumbrell@Sun.COM 			    dlist->dev_pwwn.raw_wwn, FC_WWN_SIZE) != 0)) {
2530*11547SBill.Gumbrell@Sun.COM 				(void) memset(&fcio, 0, sizeof (fcio_t));
2531*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_cmd = FCIO_GET_STATE;
2532*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_ilen = sizeof (dlist->dev_pwwn);
2533*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_ibuf = (caddr_t)&dlist->dev_pwwn;
2534*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_xfer = FCIO_XFER_READ |
2535*11547SBill.Gumbrell@Sun.COM 				    FCIO_XFER_WRITE;
2536*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_olen = sizeof (uint32_t);
2537*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_obuf = (caddr_t)&state;
2538*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_alen = 0;
2539*11547SBill.Gumbrell@Sun.COM 				fcio.fcio_abuf = NULL;
2540*11547SBill.Gumbrell@Sun.COM 				if (g_issue_fcio_ioctl(fd, &fcio, 0) != 0) {
2541*11547SBill.Gumbrell@Sun.COM 					I_DPRINTF(
2542*11547SBill.Gumbrell@Sun.COM 					    " FCIO_GET_STATE ioctl failed.\n");
2543*11547SBill.Gumbrell@Sun.COM 					if ((err = update_map_dev_FCP_prop(
2544*11547SBill.Gumbrell@Sun.COM 					    &impl_dev->prop_list, NULL,
2545*11547SBill.Gumbrell@Sun.COM 					    L_FCIO_GET_STATE_FAIL,
2546*11547SBill.Gumbrell@Sun.COM 					    PROP_NOEXIST)) != 0) {
2547*11547SBill.Gumbrell@Sun.COM 						(void) free(dev_list);
2548*11547SBill.Gumbrell@Sun.COM 						(void) close(fd);
2549*11547SBill.Gumbrell@Sun.COM 						g_dev_map_fini(impl_map);
2550*11547SBill.Gumbrell@Sun.COM 						*l_err = err;
2551*11547SBill.Gumbrell@Sun.COM 						return (NULL);
2552*11547SBill.Gumbrell@Sun.COM 					}
2553*11547SBill.Gumbrell@Sun.COM 				}
2554*11547SBill.Gumbrell@Sun.COM 				if (state != PORT_DEVICE_LOGGED_IN) {
2555*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2556*11547SBill.Gumbrell@Sun.COM 					if ((fd = g_object_open(drvr_path,
2557*11547SBill.Gumbrell@Sun.COM 					    O_NDELAY | O_RDONLY | O_EXCL)) ==
2558*11547SBill.Gumbrell@Sun.COM 					    -1) {
2559*11547SBill.Gumbrell@Sun.COM 						(void) free(dev_list);
2560*11547SBill.Gumbrell@Sun.COM 						g_dev_map_fini(impl_map);
2561*11547SBill.Gumbrell@Sun.COM 						*l_err = L_OPEN_PATH_FAIL;
2562*11547SBill.Gumbrell@Sun.COM 						return (NULL);
2563*11547SBill.Gumbrell@Sun.COM 					}
2564*11547SBill.Gumbrell@Sun.COM 					(void) memset(&fcio, 0,
2565*11547SBill.Gumbrell@Sun.COM 					    sizeof (fcio_t));
2566*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_cmd = FCIO_DEV_LOGIN;
2567*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_ilen =
2568*11547SBill.Gumbrell@Sun.COM 					    sizeof (dlist->dev_pwwn);
2569*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_ibuf =
2570*11547SBill.Gumbrell@Sun.COM 					    (caddr_t)&dlist->dev_pwwn;
2571*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_xfer = FCIO_XFER_WRITE;
2572*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_olen = fcio.fcio_alen = 0;
2573*11547SBill.Gumbrell@Sun.COM 					fcio.fcio_obuf = fcio.fcio_abuf = NULL;
2574*11547SBill.Gumbrell@Sun.COM 					if (g_issue_fcio_ioctl(fd, &fcio, 0) !=
2575*11547SBill.Gumbrell@Sun.COM 					    0) {
2576*11547SBill.Gumbrell@Sun.COM 
2577*11547SBill.Gumbrell@Sun.COM 				/* Code refactorization is needed for C style */
2578*11547SBill.Gumbrell@Sun.COM 				I_DPRINTF(" FCIO_DEV_LOGIN ioctl failed.\n");
2579*11547SBill.Gumbrell@Sun.COM 
2580*11547SBill.Gumbrell@Sun.COM 				if ((err = update_map_dev_FCP_prop(
2581*11547SBill.Gumbrell@Sun.COM 				    &impl_dev->prop_list, NULL,
2582*11547SBill.Gumbrell@Sun.COM 				    L_FCIO_DEV_LOGIN_FAIL,
2583*11547SBill.Gumbrell@Sun.COM 				    PROP_NOEXIST)) != 0) {
2584*11547SBill.Gumbrell@Sun.COM 					(void) free(dev_list);
2585*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2586*11547SBill.Gumbrell@Sun.COM 					g_dev_map_fini(impl_map);
2587*11547SBill.Gumbrell@Sun.COM 					*l_err = err;
2588*11547SBill.Gumbrell@Sun.COM 					return (NULL);
2589*11547SBill.Gumbrell@Sun.COM 				}
2590*11547SBill.Gumbrell@Sun.COM 
2591*11547SBill.Gumbrell@Sun.COM 							/*
2592*11547SBill.Gumbrell@Sun.COM 							 * plogi failed continue
2593*11547SBill.Gumbrell@Sun.COM 							 * to next dev
2594*11547SBill.Gumbrell@Sun.COM 							 */
2595*11547SBill.Gumbrell@Sun.COM 							continue;
2596*11547SBill.Gumbrell@Sun.COM 						}
2597*11547SBill.Gumbrell@Sun.COM 					}
2598*11547SBill.Gumbrell@Sun.COM 				}
2599*11547SBill.Gumbrell@Sun.COM 				/* sbuf should be set from hba_port handling. */
2600*11547SBill.Gumbrell@Sun.COM 				if ((err = handle_map_dev_FCP_prop(
2601*11547SBill.Gumbrell@Sun.COM 				    minor(sbuf.st_rdev),
2602*11547SBill.Gumbrell@Sun.COM 				    dlist->dev_pwwn, &impl_dev->prop_list)) !=
2603*11547SBill.Gumbrell@Sun.COM 				    0) {
2604*11547SBill.Gumbrell@Sun.COM 					(void) free(dev_list);
2605*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2606*11547SBill.Gumbrell@Sun.COM 					g_dev_map_fini(impl_map);
2607*11547SBill.Gumbrell@Sun.COM 					*l_err = err;
2608*11547SBill.Gumbrell@Sun.COM 					return (NULL);
2609*11547SBill.Gumbrell@Sun.COM 				}
2610*11547SBill.Gumbrell@Sun.COM 			}
2611*11547SBill.Gumbrell@Sun.COM 		}
26127836SJohn.Forte@Sun.COM 		/* connect the children to to map.	*/
2613*11547SBill.Gumbrell@Sun.COM 		impl_map->child = mdl_start;
2614*11547SBill.Gumbrell@Sun.COM 		S_FREE(dev_list);
26157836SJohn.Forte@Sun.COM 
26167836SJohn.Forte@Sun.COM 	} else {	/* sf and fc4/pci devices */
2617*11547SBill.Gumbrell@Sun.COM 		/* initialize map */
2618*11547SBill.Gumbrell@Sun.COM 		(void) memset(&sf_map, 0, sizeof (struct sf_al_map));
2619*11547SBill.Gumbrell@Sun.COM 		if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
2620*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
2621*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2622*11547SBill.Gumbrell@Sun.COM 			*l_err = L_SFIOCGMAP_IOCTL_FAIL;
2623*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2624*11547SBill.Gumbrell@Sun.COM 		}
26257836SJohn.Forte@Sun.COM 		/* Check for reasonableness. */
2626*11547SBill.Gumbrell@Sun.COM 		if ((sf_map.sf_count > 126) || (sf_map.sf_count < 0)) {
2627*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2628*11547SBill.Gumbrell@Sun.COM 			*l_err = L_INVALID_LOOP_MAP;
2629*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2630*11547SBill.Gumbrell@Sun.COM 		}
2631*11547SBill.Gumbrell@Sun.COM 
2632*11547SBill.Gumbrell@Sun.COM 		if (sf_map.sf_count == 0) {
2633*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2634*11547SBill.Gumbrell@Sun.COM 			*l_err = L_NO_DEVICES_FOUND;
2635*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2636*11547SBill.Gumbrell@Sun.COM 		}
2637*11547SBill.Gumbrell@Sun.COM 
2638*11547SBill.Gumbrell@Sun.COM 		if ((err = g_get_nexus_path(drvr_path, &nexus_path)) != 0) {
2639*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2640*11547SBill.Gumbrell@Sun.COM 			*l_err = err;
2641*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2642*11547SBill.Gumbrell@Sun.COM 		}
2643*11547SBill.Gumbrell@Sun.COM 
2644*11547SBill.Gumbrell@Sun.COM 		if ((nexus_fd =
2645*11547SBill.Gumbrell@Sun.COM 		    g_object_open(nexus_path, O_NDELAY | O_RDONLY)) == -1) {
2646*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2647*11547SBill.Gumbrell@Sun.COM 			S_FREE(nexus_path);
2648*11547SBill.Gumbrell@Sun.COM 			*l_err = errno;
2649*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2650*11547SBill.Gumbrell@Sun.COM 		}
26517836SJohn.Forte@Sun.COM 
26527836SJohn.Forte@Sun.COM 		/* get limited map to get hba param info */
2653*11547SBill.Gumbrell@Sun.COM 		if (ioctl(nexus_fd, FCIO_GETMAP, &limited_map) != 0) {
2654*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF("  FCIO_GETMAP ioctl failed\n");
2655*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2656*11547SBill.Gumbrell@Sun.COM 			(void) close(nexus_fd);
2657*11547SBill.Gumbrell@Sun.COM 			S_FREE(nexus_path);
2658*11547SBill.Gumbrell@Sun.COM 			*l_err = L_FCIO_GETMAP_IOCTL_FAIL;
2659*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2660*11547SBill.Gumbrell@Sun.COM 		}
26617836SJohn.Forte@Sun.COM 		(void) close(nexus_fd);
26627836SJohn.Forte@Sun.COM 		S_FREE(nexus_path);
2663*11547SBill.Gumbrell@Sun.COM 
2664*11547SBill.Gumbrell@Sun.COM 		for (i = 0; i < sf_map.sf_count; i++) {
2665*11547SBill.Gumbrell@Sun.COM 			if (sf_map.sf_addr_pair[i].sf_al_pa ==
2666*11547SBill.Gumbrell@Sun.COM 			    limited_map.lilp_myalpa) {
2667*11547SBill.Gumbrell@Sun.COM 				sf_map.sf_hba_addr = sf_map.sf_addr_pair[i];
2668*11547SBill.Gumbrell@Sun.COM 				hba_alpa_found = 1;
2669*11547SBill.Gumbrell@Sun.COM 			}
26707836SJohn.Forte@Sun.COM 		}
2671*11547SBill.Gumbrell@Sun.COM 
2672*11547SBill.Gumbrell@Sun.COM 		if (!(hba_alpa_found)) {
2673*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2674*11547SBill.Gumbrell@Sun.COM 			*l_err = L_INVALID_LOOP_MAP;
2675*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2676*11547SBill.Gumbrell@Sun.COM 		}
26777836SJohn.Forte@Sun.COM 
26787836SJohn.Forte@Sun.COM 		/* We have dev list info and host param info.	*/
26797836SJohn.Forte@Sun.COM 		/* Now constructs map tree with these info.	*/
26807836SJohn.Forte@Sun.COM 		/* First consturct the root of the map tree	*/
26817836SJohn.Forte@Sun.COM 		/* with host param.				*/
2682*11547SBill.Gumbrell@Sun.COM 		if ((impl_map = (impl_map_dev_t *)calloc(
2683*11547SBill.Gumbrell@Sun.COM 		    1, sizeof (impl_map_dev_t))) == NULL) {
2684*11547SBill.Gumbrell@Sun.COM 			(void) close(fd);
2685*11547SBill.Gumbrell@Sun.COM 			*l_err = L_MALLOC_FAILED;
2686*11547SBill.Gumbrell@Sun.COM 			return (NULL);
2687*11547SBill.Gumbrell@Sun.COM 		}
2688*11547SBill.Gumbrell@Sun.COM 		impl_map->flag = flag;
2689*11547SBill.Gumbrell@Sun.COM 		impl_map->topo = hba_port_top;
26907836SJohn.Forte@Sun.COM 
26917836SJohn.Forte@Sun.COM 		/* consturct hba property list.	*/
2692*11547SBill.Gumbrell@Sun.COM 		if ((err = update_map_dev_fc_prop(&impl_map->prop_list,
26937836SJohn.Forte@Sun.COM 		    hba_port_top, sf_map.sf_hba_addr.sf_port_wwn,
26947836SJohn.Forte@Sun.COM 		    sf_map.sf_hba_addr.sf_node_wwn,
26957836SJohn.Forte@Sun.COM 		    (int)sf_map.sf_hba_addr.sf_al_pa,
26967836SJohn.Forte@Sun.COM 		    (int)sf_map.sf_hba_addr.sf_hard_address)) != 0) {
26977836SJohn.Forte@Sun.COM 			(void) close(fd);
26987836SJohn.Forte@Sun.COM 			g_dev_map_fini(impl_map);
26997836SJohn.Forte@Sun.COM 			*l_err = err;
27007836SJohn.Forte@Sun.COM 			return (NULL);
2701*11547SBill.Gumbrell@Sun.COM 		}
2702*11547SBill.Gumbrell@Sun.COM 
2703*11547SBill.Gumbrell@Sun.COM 		if ((flag & MAP_XPORT_PROP_ONLY) != MAP_XPORT_PROP_ONLY) {
2704*11547SBill.Gumbrell@Sun.COM 			if ((err = update_map_dev_FCP_prop(&impl_map->prop_list,
2705*11547SBill.Gumbrell@Sun.COM 			    &sf_map.sf_hba_addr.sf_inq_dtype, 0,
2706*11547SBill.Gumbrell@Sun.COM 			    PROP_NOEXIST)) != 0) {
2707*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2708*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2709*11547SBill.Gumbrell@Sun.COM 				*l_err = err;
2710*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2711*11547SBill.Gumbrell@Sun.COM 			}
27127836SJohn.Forte@Sun.COM 		}
2713*11547SBill.Gumbrell@Sun.COM 
2714*11547SBill.Gumbrell@Sun.COM 		for (i = 0; i < sf_map.sf_count; i++) {
2715*11547SBill.Gumbrell@Sun.COM 			if ((impl_dev = (impl_map_dev_t *)calloc(
2716*11547SBill.Gumbrell@Sun.COM 			    1, sizeof (impl_map_dev_t))) == NULL) {
2717*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2718*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2719*11547SBill.Gumbrell@Sun.COM 				*l_err = L_MALLOC_FAILED;
2720*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2721*11547SBill.Gumbrell@Sun.COM 			}
2722*11547SBill.Gumbrell@Sun.COM 			/* set the map as parent */
2723*11547SBill.Gumbrell@Sun.COM 			impl_dev->parent = impl_map;
2724*11547SBill.Gumbrell@Sun.COM 			if ((err = update_map_dev_fc_prop(&impl_dev->prop_list,
2725*11547SBill.Gumbrell@Sun.COM 			    hba_port_top, sf_map.sf_addr_pair[i].sf_port_wwn,
2726*11547SBill.Gumbrell@Sun.COM 			    sf_map.sf_addr_pair[i].sf_node_wwn,
2727*11547SBill.Gumbrell@Sun.COM 			    (int)(sf_map.sf_addr_pair[i].sf_al_pa),
2728*11547SBill.Gumbrell@Sun.COM 			    (int)(sf_map.sf_addr_pair[i].sf_hard_address))) !=
2729*11547SBill.Gumbrell@Sun.COM 			    0) {
2730*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
2731*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(impl_map);
2732*11547SBill.Gumbrell@Sun.COM 				*l_err = err;
2733*11547SBill.Gumbrell@Sun.COM 				return (NULL);
2734*11547SBill.Gumbrell@Sun.COM 			}
2735*11547SBill.Gumbrell@Sun.COM 			if (i == 0) {
2736*11547SBill.Gumbrell@Sun.COM 				mdl_start = mdl_end = impl_dev;
2737*11547SBill.Gumbrell@Sun.COM 			} else {
2738*11547SBill.Gumbrell@Sun.COM 				mdl_end->next = impl_dev;
2739*11547SBill.Gumbrell@Sun.COM 				mdl_end = impl_dev;
2740*11547SBill.Gumbrell@Sun.COM 			}
2741*11547SBill.Gumbrell@Sun.COM 			if ((flag & MAP_XPORT_PROP_ONLY) !=
2742*11547SBill.Gumbrell@Sun.COM 			    MAP_XPORT_PROP_ONLY) {
2743*11547SBill.Gumbrell@Sun.COM 				if ((err = update_map_dev_FCP_prop(
2744*11547SBill.Gumbrell@Sun.COM 				    &impl_dev->prop_list,
2745*11547SBill.Gumbrell@Sun.COM 				    &sf_map.sf_addr_pair[i].sf_inq_dtype, 0,
2746*11547SBill.Gumbrell@Sun.COM 				    PROP_NOEXIST)) != 0) {
2747*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
2748*11547SBill.Gumbrell@Sun.COM 					g_dev_map_fini(impl_map);
2749*11547SBill.Gumbrell@Sun.COM 					*l_err = err;
2750*11547SBill.Gumbrell@Sun.COM 					return (NULL);
2751*11547SBill.Gumbrell@Sun.COM 				}
2752*11547SBill.Gumbrell@Sun.COM 			}
2753*11547SBill.Gumbrell@Sun.COM 		} /* end of for loop */
2754*11547SBill.Gumbrell@Sun.COM 
2755*11547SBill.Gumbrell@Sun.COM 		impl_map->child = mdl_start;
27567836SJohn.Forte@Sun.COM 	} /* end of else */
27577836SJohn.Forte@Sun.COM 
27587836SJohn.Forte@Sun.COM 	close(fd);
27597836SJohn.Forte@Sun.COM 	return ((gfc_dev_t)(impl_map));
27607836SJohn.Forte@Sun.COM }
27617836SJohn.Forte@Sun.COM 
27627836SJohn.Forte@Sun.COM /*
27637836SJohn.Forte@Sun.COM  * This function deallocates memory for propery list.
27647836SJohn.Forte@Sun.COM  */
27657836SJohn.Forte@Sun.COM static void
free_prop_list(impl_map_dev_prop_t ** prop_list)27667836SJohn.Forte@Sun.COM free_prop_list(impl_map_dev_prop_t **prop_list)
27677836SJohn.Forte@Sun.COM {
27687836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *lp, *olp;
27697836SJohn.Forte@Sun.COM 
27707836SJohn.Forte@Sun.COM 	lp = *prop_list;
27717836SJohn.Forte@Sun.COM 	while (lp != NULL) {
27727836SJohn.Forte@Sun.COM 		switch (lp->prop_type) {
27737836SJohn.Forte@Sun.COM 		case GFC_PROP_TYPE_BYTES:
27747836SJohn.Forte@Sun.COM 			free((uchar_t *)(lp->prop_data));
27757836SJohn.Forte@Sun.COM 			break;
27767836SJohn.Forte@Sun.COM 		case GFC_PROP_TYPE_INT:
27777836SJohn.Forte@Sun.COM 			free((int *)(lp->prop_data));
27787836SJohn.Forte@Sun.COM 			break;
27797836SJohn.Forte@Sun.COM 		case GFC_PROP_TYPE_STRING:
27807836SJohn.Forte@Sun.COM 			free((char *)(lp->prop_data));
27817836SJohn.Forte@Sun.COM 			break;
27827836SJohn.Forte@Sun.COM 		default:
27837836SJohn.Forte@Sun.COM 			break;
27847836SJohn.Forte@Sun.COM 		}
27857836SJohn.Forte@Sun.COM 		lp->prop_data = NULL;
27867836SJohn.Forte@Sun.COM 		olp = lp;
27877836SJohn.Forte@Sun.COM 		lp = olp->next;
27887836SJohn.Forte@Sun.COM 		S_FREE(olp);
27897836SJohn.Forte@Sun.COM 	}
27907836SJohn.Forte@Sun.COM 
27917836SJohn.Forte@Sun.COM 	*prop_list = NULL;
27927836SJohn.Forte@Sun.COM }
27937836SJohn.Forte@Sun.COM 
27947836SJohn.Forte@Sun.COM /*
27957836SJohn.Forte@Sun.COM  * This function deallocates memory for children list.
27967836SJohn.Forte@Sun.COM  */
27977836SJohn.Forte@Sun.COM static void
free_child_list(impl_map_dev_t ** dev_list)27987836SJohn.Forte@Sun.COM free_child_list(impl_map_dev_t **dev_list)
27997836SJohn.Forte@Sun.COM {
28007836SJohn.Forte@Sun.COM 	impl_map_dev_t *lp, *olp;
28017836SJohn.Forte@Sun.COM 
28027836SJohn.Forte@Sun.COM 	lp = *dev_list;
28037836SJohn.Forte@Sun.COM 	while (lp != NULL) {
28047836SJohn.Forte@Sun.COM 		free_prop_list(&lp->prop_list);
28057836SJohn.Forte@Sun.COM 		olp = lp;
28067836SJohn.Forte@Sun.COM 		lp = olp->next;
28077836SJohn.Forte@Sun.COM 		S_FREE(olp);
28087836SJohn.Forte@Sun.COM 	}
28097836SJohn.Forte@Sun.COM 
28107836SJohn.Forte@Sun.COM 	*dev_list = NULL;
28117836SJohn.Forte@Sun.COM }
28127836SJohn.Forte@Sun.COM 
28137836SJohn.Forte@Sun.COM /*
28147836SJohn.Forte@Sun.COM  * This function deallocates memory for the whole map.
28157836SJohn.Forte@Sun.COM  */
28167836SJohn.Forte@Sun.COM void
g_dev_map_fini(gfc_dev_t map)28177836SJohn.Forte@Sun.COM g_dev_map_fini(gfc_dev_t map)
28187836SJohn.Forte@Sun.COM {
28197836SJohn.Forte@Sun.COM 	impl_map_dev_t *impl_map;
28207836SJohn.Forte@Sun.COM 
28217836SJohn.Forte@Sun.COM 	impl_map = (impl_map_dev_t *)map;
28227836SJohn.Forte@Sun.COM 
28237836SJohn.Forte@Sun.COM 	if (impl_map != NULL) {
2824*11547SBill.Gumbrell@Sun.COM 		free_prop_list(&impl_map->prop_list);
2825*11547SBill.Gumbrell@Sun.COM 		free_child_list(&impl_map->child);
2826*11547SBill.Gumbrell@Sun.COM 		S_FREE(impl_map);
28277836SJohn.Forte@Sun.COM 	}
28287836SJohn.Forte@Sun.COM }
28297836SJohn.Forte@Sun.COM 
28307836SJohn.Forte@Sun.COM /*
28317836SJohn.Forte@Sun.COM  * This function passes back topology of the input map.
28327836SJohn.Forte@Sun.COM  * input should be a handle form g_dev_map_init().
28337836SJohn.Forte@Sun.COM  *
28347836SJohn.Forte@Sun.COM  * return 0 if OK.
28357836SJohn.Forte@Sun.COM  * return error code otherwise.
28367836SJohn.Forte@Sun.COM  */
28377836SJohn.Forte@Sun.COM int
g_get_map_topology(gfc_dev_t map,uint_t * topology)2838*11547SBill.Gumbrell@Sun.COM g_get_map_topology(gfc_dev_t map, uint_t *topology)
28397836SJohn.Forte@Sun.COM {
28407836SJohn.Forte@Sun.COM 	impl_map_dev_t	*impl_map;
28417836SJohn.Forte@Sun.COM 
28427836SJohn.Forte@Sun.COM 	if (map == NULL) {
28437836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
28447836SJohn.Forte@Sun.COM 	}
28457836SJohn.Forte@Sun.COM 
28467836SJohn.Forte@Sun.COM 	if (topology == NULL) {
28477836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
28487836SJohn.Forte@Sun.COM 	}
28497836SJohn.Forte@Sun.COM 
28507836SJohn.Forte@Sun.COM 	impl_map = (impl_map_dev_t *)map;
28517836SJohn.Forte@Sun.COM 
28527836SJohn.Forte@Sun.COM 	*topology = impl_map->topo;
28537836SJohn.Forte@Sun.COM 
28547836SJohn.Forte@Sun.COM 	return (0);
28557836SJohn.Forte@Sun.COM }
28567836SJohn.Forte@Sun.COM 
28577836SJohn.Forte@Sun.COM /*
28587836SJohn.Forte@Sun.COM  * This function returns the first device handle of the input map.
28597836SJohn.Forte@Sun.COM  * map input should be a handle form g_dev_map_init().
28607836SJohn.Forte@Sun.COM  *
28617836SJohn.Forte@Sun.COM  * l_err set to 0 if OK.
28627836SJohn.Forte@Sun.COM  * l_err set to error code otherwise.
28637836SJohn.Forte@Sun.COM  */
28647836SJohn.Forte@Sun.COM gfc_dev_t
g_get_first_dev(gfc_dev_t map,int * l_err)2865*11547SBill.Gumbrell@Sun.COM g_get_first_dev(gfc_dev_t map, int *l_err)
28667836SJohn.Forte@Sun.COM {
28677836SJohn.Forte@Sun.COM 	impl_map_dev_t	*impl_map;
28687836SJohn.Forte@Sun.COM 
28697836SJohn.Forte@Sun.COM 	if (l_err == NULL) {
28707836SJohn.Forte@Sun.COM 		return (NULL);
28717836SJohn.Forte@Sun.COM 	}
28727836SJohn.Forte@Sun.COM 
28737836SJohn.Forte@Sun.COM 	*l_err = 0;
28747836SJohn.Forte@Sun.COM 
28757836SJohn.Forte@Sun.COM 	if (map == NULL) {
28767836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_MAP_DEV_ADDR;
28777836SJohn.Forte@Sun.COM 		return (NULL);
28787836SJohn.Forte@Sun.COM 	}
28797836SJohn.Forte@Sun.COM 
28807836SJohn.Forte@Sun.COM 	impl_map = (impl_map_dev_t *)map;
28817836SJohn.Forte@Sun.COM 
28827836SJohn.Forte@Sun.COM 	if (impl_map->child == NULL) {
28837836SJohn.Forte@Sun.COM 		*l_err = L_NO_SUCH_DEV_FOUND;
28847836SJohn.Forte@Sun.COM 	}
28857836SJohn.Forte@Sun.COM 
28867836SJohn.Forte@Sun.COM 	return ((gfc_dev_t)(impl_map->child));
28877836SJohn.Forte@Sun.COM }
28887836SJohn.Forte@Sun.COM 
28897836SJohn.Forte@Sun.COM /*
28907836SJohn.Forte@Sun.COM  * This function returns the next device handle of the input map.
28917836SJohn.Forte@Sun.COM  * map_dev input should be a handle for device.
28927836SJohn.Forte@Sun.COM  *
28937836SJohn.Forte@Sun.COM  * l_err set to 0 if OK.
28947836SJohn.Forte@Sun.COM  * l_err set to error code otherwise.
28957836SJohn.Forte@Sun.COM  */
28967836SJohn.Forte@Sun.COM gfc_dev_t
g_get_next_dev(gfc_dev_t map_dev,int * l_err)2897*11547SBill.Gumbrell@Sun.COM g_get_next_dev(gfc_dev_t map_dev, int *l_err)
28987836SJohn.Forte@Sun.COM {
28997836SJohn.Forte@Sun.COM 	impl_map_dev_t	*impl_dev;
29007836SJohn.Forte@Sun.COM 
29017836SJohn.Forte@Sun.COM 	if (l_err == NULL) {
29027836SJohn.Forte@Sun.COM 		return (NULL);
29037836SJohn.Forte@Sun.COM 	}
29047836SJohn.Forte@Sun.COM 
29057836SJohn.Forte@Sun.COM 	*l_err = 0;
29067836SJohn.Forte@Sun.COM 
29077836SJohn.Forte@Sun.COM 	if (map_dev == NULL) {
29087836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_MAP_DEV_ADDR;
29097836SJohn.Forte@Sun.COM 		return (NULL);
29107836SJohn.Forte@Sun.COM 	}
29117836SJohn.Forte@Sun.COM 
29127836SJohn.Forte@Sun.COM 	impl_dev = (impl_map_dev_t *)map_dev;
29137836SJohn.Forte@Sun.COM 
29147836SJohn.Forte@Sun.COM 	if (impl_dev->next == NULL) {
29157836SJohn.Forte@Sun.COM 		*l_err = L_NO_SUCH_DEV_FOUND;
29167836SJohn.Forte@Sun.COM 	}
29177836SJohn.Forte@Sun.COM 
29187836SJohn.Forte@Sun.COM 	return ((gfc_dev_t)(impl_dev->next));
29197836SJohn.Forte@Sun.COM }
29207836SJohn.Forte@Sun.COM 
29217836SJohn.Forte@Sun.COM /*
29227836SJohn.Forte@Sun.COM  * This function passes back uchar_t type property and its count.
29237836SJohn.Forte@Sun.COM  * map_dev input should be a handle for device.
29247836SJohn.Forte@Sun.COM  *
29257836SJohn.Forte@Sun.COM  * return 0 if OK.
29267836SJohn.Forte@Sun.COM  * return error code otherwise.
29277836SJohn.Forte@Sun.COM  */
29287836SJohn.Forte@Sun.COM int
g_dev_prop_lookup_bytes(gfc_dev_t map_dev,const char * prop_name,int * prop_data_count,uchar_t ** prop_data)2929*11547SBill.Gumbrell@Sun.COM g_dev_prop_lookup_bytes(gfc_dev_t map_dev, const char *prop_name,
2930*11547SBill.Gumbrell@Sun.COM     int *prop_data_count, uchar_t **prop_data)
29317836SJohn.Forte@Sun.COM {
29327836SJohn.Forte@Sun.COM 	impl_map_dev_t *impl_dev;
29337836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *impl_prop;
29347836SJohn.Forte@Sun.COM 	int err;
29357836SJohn.Forte@Sun.COM 
29367836SJohn.Forte@Sun.COM 	if (map_dev == NULL) {
29377836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
29387836SJohn.Forte@Sun.COM 	}
29397836SJohn.Forte@Sun.COM 
29407836SJohn.Forte@Sun.COM 	if ((prop_name == NULL) || (prop_data == NULL) ||
2941*11547SBill.Gumbrell@Sun.COM 	    (prop_data_count == NULL)) {
29427836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
29437836SJohn.Forte@Sun.COM 	}
29447836SJohn.Forte@Sun.COM 
29457836SJohn.Forte@Sun.COM 	impl_dev = (impl_map_dev_t *)map_dev;
29467836SJohn.Forte@Sun.COM 	impl_prop = impl_dev->prop_list;
29477836SJohn.Forte@Sun.COM 
29487836SJohn.Forte@Sun.COM 	err = L_INVALID_MAP_DEV_PROP_NAME;
29497836SJohn.Forte@Sun.COM 
29507836SJohn.Forte@Sun.COM 	while (impl_prop) {
2951*11547SBill.Gumbrell@Sun.COM 		if (strncmp(impl_prop->prop_name, prop_name,
2952*11547SBill.Gumbrell@Sun.COM 		    strlen(prop_name)) == 0) {
2953*11547SBill.Gumbrell@Sun.COM 			if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
2954*11547SBill.Gumbrell@Sun.COM 				err = L_INVALID_MAP_DEV_PROP_TYPE;
2955*11547SBill.Gumbrell@Sun.COM 				break;
2956*11547SBill.Gumbrell@Sun.COM 			}
2957*11547SBill.Gumbrell@Sun.COM 			if (impl_prop->prop_data) {
2958*11547SBill.Gumbrell@Sun.COM 				*prop_data = (uchar_t *)(impl_prop->prop_data);
2959*11547SBill.Gumbrell@Sun.COM 				*prop_data_count = impl_prop->prop_size;
2960*11547SBill.Gumbrell@Sun.COM 				return (0);
2961*11547SBill.Gumbrell@Sun.COM 			} else {
2962*11547SBill.Gumbrell@Sun.COM 				err = impl_prop->prop_error;
2963*11547SBill.Gumbrell@Sun.COM 			}
2964*11547SBill.Gumbrell@Sun.COM 			break;
29657836SJohn.Forte@Sun.COM 		}
2966*11547SBill.Gumbrell@Sun.COM 		impl_prop = impl_prop->next;
29677836SJohn.Forte@Sun.COM 	}
29687836SJohn.Forte@Sun.COM 
29697836SJohn.Forte@Sun.COM 	return (err);
29707836SJohn.Forte@Sun.COM }
29717836SJohn.Forte@Sun.COM 
29727836SJohn.Forte@Sun.COM /*
29737836SJohn.Forte@Sun.COM  * This function passes back int type property.
29747836SJohn.Forte@Sun.COM  * map_dev input should be a handle for device.
29757836SJohn.Forte@Sun.COM  *
29767836SJohn.Forte@Sun.COM  * return 0 if OK.
29777836SJohn.Forte@Sun.COM  * return error code otherwise.
29787836SJohn.Forte@Sun.COM  */
29797836SJohn.Forte@Sun.COM int
g_dev_prop_lookup_ints(gfc_dev_t map_dev,const char * prop_name,int ** prop_data)2980*11547SBill.Gumbrell@Sun.COM g_dev_prop_lookup_ints(gfc_dev_t map_dev, const char *prop_name,
2981*11547SBill.Gumbrell@Sun.COM     int **prop_data)
29827836SJohn.Forte@Sun.COM {
29837836SJohn.Forte@Sun.COM 	impl_map_dev_t *impl_dev;
29847836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *impl_prop;
29857836SJohn.Forte@Sun.COM 	int err;
29867836SJohn.Forte@Sun.COM 
29877836SJohn.Forte@Sun.COM 	if (map_dev == NULL) {
29887836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
29897836SJohn.Forte@Sun.COM 	}
29907836SJohn.Forte@Sun.COM 
29917836SJohn.Forte@Sun.COM 	if ((prop_name == NULL) || (prop_data == NULL)) {
29927836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
29937836SJohn.Forte@Sun.COM 	}
29947836SJohn.Forte@Sun.COM 
29957836SJohn.Forte@Sun.COM 	impl_dev = (impl_map_dev_t *)map_dev;
29967836SJohn.Forte@Sun.COM 	impl_prop = impl_dev->prop_list;
29977836SJohn.Forte@Sun.COM 
29987836SJohn.Forte@Sun.COM 	err = L_INVALID_MAP_DEV_PROP_NAME;
29997836SJohn.Forte@Sun.COM 
30007836SJohn.Forte@Sun.COM 	while (impl_prop) {
3001*11547SBill.Gumbrell@Sun.COM 		if (strncmp(impl_prop->prop_name, prop_name,
3002*11547SBill.Gumbrell@Sun.COM 		    strlen(prop_name)) == 0) {
3003*11547SBill.Gumbrell@Sun.COM 			if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3004*11547SBill.Gumbrell@Sun.COM 			err = L_INVALID_MAP_DEV_PROP_TYPE;
3005*11547SBill.Gumbrell@Sun.COM 			break;
3006*11547SBill.Gumbrell@Sun.COM 			}
3007*11547SBill.Gumbrell@Sun.COM 			if (impl_prop->prop_data) {
3008*11547SBill.Gumbrell@Sun.COM 				*prop_data = (int *)(impl_prop->prop_data);
3009*11547SBill.Gumbrell@Sun.COM 				return (0);
3010*11547SBill.Gumbrell@Sun.COM 			} else {
3011*11547SBill.Gumbrell@Sun.COM 				err = impl_prop->prop_error;
3012*11547SBill.Gumbrell@Sun.COM 			}
3013*11547SBill.Gumbrell@Sun.COM 			break;
30147836SJohn.Forte@Sun.COM 		}
3015*11547SBill.Gumbrell@Sun.COM 		impl_prop = impl_prop->next;
30167836SJohn.Forte@Sun.COM 	}
30177836SJohn.Forte@Sun.COM 
30187836SJohn.Forte@Sun.COM 	return (err);
30197836SJohn.Forte@Sun.COM }
30207836SJohn.Forte@Sun.COM 
30217836SJohn.Forte@Sun.COM /*
30227836SJohn.Forte@Sun.COM  * This function passes back int type property.
30237836SJohn.Forte@Sun.COM  * map_dev input should be a handle for device.
30247836SJohn.Forte@Sun.COM  *
30257836SJohn.Forte@Sun.COM  * return 0 if OK.
30267836SJohn.Forte@Sun.COM  * return error code otherwise.
30277836SJohn.Forte@Sun.COM  */
30287836SJohn.Forte@Sun.COM int
g_dev_prop_lookup_strings(gfc_dev_t map_dev,const char * prop_name,char ** prop_data)3029*11547SBill.Gumbrell@Sun.COM g_dev_prop_lookup_strings(gfc_dev_t map_dev, const char *prop_name,
3030*11547SBill.Gumbrell@Sun.COM     char **prop_data)
30317836SJohn.Forte@Sun.COM {
30327836SJohn.Forte@Sun.COM 	impl_map_dev_t *impl_dev;
30337836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *impl_prop;
30347836SJohn.Forte@Sun.COM 	int err;
30357836SJohn.Forte@Sun.COM 
30367836SJohn.Forte@Sun.COM 	if (map_dev == NULL) {
30377836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
30387836SJohn.Forte@Sun.COM 	}
30397836SJohn.Forte@Sun.COM 
30407836SJohn.Forte@Sun.COM 	if ((prop_name == NULL) || (prop_data == NULL)) {
30417836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
30427836SJohn.Forte@Sun.COM 	}
30437836SJohn.Forte@Sun.COM 
30447836SJohn.Forte@Sun.COM 	impl_dev = (impl_map_dev_t *)map_dev;
30457836SJohn.Forte@Sun.COM 	impl_prop = impl_dev->prop_list;
30467836SJohn.Forte@Sun.COM 
30477836SJohn.Forte@Sun.COM 	err = L_INVALID_MAP_DEV_PROP_NAME;
30487836SJohn.Forte@Sun.COM 
30497836SJohn.Forte@Sun.COM 	while (impl_prop) {
3050*11547SBill.Gumbrell@Sun.COM 		if (strncmp(impl_prop->prop_name, prop_name,
3051*11547SBill.Gumbrell@Sun.COM 		    strlen(prop_name)) == 0) {
3052*11547SBill.Gumbrell@Sun.COM 			if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3053*11547SBill.Gumbrell@Sun.COM 				err = L_INVALID_MAP_DEV_PROP_TYPE;
3054*11547SBill.Gumbrell@Sun.COM 				break;
3055*11547SBill.Gumbrell@Sun.COM 			}
3056*11547SBill.Gumbrell@Sun.COM 			if (impl_prop->prop_data) {
3057*11547SBill.Gumbrell@Sun.COM 				*prop_data = (char *)(impl_prop->prop_data);
3058*11547SBill.Gumbrell@Sun.COM 				return (0);
3059*11547SBill.Gumbrell@Sun.COM 			} else {
3060*11547SBill.Gumbrell@Sun.COM 				err = impl_prop->prop_error;
3061*11547SBill.Gumbrell@Sun.COM 			}
3062*11547SBill.Gumbrell@Sun.COM 			break;
30637836SJohn.Forte@Sun.COM 		}
3064*11547SBill.Gumbrell@Sun.COM 		impl_prop = impl_prop->next;
30657836SJohn.Forte@Sun.COM 	}
30667836SJohn.Forte@Sun.COM 
30677836SJohn.Forte@Sun.COM 	return (err);
30687836SJohn.Forte@Sun.COM }
30697836SJohn.Forte@Sun.COM 
30707836SJohn.Forte@Sun.COM /*
30717836SJohn.Forte@Sun.COM  * This function returns the handle for the first property of the input device.
30727836SJohn.Forte@Sun.COM  * map_dev input should be a handle form a device.
30737836SJohn.Forte@Sun.COM  *
30747836SJohn.Forte@Sun.COM  * l_err set to 0 if OK.
30757836SJohn.Forte@Sun.COM  * l_err set to error code otherwise.
30767836SJohn.Forte@Sun.COM  */
30777836SJohn.Forte@Sun.COM gfc_prop_t
g_get_first_dev_prop(gfc_dev_t map_dev,int * l_err)3078*11547SBill.Gumbrell@Sun.COM g_get_first_dev_prop(gfc_dev_t map_dev, int *l_err)
30797836SJohn.Forte@Sun.COM {
30807836SJohn.Forte@Sun.COM 	impl_map_dev_t	*impl_dev;
30817836SJohn.Forte@Sun.COM 
30827836SJohn.Forte@Sun.COM 	if (l_err == NULL) {
30837836SJohn.Forte@Sun.COM 		return (NULL);
30847836SJohn.Forte@Sun.COM 	}
30857836SJohn.Forte@Sun.COM 
30867836SJohn.Forte@Sun.COM 	*l_err = 0;
30877836SJohn.Forte@Sun.COM 
30887836SJohn.Forte@Sun.COM 	if (map_dev == NULL) {
30897836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_MAP_DEV_ADDR;
30907836SJohn.Forte@Sun.COM 		return (NULL);
30917836SJohn.Forte@Sun.COM 	}
30927836SJohn.Forte@Sun.COM 
30937836SJohn.Forte@Sun.COM 	impl_dev = (impl_map_dev_t *)map_dev;
30947836SJohn.Forte@Sun.COM 
30957836SJohn.Forte@Sun.COM 	if (impl_dev->prop_list == NULL) {
30967836SJohn.Forte@Sun.COM 		*l_err = L_NO_SUCH_PROP_FOUND;
30977836SJohn.Forte@Sun.COM 	}
30987836SJohn.Forte@Sun.COM 
30997836SJohn.Forte@Sun.COM 	return ((gfc_prop_t)(impl_dev->prop_list));
31007836SJohn.Forte@Sun.COM }
31017836SJohn.Forte@Sun.COM 
31027836SJohn.Forte@Sun.COM /*
31037836SJohn.Forte@Sun.COM  * This function returns the handle for next property handle of the input prop.
31047836SJohn.Forte@Sun.COM  * map_prop input should be a handle for property.
31057836SJohn.Forte@Sun.COM  *
31067836SJohn.Forte@Sun.COM  * l_err set to 0 if OK.
31077836SJohn.Forte@Sun.COM  * l_err set to error code otherwise.
31087836SJohn.Forte@Sun.COM  */
31097836SJohn.Forte@Sun.COM gfc_prop_t
g_get_next_dev_prop(gfc_prop_t map_prop,int * l_err)3110*11547SBill.Gumbrell@Sun.COM g_get_next_dev_prop(gfc_prop_t map_prop, int *l_err)
31117836SJohn.Forte@Sun.COM {
31127836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t	*impl_prop;
31137836SJohn.Forte@Sun.COM 
31147836SJohn.Forte@Sun.COM 	if (l_err == NULL) {
31157836SJohn.Forte@Sun.COM 		return (NULL);
31167836SJohn.Forte@Sun.COM 	}
31177836SJohn.Forte@Sun.COM 
31187836SJohn.Forte@Sun.COM 	*l_err = 0;
31197836SJohn.Forte@Sun.COM 
31207836SJohn.Forte@Sun.COM 	if (map_prop == NULL) {
31217836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_MAP_DEV_PROP;
31227836SJohn.Forte@Sun.COM 		return (NULL);
31237836SJohn.Forte@Sun.COM 	}
31247836SJohn.Forte@Sun.COM 
31257836SJohn.Forte@Sun.COM 	impl_prop = (impl_map_dev_prop_t *)map_prop;
31267836SJohn.Forte@Sun.COM 
31277836SJohn.Forte@Sun.COM 	if (impl_prop->next == NULL) {
31287836SJohn.Forte@Sun.COM 		*l_err = L_NO_SUCH_PROP_FOUND;
31297836SJohn.Forte@Sun.COM 	}
31307836SJohn.Forte@Sun.COM 
31317836SJohn.Forte@Sun.COM 	return ((gfc_prop_t)(impl_prop->next));
31327836SJohn.Forte@Sun.COM }
31337836SJohn.Forte@Sun.COM 
31347836SJohn.Forte@Sun.COM /*
31357836SJohn.Forte@Sun.COM  * This function returns the name of the property of the input prop.
31367836SJohn.Forte@Sun.COM  * map_prop input should be a handle for property.
31377836SJohn.Forte@Sun.COM  *
31387836SJohn.Forte@Sun.COM  * return name string if OK.
31397836SJohn.Forte@Sun.COM  * returns NULL and l_err set to error code otherwise.
31407836SJohn.Forte@Sun.COM  */
31417836SJohn.Forte@Sun.COM char *
g_get_dev_prop_name(gfc_prop_t map_prop,int * l_err)3142*11547SBill.Gumbrell@Sun.COM g_get_dev_prop_name(gfc_prop_t map_prop, int *l_err)
31437836SJohn.Forte@Sun.COM {
31447836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t	*impl_prop;
31457836SJohn.Forte@Sun.COM 
31467836SJohn.Forte@Sun.COM 	if (l_err == NULL) {
31477836SJohn.Forte@Sun.COM 		return (NULL);
31487836SJohn.Forte@Sun.COM 	}
31497836SJohn.Forte@Sun.COM 
31507836SJohn.Forte@Sun.COM 	*l_err = 0;
31517836SJohn.Forte@Sun.COM 
31527836SJohn.Forte@Sun.COM 	if (map_prop == NULL) {
31537836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_MAP_DEV_PROP;
31547836SJohn.Forte@Sun.COM 		return (NULL);
31557836SJohn.Forte@Sun.COM 	}
31567836SJohn.Forte@Sun.COM 
31577836SJohn.Forte@Sun.COM 	impl_prop = (impl_map_dev_prop_t *)map_prop;
31587836SJohn.Forte@Sun.COM 
31597836SJohn.Forte@Sun.COM 	return (impl_prop->prop_name);
31607836SJohn.Forte@Sun.COM }
31617836SJohn.Forte@Sun.COM 
31627836SJohn.Forte@Sun.COM /*
31637836SJohn.Forte@Sun.COM  * This function returns the type of the property of the input prop.
31647836SJohn.Forte@Sun.COM  * map_prop input should be a handle for property.
31657836SJohn.Forte@Sun.COM  *
31667836SJohn.Forte@Sun.COM  * return type if OK.
31677836SJohn.Forte@Sun.COM  * returns GFC_PROP_TYPE_UNKNOWN and l_err set to error code otherwise.
31687836SJohn.Forte@Sun.COM  */
31697836SJohn.Forte@Sun.COM int
g_get_dev_prop_type(gfc_prop_t map_prop,int * l_err)3170*11547SBill.Gumbrell@Sun.COM g_get_dev_prop_type(gfc_prop_t map_prop, int *l_err)
31717836SJohn.Forte@Sun.COM {
31727836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t	*impl_prop;
31737836SJohn.Forte@Sun.COM 
31747836SJohn.Forte@Sun.COM 	if (l_err != NULL) {
31757836SJohn.Forte@Sun.COM 		*l_err = 0;
31767836SJohn.Forte@Sun.COM 	} else {
31777836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
31787836SJohn.Forte@Sun.COM 	}
31797836SJohn.Forte@Sun.COM 
31807836SJohn.Forte@Sun.COM 	if (map_prop == NULL) {
31817836SJohn.Forte@Sun.COM 		*l_err = L_INVALID_MAP_DEV_PROP;
31827836SJohn.Forte@Sun.COM 		return (GFC_PROP_TYPE_UNKNOWN);
31837836SJohn.Forte@Sun.COM 	}
31847836SJohn.Forte@Sun.COM 
31857836SJohn.Forte@Sun.COM 	impl_prop = (impl_map_dev_prop_t *)map_prop;
31867836SJohn.Forte@Sun.COM 
31877836SJohn.Forte@Sun.COM 	return (impl_prop->prop_type);
31887836SJohn.Forte@Sun.COM }
31897836SJohn.Forte@Sun.COM 
31907836SJohn.Forte@Sun.COM /*
31917836SJohn.Forte@Sun.COM  * This function passes back uchar_t type property and its count.
31927836SJohn.Forte@Sun.COM  * map_prop input should be a handle for property.
31937836SJohn.Forte@Sun.COM  *
31947836SJohn.Forte@Sun.COM  * return 0 if OK.
31957836SJohn.Forte@Sun.COM  * return error code otherwise.
31967836SJohn.Forte@Sun.COM  */
31977836SJohn.Forte@Sun.COM int
g_get_dev_prop_bytes(gfc_prop_t map_prop,int * prop_data_count,uchar_t ** prop_data)3198*11547SBill.Gumbrell@Sun.COM g_get_dev_prop_bytes(gfc_prop_t map_prop, int *prop_data_count,
3199*11547SBill.Gumbrell@Sun.COM     uchar_t **prop_data)
32007836SJohn.Forte@Sun.COM {
32017836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *impl_prop;
32027836SJohn.Forte@Sun.COM 
32037836SJohn.Forte@Sun.COM 	if (map_prop == NULL) {
32047836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
32057836SJohn.Forte@Sun.COM 	}
32067836SJohn.Forte@Sun.COM 
32077836SJohn.Forte@Sun.COM 	if ((prop_data == NULL) || (prop_data_count == NULL)) {
32087836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
32097836SJohn.Forte@Sun.COM 	}
32107836SJohn.Forte@Sun.COM 
32117836SJohn.Forte@Sun.COM 	impl_prop = (impl_map_dev_prop_t *)map_prop;
32127836SJohn.Forte@Sun.COM 
32137836SJohn.Forte@Sun.COM 	if (impl_prop->prop_type != GFC_PROP_TYPE_BYTES) {
3214*11547SBill.Gumbrell@Sun.COM 		return (L_INVALID_MAP_DEV_PROP_TYPE);
32157836SJohn.Forte@Sun.COM 	}
32167836SJohn.Forte@Sun.COM 	if (impl_prop->prop_data) {
3217*11547SBill.Gumbrell@Sun.COM 		*prop_data = (uchar_t *)(impl_prop->prop_data);
3218*11547SBill.Gumbrell@Sun.COM 		*prop_data_count = impl_prop->prop_size;
32197836SJohn.Forte@Sun.COM 	} else {
3220*11547SBill.Gumbrell@Sun.COM 		return (impl_prop->prop_error);
32217836SJohn.Forte@Sun.COM 	}
32227836SJohn.Forte@Sun.COM 
32237836SJohn.Forte@Sun.COM 	return (0);
32247836SJohn.Forte@Sun.COM }
32257836SJohn.Forte@Sun.COM 
32267836SJohn.Forte@Sun.COM /*
32277836SJohn.Forte@Sun.COM  * This function passes back int type property.
32287836SJohn.Forte@Sun.COM  * map_prop input should be a handle for property.
32297836SJohn.Forte@Sun.COM  *
32307836SJohn.Forte@Sun.COM  * return 0 if OK.
32317836SJohn.Forte@Sun.COM  * return error code otherwise.
32327836SJohn.Forte@Sun.COM  */
32337836SJohn.Forte@Sun.COM int
g_get_dev_prop_ints(gfc_prop_t map_prop,int ** prop_data)3234*11547SBill.Gumbrell@Sun.COM g_get_dev_prop_ints(gfc_prop_t map_prop, int **prop_data)
32357836SJohn.Forte@Sun.COM {
32367836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *impl_prop;
32377836SJohn.Forte@Sun.COM 
32387836SJohn.Forte@Sun.COM 	if (map_prop == NULL) {
32397836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
32407836SJohn.Forte@Sun.COM 	}
32417836SJohn.Forte@Sun.COM 
32427836SJohn.Forte@Sun.COM 	if (prop_data == NULL) {
32437836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
32447836SJohn.Forte@Sun.COM 	}
32457836SJohn.Forte@Sun.COM 
32467836SJohn.Forte@Sun.COM 	impl_prop = (impl_map_dev_prop_t *)map_prop;
32477836SJohn.Forte@Sun.COM 
32487836SJohn.Forte@Sun.COM 	if (impl_prop->prop_type != GFC_PROP_TYPE_INT) {
3249*11547SBill.Gumbrell@Sun.COM 		return (L_INVALID_MAP_DEV_PROP_TYPE);
32507836SJohn.Forte@Sun.COM 	}
32517836SJohn.Forte@Sun.COM 	if (impl_prop->prop_data) {
3252*11547SBill.Gumbrell@Sun.COM 		*prop_data = (int *)(impl_prop->prop_data);
32537836SJohn.Forte@Sun.COM 	} else {
3254*11547SBill.Gumbrell@Sun.COM 		return (impl_prop->prop_error);
32557836SJohn.Forte@Sun.COM 	}
32567836SJohn.Forte@Sun.COM 
32577836SJohn.Forte@Sun.COM 	return (0);
32587836SJohn.Forte@Sun.COM }
32597836SJohn.Forte@Sun.COM 
32607836SJohn.Forte@Sun.COM /*
32617836SJohn.Forte@Sun.COM  * This function passes back string type property.
32627836SJohn.Forte@Sun.COM  * map_prop input should be a handle for property.
32637836SJohn.Forte@Sun.COM  *
32647836SJohn.Forte@Sun.COM  * return 0 if OK.
32657836SJohn.Forte@Sun.COM  * return error code otherwise.
32667836SJohn.Forte@Sun.COM  */
32677836SJohn.Forte@Sun.COM int
g_get_dev_prop_strings(gfc_prop_t map_prop,char ** prop_data)3268*11547SBill.Gumbrell@Sun.COM g_get_dev_prop_strings(gfc_prop_t map_prop, char **prop_data)
32697836SJohn.Forte@Sun.COM {
32707836SJohn.Forte@Sun.COM 	impl_map_dev_prop_t *impl_prop;
32717836SJohn.Forte@Sun.COM 
32727836SJohn.Forte@Sun.COM 	if (map_prop == NULL) {
32737836SJohn.Forte@Sun.COM 		return (L_INVALID_MAP_DEV_ADDR);
32747836SJohn.Forte@Sun.COM 	}
32757836SJohn.Forte@Sun.COM 
32767836SJohn.Forte@Sun.COM 	if (prop_data == NULL) {
32777836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
32787836SJohn.Forte@Sun.COM 	}
32797836SJohn.Forte@Sun.COM 
32807836SJohn.Forte@Sun.COM 	impl_prop = (impl_map_dev_prop_t *)map_prop;
32817836SJohn.Forte@Sun.COM 
32827836SJohn.Forte@Sun.COM 	if (impl_prop->prop_type != GFC_PROP_TYPE_STRING) {
3283*11547SBill.Gumbrell@Sun.COM 		return (L_INVALID_MAP_DEV_PROP_TYPE);
32847836SJohn.Forte@Sun.COM 	}
32857836SJohn.Forte@Sun.COM 	if (impl_prop->prop_data) {
3286*11547SBill.Gumbrell@Sun.COM 		*prop_data = (char *)(impl_prop->prop_data);
32877836SJohn.Forte@Sun.COM 	} else {
3288*11547SBill.Gumbrell@Sun.COM 		return (impl_prop->prop_error);
32897836SJohn.Forte@Sun.COM 	}
32907836SJohn.Forte@Sun.COM 
32917836SJohn.Forte@Sun.COM 	return (0);
32927836SJohn.Forte@Sun.COM }
32937836SJohn.Forte@Sun.COM 
32947836SJohn.Forte@Sun.COM /*
32957836SJohn.Forte@Sun.COM  * Free the linked list allocated by g_rdls()
32967836SJohn.Forte@Sun.COM  */
32977836SJohn.Forte@Sun.COM static void
g_free_rls(AL_rls * rlsptr)32987836SJohn.Forte@Sun.COM g_free_rls(AL_rls *rlsptr)
32997836SJohn.Forte@Sun.COM {
33007836SJohn.Forte@Sun.COM 	AL_rls *trlsptr;
33017836SJohn.Forte@Sun.COM 
33027836SJohn.Forte@Sun.COM 	while (rlsptr != NULL) {
33037836SJohn.Forte@Sun.COM 		trlsptr = rlsptr->next;
33047836SJohn.Forte@Sun.COM 		free(rlsptr);
33057836SJohn.Forte@Sun.COM 		rlsptr = trlsptr;
33067836SJohn.Forte@Sun.COM 	}
33077836SJohn.Forte@Sun.COM }
33087836SJohn.Forte@Sun.COM 
33097836SJohn.Forte@Sun.COM /*
33107836SJohn.Forte@Sun.COM  * Read the extended link error status block
33117836SJohn.Forte@Sun.COM  * from the specified device and Host Adapter.
33127836SJohn.Forte@Sun.COM  *
33137836SJohn.Forte@Sun.COM  * PARAMS:
33147836SJohn.Forte@Sun.COM  *	path_phys - physical path to an FC device
33157836SJohn.Forte@Sun.COM  *	rls_ptr   - pointer to read link state structure
33167836SJohn.Forte@Sun.COM  *
33177836SJohn.Forte@Sun.COM  * RETURNS:
33187836SJohn.Forte@Sun.COM  *	0	: if OK
33197836SJohn.Forte@Sun.COM  *	non-zero: otherwise
33207836SJohn.Forte@Sun.COM  */
33217836SJohn.Forte@Sun.COM int
g_rdls(char * path_phys,struct al_rls ** rls_ptr,int verbose)33227836SJohn.Forte@Sun.COM g_rdls(char *path_phys, struct al_rls **rls_ptr, int verbose)
33237836SJohn.Forte@Sun.COM {
3324*11547SBill.Gumbrell@Sun.COM 	char		nexus_path[MAXPATHLEN], *nexus_path_ptr;
3325*11547SBill.Gumbrell@Sun.COM 	int		fd, fp_fd, err, length, exp_map_flag = 0, *port_addr;
3326*11547SBill.Gumbrell@Sun.COM 	struct lilpmap	map;
3327*11547SBill.Gumbrell@Sun.COM 	AL_rls		*rls, *c1 = NULL, *c2 = NULL;
3328*11547SBill.Gumbrell@Sun.COM 	uchar_t		i, *port_wwn_byte;
3329*11547SBill.Gumbrell@Sun.COM 	la_wwn_t	port_wwn;
3330*11547SBill.Gumbrell@Sun.COM 	sf_al_map_t	exp_map;
3331*11547SBill.Gumbrell@Sun.COM 	char		*charPtr, fp_path[MAXPATHLEN];
3332*11547SBill.Gumbrell@Sun.COM 	uint_t		dev_type;
3333*11547SBill.Gumbrell@Sun.COM 	struct stat	stbuf;
3334*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
3335*11547SBill.Gumbrell@Sun.COM 	fc_portid_t	rls_req;
3336*11547SBill.Gumbrell@Sun.COM 	fc_rls_acc_t	rls_payload;
3337*11547SBill.Gumbrell@Sun.COM 	gfc_dev_t	map_root, map_dev;
3338*11547SBill.Gumbrell@Sun.COM 	uint32_t	hba_port_top, state;
3339*11547SBill.Gumbrell@Sun.COM 	int		pathcnt = 1, count;
3340*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
3341*11547SBill.Gumbrell@Sun.COM 	int		p_on = 0, p_st = 0;
33427836SJohn.Forte@Sun.COM 
33437836SJohn.Forte@Sun.COM 	/* return invalid path if path_phys is NULL */
33447836SJohn.Forte@Sun.COM 	if (path_phys == NULL) {
33457836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
33467836SJohn.Forte@Sun.COM 	}
33477836SJohn.Forte@Sun.COM 	/* return invalid arg if rls_ptr is NULL */
33487836SJohn.Forte@Sun.COM 	if (rls_ptr == NULL) {
33497836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
33507836SJohn.Forte@Sun.COM 	}
33517836SJohn.Forte@Sun.COM 
33527836SJohn.Forte@Sun.COM 	*rls_ptr = rls = NULL;
33537836SJohn.Forte@Sun.COM 
33547836SJohn.Forte@Sun.COM 	if (strstr(path_phys, SCSI_VHCI) != NULL) {
33557836SJohn.Forte@Sun.COM 		(void) strcpy(fp_path, path_phys);
33567836SJohn.Forte@Sun.COM 		if (g_get_pathlist(fp_path, &pathlist)) {
33577836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
33587836SJohn.Forte@Sun.COM 		}
33597836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
33607836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
33617836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
33627836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
33637836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
3364*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_ONLINE) {
33657836SJohn.Forte@Sun.COM 					p_on = i;
33667836SJohn.Forte@Sun.COM 					break;
33677836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
3368*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_STANDBY) {
33697836SJohn.Forte@Sun.COM 					p_st = i;
33707836SJohn.Forte@Sun.COM 				}
33717836SJohn.Forte@Sun.COM 			}
33727836SJohn.Forte@Sun.COM 		}
33737836SJohn.Forte@Sun.COM 		if (pathlist.path_info[p_on].path_state ==
33747836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
33757836SJohn.Forte@Sun.COM 			/* on_line path */
33767836SJohn.Forte@Sun.COM 			(void) strcpy(fp_path,
3377*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_hba);
33787836SJohn.Forte@Sun.COM 		} else {
33797836SJohn.Forte@Sun.COM 			/* standby or path0 */
33807836SJohn.Forte@Sun.COM 			(void) strcpy(fp_path,
3381*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_hba);
33827836SJohn.Forte@Sun.COM 		}
33837836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
33847836SJohn.Forte@Sun.COM 	} else {
33857836SJohn.Forte@Sun.COM 		(void) strcpy(fp_path, path_phys);
33867836SJohn.Forte@Sun.COM 	}
33877836SJohn.Forte@Sun.COM 
33887836SJohn.Forte@Sun.COM 	/* Get map of devices on this loop. */
33897836SJohn.Forte@Sun.COM 	if ((dev_type = g_get_path_type(fp_path)) == 0) {
33907836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
33917836SJohn.Forte@Sun.COM 	}
33927836SJohn.Forte@Sun.COM 	if (dev_type & FC_FCA_MASK) {
33937836SJohn.Forte@Sun.COM 		if (strstr(path_phys, SCSI_VHCI) != NULL) {
33947836SJohn.Forte@Sun.COM 			(void) strcat(fp_path, FC_CTLR);
33957836SJohn.Forte@Sun.COM 		} else if (strstr(fp_path, DRV_NAME_SSD) ||
33967836SJohn.Forte@Sun.COM 		    strstr(fp_path, DRV_NAME_ST) ||
3397*11547SBill.Gumbrell@Sun.COM 		    strstr(fp_path, SES_NAME)) {
33987836SJohn.Forte@Sun.COM 			if ((charPtr = strrchr(fp_path, '/')) == NULL) {
33997836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
34007836SJohn.Forte@Sun.COM 			}
34017836SJohn.Forte@Sun.COM 			*charPtr = '\0';
34027836SJohn.Forte@Sun.COM 			/* append devctl to the path */
34037836SJohn.Forte@Sun.COM 			(void) strcat(fp_path, FC_CTLR);
34047836SJohn.Forte@Sun.COM 		} else {
34057836SJohn.Forte@Sun.COM 			if (stat(fp_path, &stbuf) < 0) {
34067836SJohn.Forte@Sun.COM 				return (L_LSTAT_ERROR);
34077836SJohn.Forte@Sun.COM 			}
34087836SJohn.Forte@Sun.COM 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
34097836SJohn.Forte@Sun.COM 				/* append devctl to the path */
34107836SJohn.Forte@Sun.COM 				(void) strcat(fp_path, FC_CTLR);
34117836SJohn.Forte@Sun.COM 			}
34127836SJohn.Forte@Sun.COM 		}
34137836SJohn.Forte@Sun.COM 
34147836SJohn.Forte@Sun.COM 		if ((map_root = g_dev_map_init(fp_path, &err,
3415*11547SBill.Gumbrell@Sun.COM 		    MAP_XPORT_PROP_ONLY)) == NULL) {
34167836SJohn.Forte@Sun.COM 			return (err);
34177836SJohn.Forte@Sun.COM 		}
34187836SJohn.Forte@Sun.COM 
34197836SJohn.Forte@Sun.COM 	} else { /* FC4_FCA_MASK type path */
3420*11547SBill.Gumbrell@Sun.COM 		(void) memset(&map, 0, sizeof (struct lilpmap));
3421*11547SBill.Gumbrell@Sun.COM 
3422*11547SBill.Gumbrell@Sun.COM 		if ((err = g_get_nexus_path(path_phys,
34237836SJohn.Forte@Sun.COM 		    &nexus_path_ptr)) != 0) {
3424*11547SBill.Gumbrell@Sun.COM 			return (err);
3425*11547SBill.Gumbrell@Sun.COM 		}
3426*11547SBill.Gumbrell@Sun.COM 		(void) strcpy(nexus_path, nexus_path_ptr);
3427*11547SBill.Gumbrell@Sun.COM 		g_destroy_data(nexus_path_ptr);
34287836SJohn.Forte@Sun.COM 
34297836SJohn.Forte@Sun.COM 		/* open driver */
3430*11547SBill.Gumbrell@Sun.COM 		if ((fd = g_object_open(nexus_path,
3431*11547SBill.Gumbrell@Sun.COM 		    O_NDELAY | O_RDONLY)) == -1)
3432*11547SBill.Gumbrell@Sun.COM 			return (errno);
34337836SJohn.Forte@Sun.COM 
34347836SJohn.Forte@Sun.COM 		/*
34357836SJohn.Forte@Sun.COM 		 * First try using the socal version of the map.
34367836SJohn.Forte@Sun.COM 		 * If that fails get the expanded vesion.
34377836SJohn.Forte@Sun.COM 		 */
3438*11547SBill.Gumbrell@Sun.COM 		if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
3439*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF("  FCIO_GETMAP ioctl failed.\n");
3440*11547SBill.Gumbrell@Sun.COM 			if (ioctl(fd, SFIOCGMAP, &exp_map) != 0) {
3441*11547SBill.Gumbrell@Sun.COM 				I_DPRINTF("  SFIOCGMAP ioctl failed.\n");
3442*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
3443*11547SBill.Gumbrell@Sun.COM 				return (L_SFIOCGMAP_IOCTL_FAIL);
3444*11547SBill.Gumbrell@Sun.COM 			}
3445*11547SBill.Gumbrell@Sun.COM 			/* Check for reasonableness. */
3446*11547SBill.Gumbrell@Sun.COM 			if ((exp_map.sf_count > 126) ||
3447*11547SBill.Gumbrell@Sun.COM 			    (exp_map.sf_count < 0)) {
34487836SJohn.Forte@Sun.COM 				(void) close(fd);
34497836SJohn.Forte@Sun.COM 				return (L_INVALID_LOOP_MAP);
34507836SJohn.Forte@Sun.COM 			}
3451*11547SBill.Gumbrell@Sun.COM 			for (i = 0; i < exp_map.sf_count; i++) {
3452*11547SBill.Gumbrell@Sun.COM 				if (exp_map.sf_addr_pair[i].sf_al_pa > 0xef) {
3453*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
3454*11547SBill.Gumbrell@Sun.COM 					return (L_INVALID_LOOP_MAP);
3455*11547SBill.Gumbrell@Sun.COM 				}
3456*11547SBill.Gumbrell@Sun.COM 			}
3457*11547SBill.Gumbrell@Sun.COM 			length = exp_map.sf_count;
3458*11547SBill.Gumbrell@Sun.COM 			exp_map_flag++;
34597836SJohn.Forte@Sun.COM 		} else {
3460*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF("  g_rdls:"
3461*11547SBill.Gumbrell@Sun.COM 			    " FCIO_GETMAP ioctl returned %d entries.\n",
3462*11547SBill.Gumbrell@Sun.COM 			    map.lilp_length);
3463*11547SBill.Gumbrell@Sun.COM 			/* Check for reasonableness. */
3464*11547SBill.Gumbrell@Sun.COM 			if (map.lilp_length > sizeof (map.lilp_list)) {
3465*11547SBill.Gumbrell@Sun.COM 				(void) close(fd);
3466*11547SBill.Gumbrell@Sun.COM 				return (L_FCIOGETMAP_INVLD_LEN);
3467*11547SBill.Gumbrell@Sun.COM 			}
3468*11547SBill.Gumbrell@Sun.COM 			length = map.lilp_length;
34697836SJohn.Forte@Sun.COM 		}
3470*11547SBill.Gumbrell@Sun.COM 		for (i = 0; i < length; i++) {
3471*11547SBill.Gumbrell@Sun.COM 			if ((c2 = (struct al_rls *)
3472*11547SBill.Gumbrell@Sun.COM 			    g_zalloc(sizeof (struct al_rls))) == NULL) {
3473*11547SBill.Gumbrell@Sun.COM 				close(fd);
3474*11547SBill.Gumbrell@Sun.COM 				return (L_MALLOC_FAILED);
3475*11547SBill.Gumbrell@Sun.COM 			}
3476*11547SBill.Gumbrell@Sun.COM 			if (rls == NULL) {
3477*11547SBill.Gumbrell@Sun.COM 				c1 = rls = c2;
3478*11547SBill.Gumbrell@Sun.COM 			} else {
3479*11547SBill.Gumbrell@Sun.COM 				for (c1 = rls; c1->next; c1 =  c1->next) {};
3480*11547SBill.Gumbrell@Sun.COM 				c1 = c1->next = c2;
3481*11547SBill.Gumbrell@Sun.COM 			}
3482*11547SBill.Gumbrell@Sun.COM 			(void) strcpy(c1->driver_path, nexus_path);
3483*11547SBill.Gumbrell@Sun.COM 			if (exp_map_flag) {
3484*11547SBill.Gumbrell@Sun.COM 				c1->payload.rls_portno = c1->al_ha =
3485*11547SBill.Gumbrell@Sun.COM 				    exp_map.sf_addr_pair[i].sf_al_pa;
34867836SJohn.Forte@Sun.COM 			} else {
3487*11547SBill.Gumbrell@Sun.COM 				c1->payload.rls_portno = c1->al_ha =
3488*11547SBill.Gumbrell@Sun.COM 				    map.lilp_list[i];
34897836SJohn.Forte@Sun.COM 			}
3490*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_linkfail =
3491*11547SBill.Gumbrell@Sun.COM 			    (uint_t)0xff000000; /* get LESB for this port */
3492*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF("  g_rdls:"
3493*11547SBill.Gumbrell@Sun.COM 			    " al_pa 0x%x\n", c1->payload.rls_portno);
3494*11547SBill.Gumbrell@Sun.COM 
3495*11547SBill.Gumbrell@Sun.COM 			if (ioctl(fd, FCIO_LINKSTATUS, &c1->payload) != 0) {
3496*11547SBill.Gumbrell@Sun.COM 				/*
3497*11547SBill.Gumbrell@Sun.COM 				 * The ifp driver will return ENXIO when rls
3498*11547SBill.Gumbrell@Sun.COM 				 * is issued for same initiator on loop when
3499*11547SBill.Gumbrell@Sun.COM 				 * there is more than one on the loop.
3500*11547SBill.Gumbrell@Sun.COM 				 * Rather than completely fail, continue on.
3501*11547SBill.Gumbrell@Sun.COM 				 * Set values in the payload struct to -1 as
3502*11547SBill.Gumbrell@Sun.COM 				 * this is what socal is currently doing for
3503*11547SBill.Gumbrell@Sun.COM 				 * the case of same initiator rls.
3504*11547SBill.Gumbrell@Sun.COM 				 */
3505*11547SBill.Gumbrell@Sun.COM 				if ((dev_type & FC4_PCI_FCA) &&
3506*11547SBill.Gumbrell@Sun.COM 				    (errno == ENXIO)) {
3507*11547SBill.Gumbrell@Sun.COM 					c1->payload.rls_linkfail =
3508*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_syncfail =
3509*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_sigfail =
3510*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_primitiverr =
3511*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_invalidword =
3512*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_invalidcrc =
3513*11547SBill.Gumbrell@Sun.COM 					    (uint_t)0xffffffff;
3514*11547SBill.Gumbrell@Sun.COM 				} else {
3515*11547SBill.Gumbrell@Sun.COM 					I_DPRINTF("  FCIO_LINKSTATUS ioctl"
3516*11547SBill.Gumbrell@Sun.COM 					    " failed with errno %d.\n", errno);
3517*11547SBill.Gumbrell@Sun.COM 					g_free_rls(rls);
3518*11547SBill.Gumbrell@Sun.COM 					(void) close(fd);
3519*11547SBill.Gumbrell@Sun.COM 					return (L_FCIO_LINKSTATUS_FAILED);
3520*11547SBill.Gumbrell@Sun.COM 				}
3521*11547SBill.Gumbrell@Sun.COM 			}
3522*11547SBill.Gumbrell@Sun.COM 			I_DPRINTF("  g_rdls: al_pa returned by ioctl 0x%x\n",
3523*11547SBill.Gumbrell@Sun.COM 			    c1->payload.rls_portno);
35247836SJohn.Forte@Sun.COM 		}
3525*11547SBill.Gumbrell@Sun.COM 		*rls_ptr = rls; /* Pass back pointer */
3526*11547SBill.Gumbrell@Sun.COM 
3527*11547SBill.Gumbrell@Sun.COM 		(void) close(fd);
3528*11547SBill.Gumbrell@Sun.COM 		return (0);
35297836SJohn.Forte@Sun.COM 	}
35307836SJohn.Forte@Sun.COM 
35317836SJohn.Forte@Sun.COM 	/* Now we need to take care of FC_FCA_MASK case.	*/
35327836SJohn.Forte@Sun.COM 	/* we have map created already via g_dev_map_init.	*/
35337836SJohn.Forte@Sun.COM 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
35347836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
35357836SJohn.Forte@Sun.COM 		return (err);
35367836SJohn.Forte@Sun.COM 	}
35377836SJohn.Forte@Sun.COM 
35387836SJohn.Forte@Sun.COM 	if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
35397836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
35407836SJohn.Forte@Sun.COM 		if (err != L_NO_SUCH_DEV_FOUND) {
35417836SJohn.Forte@Sun.COM 			return (err);
35427836SJohn.Forte@Sun.COM 		} else {
35437836SJohn.Forte@Sun.COM 			return (L_NO_DEVICES_FOUND);
35447836SJohn.Forte@Sun.COM 		}
35457836SJohn.Forte@Sun.COM 	}
35467836SJohn.Forte@Sun.COM 
35477836SJohn.Forte@Sun.COM 	while (map_dev) {
3548*11547SBill.Gumbrell@Sun.COM 		if ((err = g_dev_prop_lookup_ints(
3549*11547SBill.Gumbrell@Sun.COM 		    map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3550*11547SBill.Gumbrell@Sun.COM 			g_dev_map_fini(map_root);
3551*11547SBill.Gumbrell@Sun.COM 			g_free_rls(rls);
3552*11547SBill.Gumbrell@Sun.COM 			return (err);
3553*11547SBill.Gumbrell@Sun.COM 		}
3554*11547SBill.Gumbrell@Sun.COM 
3555*11547SBill.Gumbrell@Sun.COM 		if ((c2 = (struct al_rls *)
3556*11547SBill.Gumbrell@Sun.COM 		    g_zalloc(sizeof (struct al_rls))) == NULL) {
3557*11547SBill.Gumbrell@Sun.COM 			g_dev_map_fini(map_root);
3558*11547SBill.Gumbrell@Sun.COM 			g_free_rls(rls);
3559*11547SBill.Gumbrell@Sun.COM 			close(fd);
3560*11547SBill.Gumbrell@Sun.COM 			return (L_MALLOC_FAILED);
3561*11547SBill.Gumbrell@Sun.COM 		}
3562*11547SBill.Gumbrell@Sun.COM 		if (rls == NULL) {
3563*11547SBill.Gumbrell@Sun.COM 			c1 = rls = c2;
3564*11547SBill.Gumbrell@Sun.COM 		} else {
3565*11547SBill.Gumbrell@Sun.COM 			for (c1 = rls; c1->next; c1 =  c1->next) {};
3566*11547SBill.Gumbrell@Sun.COM 			c1 = c1->next = c2;
3567*11547SBill.Gumbrell@Sun.COM 		}
3568*11547SBill.Gumbrell@Sun.COM 		/* Set the al_ha here */
3569*11547SBill.Gumbrell@Sun.COM 		c1->al_ha = rls_req.port_id = *port_addr;
35707836SJohn.Forte@Sun.COM 
35717836SJohn.Forte@Sun.COM 		/*
35727836SJohn.Forte@Sun.COM 		 * fp uses different input/output structures for
35737836SJohn.Forte@Sun.COM 		 * rls. Load the values returned for the fp ioctl
35747836SJohn.Forte@Sun.COM 		 * into the structure passed back to the caller
35757836SJohn.Forte@Sun.COM 		 * Note: There is no reason for the path
35767836SJohn.Forte@Sun.COM 		 * to be loaded into AL_rls as is done for socal/ifp
35777836SJohn.Forte@Sun.COM 		 * above.
35787836SJohn.Forte@Sun.COM 		 */
3579*11547SBill.Gumbrell@Sun.COM 		if ((hba_port_top == FC_TOP_FABRIC) ||
3580*11547SBill.Gumbrell@Sun.COM 		    (hba_port_top == FC_TOP_PUBLIC_LOOP)) {
3581*11547SBill.Gumbrell@Sun.COM 			if ((err = g_dev_prop_lookup_bytes(
3582*11547SBill.Gumbrell@Sun.COM 			    map_dev, PORT_WWN_PROP, &count,
3583*11547SBill.Gumbrell@Sun.COM 			    &port_wwn_byte)) != 0) {
3584*11547SBill.Gumbrell@Sun.COM 				g_dev_map_fini(map_root);
3585*11547SBill.Gumbrell@Sun.COM 				g_free_rls(rls);
3586*11547SBill.Gumbrell@Sun.COM 				return (err);
3587*11547SBill.Gumbrell@Sun.COM 			}
3588*11547SBill.Gumbrell@Sun.COM 			memcpy(port_wwn.raw_wwn, port_wwn_byte, FC_WWN_SIZE);
3589*11547SBill.Gumbrell@Sun.COM 			if ((err = g_get_dev_port_state(
3590*11547SBill.Gumbrell@Sun.COM 			    fp_path, port_wwn, &state)) == 0) {
3591*11547SBill.Gumbrell@Sun.COM 				if (state != PORT_DEVICE_LOGGED_IN) {
3592*11547SBill.Gumbrell@Sun.COM 					if ((err = g_dev_login(fp_path,
3593*11547SBill.Gumbrell@Sun.COM 					    port_wwn)) != 0) {
3594*11547SBill.Gumbrell@Sun.COM 
3595*11547SBill.Gumbrell@Sun.COM 					c1->payload.rls_linkfail =
3596*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_syncfail =
3597*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_sigfail =
3598*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_primitiverr =
3599*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_invalidword =
3600*11547SBill.Gumbrell@Sun.COM 					    c1->payload.rls_invalidcrc =
3601*11547SBill.Gumbrell@Sun.COM 					    (uint_t)0xffffffff;
3602*11547SBill.Gumbrell@Sun.COM 						if (((map_dev =
3603*11547SBill.Gumbrell@Sun.COM 						    g_get_next_dev(map_dev,
3604*11547SBill.Gumbrell@Sun.COM 						    &err))
3605*11547SBill.Gumbrell@Sun.COM 						    == NULL) &&
3606*11547SBill.Gumbrell@Sun.COM 						    (err !=
3607*11547SBill.Gumbrell@Sun.COM 						    L_NO_SUCH_DEV_FOUND)) {
3608*11547SBill.Gumbrell@Sun.COM 							g_dev_map_fini(
3609*11547SBill.Gumbrell@Sun.COM 							    map_root);
3610*11547SBill.Gumbrell@Sun.COM 							g_free_rls(rls);
3611*11547SBill.Gumbrell@Sun.COM 							return (err);
3612*11547SBill.Gumbrell@Sun.COM 						}
3613*11547SBill.Gumbrell@Sun.COM 						continue;
3614*11547SBill.Gumbrell@Sun.COM 					}
3615*11547SBill.Gumbrell@Sun.COM 				}
3616*11547SBill.Gumbrell@Sun.COM 			} /* if g_get_dev_port_state fails proceed. */
3617*11547SBill.Gumbrell@Sun.COM 		}
3618*11547SBill.Gumbrell@Sun.COM 
3619*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
3620*11547SBill.Gumbrell@Sun.COM 		if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
3621*11547SBill.Gumbrell@Sun.COM 			g_dev_map_fini(map_root);
3622*11547SBill.Gumbrell@Sun.COM 			g_free_rls(rls);
3623*11547SBill.Gumbrell@Sun.COM 			return (L_OPEN_PATH_FAIL);
3624*11547SBill.Gumbrell@Sun.COM 		}
3625*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_cmd = FCIO_LINK_STATUS;
3626*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_ibuf = (caddr_t)&rls_req;
3627*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_ilen = sizeof (rls_req);
3628*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_xfer = FCIO_XFER_RW;
3629*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_flags = 0;
3630*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_obuf = (caddr_t)&rls_payload;
3631*11547SBill.Gumbrell@Sun.COM 		fcio.fcio_olen = sizeof (rls_payload);
3632*11547SBill.Gumbrell@Sun.COM 		if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
3633*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_linkfail =
3634*11547SBill.Gumbrell@Sun.COM 			    c1->payload.rls_syncfail =
3635*11547SBill.Gumbrell@Sun.COM 			    c1->payload.rls_sigfail =
3636*11547SBill.Gumbrell@Sun.COM 			    c1->payload.rls_primitiverr =
3637*11547SBill.Gumbrell@Sun.COM 			    c1->payload.rls_invalidword =
3638*11547SBill.Gumbrell@Sun.COM 			    c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
3639*11547SBill.Gumbrell@Sun.COM 		} else {
3640*11547SBill.Gumbrell@Sun.COM 			/*
3641*11547SBill.Gumbrell@Sun.COM 			 * Load the values into the struct passed
3642*11547SBill.Gumbrell@Sun.COM 			 * back to the caller
3643*11547SBill.Gumbrell@Sun.COM 			 */
3644*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_linkfail = rls_payload.rls_link_fail;
3645*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
3646*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
3647*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_primitiverr =
3648*11547SBill.Gumbrell@Sun.COM 			    rls_payload.rls_prim_seq_err;
3649*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_invalidword =
3650*11547SBill.Gumbrell@Sun.COM 			    rls_payload.rls_invalid_word;
3651*11547SBill.Gumbrell@Sun.COM 			c1->payload.rls_invalidcrc =
3652*11547SBill.Gumbrell@Sun.COM 			    rls_payload.rls_invalid_crc;
3653*11547SBill.Gumbrell@Sun.COM 		}
3654*11547SBill.Gumbrell@Sun.COM 		(void) close(fp_fd);
3655*11547SBill.Gumbrell@Sun.COM 
3656*11547SBill.Gumbrell@Sun.COM 		if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
3657*11547SBill.Gumbrell@Sun.COM 		    (err != L_NO_SUCH_DEV_FOUND)) {
36587836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
36597836SJohn.Forte@Sun.COM 			g_free_rls(rls);
36607836SJohn.Forte@Sun.COM 			return (err);
36617836SJohn.Forte@Sun.COM 		}
36627836SJohn.Forte@Sun.COM 	}
36637836SJohn.Forte@Sun.COM 
36647836SJohn.Forte@Sun.COM 	/* for Leadville issue a final call for the initiator */
36657836SJohn.Forte@Sun.COM 
36667836SJohn.Forte@Sun.COM 	if ((err = g_dev_prop_lookup_ints(
3667*11547SBill.Gumbrell@Sun.COM 	    map_root, PORT_ADDR_PROP, &port_addr)) != 0) {
36687836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
36697836SJohn.Forte@Sun.COM 		g_free_rls(rls);
36707836SJohn.Forte@Sun.COM 		return (err);
36717836SJohn.Forte@Sun.COM 	}
36727836SJohn.Forte@Sun.COM 
36737836SJohn.Forte@Sun.COM 	if ((c2 = (struct al_rls *)
36747836SJohn.Forte@Sun.COM 		g_zalloc(sizeof (struct al_rls))) == NULL) {
36757836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
36767836SJohn.Forte@Sun.COM 		g_free_rls(rls);
36777836SJohn.Forte@Sun.COM 		return (L_MALLOC_FAILED);
36787836SJohn.Forte@Sun.COM 	}
36797836SJohn.Forte@Sun.COM 	if (rls == NULL) {
36807836SJohn.Forte@Sun.COM 		c1 = rls = c2;
36817836SJohn.Forte@Sun.COM 	} else {
36827836SJohn.Forte@Sun.COM 		for (c1 = rls; c1->next; c1 =  c1->next) {};
36837836SJohn.Forte@Sun.COM 		c1 = c1->next = c2;
36847836SJohn.Forte@Sun.COM 	}
36857836SJohn.Forte@Sun.COM 
36867836SJohn.Forte@Sun.COM 	c1->al_ha = rls_req.port_id = *port_addr;
36877836SJohn.Forte@Sun.COM 
36887836SJohn.Forte@Sun.COM 	if ((fp_fd = g_object_open(fp_path, O_RDONLY | O_EXCL)) < 0) {
36897836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
36907836SJohn.Forte@Sun.COM 		g_free_rls(rls);
36917836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
36927836SJohn.Forte@Sun.COM 	}
36937836SJohn.Forte@Sun.COM 
36947836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_LINK_STATUS;
36957836SJohn.Forte@Sun.COM 	fcio.fcio_ibuf = (caddr_t)&rls_req;
36967836SJohn.Forte@Sun.COM 	fcio.fcio_ilen = sizeof (rls_req);
36977836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_RW;
36987836SJohn.Forte@Sun.COM 	fcio.fcio_flags = 0;
36997836SJohn.Forte@Sun.COM 	fcio.fcio_cmd_flags = FCIO_CFLAGS_RLS_DEST_NPORT;
37007836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = (caddr_t)&rls_payload;
37017836SJohn.Forte@Sun.COM 	fcio.fcio_olen = sizeof (rls_payload);
37027836SJohn.Forte@Sun.COM 
37037836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fp_fd, &fcio, verbose) != 0) {
37047836SJohn.Forte@Sun.COM 		c1->payload.rls_linkfail =
3705*11547SBill.Gumbrell@Sun.COM 		    c1->payload.rls_syncfail =
3706*11547SBill.Gumbrell@Sun.COM 		    c1->payload.rls_sigfail =
3707*11547SBill.Gumbrell@Sun.COM 		    c1->payload.rls_primitiverr =
3708*11547SBill.Gumbrell@Sun.COM 		    c1->payload.rls_invalidword =
3709*11547SBill.Gumbrell@Sun.COM 		    c1->payload.rls_invalidcrc = (uint_t)0xffffffff;
37107836SJohn.Forte@Sun.COM 	} else {
37117836SJohn.Forte@Sun.COM 		/*
37127836SJohn.Forte@Sun.COM 		 * Load the values into the struct passed
37137836SJohn.Forte@Sun.COM 		 * back to the caller
37147836SJohn.Forte@Sun.COM 		 */
37157836SJohn.Forte@Sun.COM 		c1->payload.rls_linkfail = rls_payload.rls_link_fail;
37167836SJohn.Forte@Sun.COM 		c1->payload.rls_syncfail = rls_payload.rls_sync_loss;
37177836SJohn.Forte@Sun.COM 		c1->payload.rls_sigfail = rls_payload.rls_sig_loss;
37187836SJohn.Forte@Sun.COM 		c1->payload.rls_primitiverr = rls_payload.rls_prim_seq_err;
37197836SJohn.Forte@Sun.COM 		c1->payload.rls_invalidword = rls_payload.rls_invalid_word;
37207836SJohn.Forte@Sun.COM 		c1->payload.rls_invalidcrc = rls_payload.rls_invalid_crc;
37217836SJohn.Forte@Sun.COM 		(void) close(fp_fd);
37227836SJohn.Forte@Sun.COM 	}
37237836SJohn.Forte@Sun.COM 	(void) close(fp_fd);
37247836SJohn.Forte@Sun.COM 
37257836SJohn.Forte@Sun.COM 	*rls_ptr = rls;	/* Pass back pointer */
37267836SJohn.Forte@Sun.COM 
37277836SJohn.Forte@Sun.COM 	g_dev_map_fini(map_root);
37287836SJohn.Forte@Sun.COM 	return (0);
37297836SJohn.Forte@Sun.COM }
37307836SJohn.Forte@Sun.COM 
wwnConversion(uchar_t * wwn)37317836SJohn.Forte@Sun.COM static u_longlong_t wwnConversion(uchar_t *wwn)
37327836SJohn.Forte@Sun.COM {
37337836SJohn.Forte@Sun.COM 	u_longlong_t tmp;
37347836SJohn.Forte@Sun.COM 	memcpy(&tmp, wwn, sizeof (u_longlong_t));
37357836SJohn.Forte@Sun.COM 	return (tmp);
37367836SJohn.Forte@Sun.COM }
37377836SJohn.Forte@Sun.COM 
37387836SJohn.Forte@Sun.COM /*
37397836SJohn.Forte@Sun.COM  * Get device World Wide Name (port and node) for device at path
37407836SJohn.Forte@Sun.COM  * and add all WWNs to the wwn_list_found list.
37417836SJohn.Forte@Sun.COM  *
37427836SJohn.Forte@Sun.COM  * RETURN: 0 O.K.
37437836SJohn.Forte@Sun.COM  *
37447836SJohn.Forte@Sun.COM  * INPUTS:
37457836SJohn.Forte@Sun.COM  *	- path_phys must be of a device, either an IB or disk.
37467836SJohn.Forte@Sun.COM  */
37477836SJohn.Forte@Sun.COM static int
get_wwns(char * path_phys,uchar_t port_wwn[],uchar_t node_wwn[],int * al_pa,struct wwn_list_found_struct ** wwn_list_found)37487836SJohn.Forte@Sun.COM get_wwns(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[], int *al_pa,
3749*11547SBill.Gumbrell@Sun.COM     struct wwn_list_found_struct **wwn_list_found)
37507836SJohn.Forte@Sun.COM {
3751*11547SBill.Gumbrell@Sun.COM 	uint32_t	hba_port_top;
3752*11547SBill.Gumbrell@Sun.COM 	int		i, err, count;
3753*11547SBill.Gumbrell@Sun.COM 	char		*char_ptr, *ptr;
3754*11547SBill.Gumbrell@Sun.COM 	int		found = 0, pathcnt, *port_addr;
3755*11547SBill.Gumbrell@Sun.COM 	unsigned long long 	pwwn;
3756*11547SBill.Gumbrell@Sun.COM 	uchar_t			*port_wwn_byte, *node_wwn_byte;
3757*11547SBill.Gumbrell@Sun.COM 	char		drvr_path[MAXPATHLEN];
3758*11547SBill.Gumbrell@Sun.COM 	int		p_on = 0, p_st = 0;
3759*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
3760*11547SBill.Gumbrell@Sun.COM 	char		pwwn1[WWN_S_LEN];
3761*11547SBill.Gumbrell@Sun.COM 	gfc_dev_t	map_root, map_dev;
3762*11547SBill.Gumbrell@Sun.COM 	hrtime_t	start_time, end_time;
3763*11547SBill.Gumbrell@Sun.COM 	char *env = NULL;
37647836SJohn.Forte@Sun.COM 
37657836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_wwn: Getting device WWN"
3766*11547SBill.Gumbrell@Sun.COM 	    " and al_pa for device: %s\n",
3767*11547SBill.Gumbrell@Sun.COM 	    path_phys);
37687836SJohn.Forte@Sun.COM 
37697836SJohn.Forte@Sun.COM 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
37707836SJohn.Forte@Sun.COM 		start_time = gethrtime();
37717836SJohn.Forte@Sun.COM 	}
37727836SJohn.Forte@Sun.COM 
37737836SJohn.Forte@Sun.COM 	/*
37747836SJohn.Forte@Sun.COM 	 * Get the loop identifier (switch setting) from the path.
37757836SJohn.Forte@Sun.COM 	 *
37767836SJohn.Forte@Sun.COM 	 * This assumes the path looks something like this:
37777836SJohn.Forte@Sun.COM 	 * /devices/.../SUNW,socal@3,0/SUNW,sf@0,0/SUNW,ssd@x,0
37787836SJohn.Forte@Sun.COM 	 * or
37797836SJohn.Forte@Sun.COM 	 * /devices/.../SUNW,qlc@5/SUNW,fp@0,0/SUNW,ssd@x,0
37807836SJohn.Forte@Sun.COM 	 */
37817836SJohn.Forte@Sun.COM 	if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
37827836SJohn.Forte@Sun.COM 		return (L_INVLD_PATH_NO_ATSIGN_FND);
37837836SJohn.Forte@Sun.COM 	}
37847836SJohn.Forte@Sun.COM 	char_ptr++;	/* point to the loop identifier or WWN */
37857836SJohn.Forte@Sun.COM 
37867836SJohn.Forte@Sun.COM 	(void) strcpy(drvr_path, path_phys);
37877836SJohn.Forte@Sun.COM 	/* This function allocs mem for map.dev_addr on success */
37887836SJohn.Forte@Sun.COM 	if (strstr(drvr_path, SCSI_VHCI)) {
37897836SJohn.Forte@Sun.COM 		if (g_get_pathlist(drvr_path, &pathlist)) {
37907836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
37917836SJohn.Forte@Sun.COM 		}
37927836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
37937836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
37947836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
37957836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
37967836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
3797*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_ONLINE) {
37987836SJohn.Forte@Sun.COM 					p_on = i;
37997836SJohn.Forte@Sun.COM 					break;
38007836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
3801*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_STANDBY) {
38027836SJohn.Forte@Sun.COM 					p_st = i;
38037836SJohn.Forte@Sun.COM 				}
38047836SJohn.Forte@Sun.COM 			}
38057836SJohn.Forte@Sun.COM 		}
38067836SJohn.Forte@Sun.COM 		if (p_on == i) {
38077836SJohn.Forte@Sun.COM 			/* on_line path */
38087836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
3809*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_hba);
38107836SJohn.Forte@Sun.COM 			(void) strncpy(pwwn1,
3811*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_addr,
3812*11547SBill.Gumbrell@Sun.COM 			    WWN_S_LEN - 1);
38137836SJohn.Forte@Sun.COM 			pwwn1[WWN_S_LEN - 1] = '\0';
38147836SJohn.Forte@Sun.COM 		} else {
38157836SJohn.Forte@Sun.COM 			/* standby or path0 */
38167836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
3817*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_hba);
38187836SJohn.Forte@Sun.COM 			(void) strncpy(pwwn1,
3819*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_addr,
3820*11547SBill.Gumbrell@Sun.COM 			    WWN_S_LEN - 1);
38217836SJohn.Forte@Sun.COM 			pwwn1[WWN_S_LEN - 1] = '\0';
38227836SJohn.Forte@Sun.COM 		}
38237836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
38247836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, FC_CTLR);
38257836SJohn.Forte@Sun.COM 	}
38267836SJohn.Forte@Sun.COM 	if ((map_root = g_dev_map_init(drvr_path, &err,
3827*11547SBill.Gumbrell@Sun.COM 	    MAP_XPORT_PROP_ONLY)) == NULL) {
38287836SJohn.Forte@Sun.COM 		return (err);
38297836SJohn.Forte@Sun.COM 	}
38307836SJohn.Forte@Sun.COM 
38317836SJohn.Forte@Sun.COM 	if ((err = g_get_map_topology(map_root, &hba_port_top)) != 0) {
38327836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
38337836SJohn.Forte@Sun.COM 		return (err);
38347836SJohn.Forte@Sun.COM 	}
38357836SJohn.Forte@Sun.COM 
38367836SJohn.Forte@Sun.COM 	if (strstr(path_phys, SCSI_VHCI)) {
38377836SJohn.Forte@Sun.COM 		char_ptr = pwwn1;
38387836SJohn.Forte@Sun.COM 	} else {
38397836SJohn.Forte@Sun.COM 		/*
38407836SJohn.Forte@Sun.COM 		 * Format of WWN is
38417836SJohn.Forte@Sun.COM 		 * ssd@w2200002037000f96,0:a,raw
38427836SJohn.Forte@Sun.COM 		 */
38437836SJohn.Forte@Sun.COM 		if (*char_ptr != 'w') {
38447836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
38457836SJohn.Forte@Sun.COM 			return (L_INVLD_WWN_FORMAT);
38467836SJohn.Forte@Sun.COM 		}
38477836SJohn.Forte@Sun.COM 		char_ptr++;
38487836SJohn.Forte@Sun.COM 	}
38497836SJohn.Forte@Sun.COM 	pwwn = strtoull(char_ptr, &ptr, 16);
38507836SJohn.Forte@Sun.COM 	if (ptr == char_ptr) {
38517836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
38527836SJohn.Forte@Sun.COM 		return (L_NO_WWN_FOUND_IN_PATH);
38537836SJohn.Forte@Sun.COM 	}
38547836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_wwn:  Looking for WWN "
38557836SJohn.Forte@Sun.COM 	    "0x%llx\n", pwwn);
38567836SJohn.Forte@Sun.COM 
38577836SJohn.Forte@Sun.COM 	if (((map_dev = g_get_first_dev(map_root, &err)) == NULL) &&
38587836SJohn.Forte@Sun.COM 	    (err != L_NO_SUCH_DEV_FOUND)) {
38597836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
38607836SJohn.Forte@Sun.COM 		return (err);
38617836SJohn.Forte@Sun.COM 	}
38627836SJohn.Forte@Sun.COM 
38637836SJohn.Forte@Sun.COM 	while (map_dev) {
38647836SJohn.Forte@Sun.COM 		if ((err = g_dev_prop_lookup_bytes(map_dev,
3865*11547SBill.Gumbrell@Sun.COM 		    PORT_WWN_PROP, &count, &port_wwn_byte)) != 0) {
38667836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
38677836SJohn.Forte@Sun.COM 			return (err);
38687836SJohn.Forte@Sun.COM 		}
38697836SJohn.Forte@Sun.COM 		if ((err = g_dev_prop_lookup_bytes(map_dev,
3870*11547SBill.Gumbrell@Sun.COM 		    NODE_WWN_PROP, &count, &node_wwn_byte)) != 0) {
38717836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
38727836SJohn.Forte@Sun.COM 			return (err);
38737836SJohn.Forte@Sun.COM 		}
38747836SJohn.Forte@Sun.COM 
38757836SJohn.Forte@Sun.COM 		if (pwwn == wwnConversion(port_wwn_byte) && found != 1) {
38767836SJohn.Forte@Sun.COM 			found = 1;
38777836SJohn.Forte@Sun.COM 			memcpy(port_wwn, port_wwn_byte, FC_WWN_SIZE);
38787836SJohn.Forte@Sun.COM 			memcpy(node_wwn, node_wwn_byte, FC_WWN_SIZE);
38797836SJohn.Forte@Sun.COM 			if ((err = g_dev_prop_lookup_ints(
3880*11547SBill.Gumbrell@Sun.COM 			    map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
38817836SJohn.Forte@Sun.COM 				g_dev_map_fini(map_root);
38827836SJohn.Forte@Sun.COM 				return (err);
38837836SJohn.Forte@Sun.COM 			}
38847836SJohn.Forte@Sun.COM 			*al_pa = *port_addr;
38857836SJohn.Forte@Sun.COM 		}
38867836SJohn.Forte@Sun.COM 		add_wwn_entry(wwn_list_found, port_wwn_byte,
38877836SJohn.Forte@Sun.COM 		    node_wwn_byte);
38887836SJohn.Forte@Sun.COM 
38897836SJohn.Forte@Sun.COM 		if (((map_dev = g_get_next_dev(map_dev, &err)) == NULL) &&
38907836SJohn.Forte@Sun.COM 		    (err != L_NO_SUCH_DEV_FOUND)) {
38917836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
38927836SJohn.Forte@Sun.COM 			return (err);
38937836SJohn.Forte@Sun.COM 		}
38947836SJohn.Forte@Sun.COM 	}
38957836SJohn.Forte@Sun.COM 	if (!found) {
38967836SJohn.Forte@Sun.COM 		g_dev_map_fini(map_root);
38977836SJohn.Forte@Sun.COM 		return (L_NO_LOOP_ADDRS_FOUND);
38987836SJohn.Forte@Sun.COM 	}
38997836SJohn.Forte@Sun.COM 
39007836SJohn.Forte@Sun.COM 	g_dev_map_fini(map_root);
39017836SJohn.Forte@Sun.COM 	if (env != NULL) {
39027836SJohn.Forte@Sun.COM 		end_time = gethrtime();
39037836SJohn.Forte@Sun.COM 		fprintf(stdout, "      get_wwns: "
3904*11547SBill.Gumbrell@Sun.COM 		    "\t\tTime = %lld millisec\n",
3905*11547SBill.Gumbrell@Sun.COM 		    (end_time - start_time)/1000000);
39067836SJohn.Forte@Sun.COM 	}
39077836SJohn.Forte@Sun.COM 	return (0);
39087836SJohn.Forte@Sun.COM }
39097836SJohn.Forte@Sun.COM 
39107836SJohn.Forte@Sun.COM /*
39117836SJohn.Forte@Sun.COM  * Get device World Wide Name and AL_PA for device at path
39127836SJohn.Forte@Sun.COM  *
39137836SJohn.Forte@Sun.COM  * RETURN: 0 O.K.
39147836SJohn.Forte@Sun.COM  *
39157836SJohn.Forte@Sun.COM  * INPUTS:
39167836SJohn.Forte@Sun.COM  *	- path_phys must be of a device, either an IB or disk.
39177836SJohn.Forte@Sun.COM  */
39187836SJohn.Forte@Sun.COM int
g_get_wwn(char * path_phys,uchar_t port_wwn[],uchar_t node_wwn[],int * al_pa,int verbose)39197836SJohn.Forte@Sun.COM g_get_wwn(char *path_phys, uchar_t port_wwn[], uchar_t node_wwn[],
3920*11547SBill.Gumbrell@Sun.COM     int *al_pa, int verbose)
39217836SJohn.Forte@Sun.COM {
39227836SJohn.Forte@Sun.COM 	struct wwn_list_found_struct *wwn_list_found = NULL;
39237836SJohn.Forte@Sun.COM 	int ret;
39247836SJohn.Forte@Sun.COM 
39257836SJohn.Forte@Sun.COM 	/* return invalid path if the argument is NULL */
39267836SJohn.Forte@Sun.COM 	if (path_phys == NULL) {
39277836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
39287836SJohn.Forte@Sun.COM 	}
39297836SJohn.Forte@Sun.COM 	/* return invalid arg if the argument is NULL */
3930*11547SBill.Gumbrell@Sun.COM 	if ((port_wwn == NULL) || (node_wwn == NULL) || (al_pa == NULL)) {
39317836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
39327836SJohn.Forte@Sun.COM 	}
39337836SJohn.Forte@Sun.COM 
39347836SJohn.Forte@Sun.COM 	ret = get_wwns(path_phys, port_wwn, node_wwn, al_pa, &wwn_list_found);
39357836SJohn.Forte@Sun.COM 	g_free_wwn_list_found(&wwn_list_found);
39367836SJohn.Forte@Sun.COM 	return (ret);
39377836SJohn.Forte@Sun.COM }
39387836SJohn.Forte@Sun.COM 
39397836SJohn.Forte@Sun.COM int
g_get_serial_number(char * path,uchar_t * serial_number,size_t * serial_number_len)39407836SJohn.Forte@Sun.COM g_get_serial_number(char *path, uchar_t *serial_number,
39417836SJohn.Forte@Sun.COM     size_t *serial_number_len)
39427836SJohn.Forte@Sun.COM {
3943*11547SBill.Gumbrell@Sun.COM 	int	    fd, status = 0;
3944*11547SBill.Gumbrell@Sun.COM 	L_inquiry80 inq80;
39457836SJohn.Forte@Sun.COM 
39467836SJohn.Forte@Sun.COM 	/* return invalid path if path is NULL */
39477836SJohn.Forte@Sun.COM 	if (path == NULL) {
39487836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
39497836SJohn.Forte@Sun.COM 	}
39507836SJohn.Forte@Sun.COM 	/* return invalid arg if serial_number is NULL */
39517836SJohn.Forte@Sun.COM 	if (serial_number == NULL) {
39527836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
39537836SJohn.Forte@Sun.COM 	}
39547836SJohn.Forte@Sun.COM 
39557836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_serial_number: path: %s\n", path);
39567836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1) {
39577836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
39587836SJohn.Forte@Sun.COM 	}
39597836SJohn.Forte@Sun.COM 	/*
39607836SJohn.Forte@Sun.COM 	 * Call the inquiry cmd on page 0x80 only if the vendor
39617836SJohn.Forte@Sun.COM 	 * supports page 0x80.
39627836SJohn.Forte@Sun.COM 	 */
39637836SJohn.Forte@Sun.COM 	if ((g_find_supported_inq_page(fd, 0x80))) {
39647836SJohn.Forte@Sun.COM 		/*
39657836SJohn.Forte@Sun.COM 		 * Let's retrieve the serial number from page 0x80
39667836SJohn.Forte@Sun.COM 		 * and store it in the inquiry structure
39677836SJohn.Forte@Sun.COM 		 */
39687836SJohn.Forte@Sun.COM 		status = g_scsi_inquiry_cmd80(fd,
39697836SJohn.Forte@Sun.COM 		    (uchar_t *)&inq80,
39707836SJohn.Forte@Sun.COM 		    sizeof (struct l_inquiry80_struct));
39717836SJohn.Forte@Sun.COM 		if (status == 0) {
39727836SJohn.Forte@Sun.COM 			if (*serial_number_len > inq80.inq_page_len)
39737836SJohn.Forte@Sun.COM 				*serial_number_len = inq80.inq_page_len;
39747836SJohn.Forte@Sun.COM 			strncpy((char *)serial_number, (char *)inq80.inq_serial,
39757836SJohn.Forte@Sun.COM 			    *serial_number_len);
39767836SJohn.Forte@Sun.COM 		} else {
39777836SJohn.Forte@Sun.COM 			char unavail[] = "Unavailable";
39787836SJohn.Forte@Sun.COM 			status = 0;
39797836SJohn.Forte@Sun.COM 			if (*serial_number_len > strlen(unavail))
39807836SJohn.Forte@Sun.COM 				*serial_number_len = strlen(unavail);
39817836SJohn.Forte@Sun.COM 			strncpy((char *)serial_number, unavail,
39827836SJohn.Forte@Sun.COM 			    *serial_number_len);
39837836SJohn.Forte@Sun.COM 		}
39847836SJohn.Forte@Sun.COM 	} else {
39857836SJohn.Forte@Sun.COM 		/*
39867836SJohn.Forte@Sun.COM 		 * page 0x80 is not supported, so print the
39877836SJohn.Forte@Sun.COM 		 * appropriate message.
39887836SJohn.Forte@Sun.COM 		 */
39897836SJohn.Forte@Sun.COM 		char unsupp[] = "Unsupported";
39907836SJohn.Forte@Sun.COM 		if (*serial_number_len > strlen(unsupp))
39917836SJohn.Forte@Sun.COM 			*serial_number_len = strlen(unsupp);
39927836SJohn.Forte@Sun.COM 		strncpy((char *)serial_number, unsupp,
39937836SJohn.Forte@Sun.COM 		    *serial_number_len);
39947836SJohn.Forte@Sun.COM 	}
39957836SJohn.Forte@Sun.COM 	(void) close(fd);
39967836SJohn.Forte@Sun.COM 	return (status);
39977836SJohn.Forte@Sun.COM }
39987836SJohn.Forte@Sun.COM 
39997836SJohn.Forte@Sun.COM int
g_get_inquiry(char * path,L_inquiry * l_inquiry)40007836SJohn.Forte@Sun.COM g_get_inquiry(char *path, L_inquiry *l_inquiry)
40017836SJohn.Forte@Sun.COM {
4002*11547SBill.Gumbrell@Sun.COM 	int	    fd, status;
40037836SJohn.Forte@Sun.COM 
40047836SJohn.Forte@Sun.COM 	/* return invalid path if path is NULL */
40057836SJohn.Forte@Sun.COM 	if (path == NULL) {
40067836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
40077836SJohn.Forte@Sun.COM 	}
40087836SJohn.Forte@Sun.COM 	/* return invalid arg if l_inquiry is NULL */
40097836SJohn.Forte@Sun.COM 	if (l_inquiry == NULL) {
40107836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
40117836SJohn.Forte@Sun.COM 	}
40127836SJohn.Forte@Sun.COM 
40137836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_inquiry: path: %s\n", path);
40147836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
40157836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
40167836SJohn.Forte@Sun.COM 	status = g_scsi_inquiry_cmd(fd,
4017*11547SBill.Gumbrell@Sun.COM 	    (uchar_t *)l_inquiry, sizeof (struct l_inquiry_struct));
40187836SJohn.Forte@Sun.COM 
40197836SJohn.Forte@Sun.COM 	(void) close(fd);
40207836SJohn.Forte@Sun.COM 	return (status);
40217836SJohn.Forte@Sun.COM }
40227836SJohn.Forte@Sun.COM 
40237836SJohn.Forte@Sun.COM /*
40247836SJohn.Forte@Sun.COM  * Function to retrieve inquiry page 0x80 from the device
40257836SJohn.Forte@Sun.COM  */
40267836SJohn.Forte@Sun.COM static int
g_scsi_inquiry_cmd80(int fd,uchar_t * buf_ptr,int buf_len)40277836SJohn.Forte@Sun.COM g_scsi_inquiry_cmd80(int fd, uchar_t *buf_ptr, int buf_len)
40287836SJohn.Forte@Sun.COM {
4029*11547SBill.Gumbrell@Sun.COM 	struct uscsi_cmd	ucmd;
4030*11547SBill.Gumbrell@Sun.COM 	my_cdb_g0		cdb = {SCMD_INQUIRY, 0x1, 0x80, 0, 0x10, 0};
4031*11547SBill.Gumbrell@Sun.COM 	struct scsi_extended_sense	sense;
40327836SJohn.Forte@Sun.COM 
40337836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
40347836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
40357836SJohn.Forte@Sun.COM 	cdb.count = (uchar_t)buf_len;
40367836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
40377836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
40387836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
40397836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
40407836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
40417836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
40427836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
40437836SJohn.Forte@Sun.COM 	return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT));
40447836SJohn.Forte@Sun.COM }
40457836SJohn.Forte@Sun.COM 
40467836SJohn.Forte@Sun.COM /*
40477836SJohn.Forte@Sun.COM  * Function to determine if the given page is supported by vendor.
40487836SJohn.Forte@Sun.COM  */
40497836SJohn.Forte@Sun.COM static int
g_find_supported_inq_page(int fd,int page_num)40507836SJohn.Forte@Sun.COM g_find_supported_inq_page(int fd, int page_num)
40517836SJohn.Forte@Sun.COM {
4052*11547SBill.Gumbrell@Sun.COM 	struct	uscsi_cmd	ucmd;
4053*11547SBill.Gumbrell@Sun.COM 	my_cdb_g0	cdb = {SCMD_INQUIRY, 0x1, 0, 0, 0xff, 0};
4054*11547SBill.Gumbrell@Sun.COM 	struct	scsi_extended_sense	sense;
4055*11547SBill.Gumbrell@Sun.COM 	L_inquiry00			inq00;
4056*11547SBill.Gumbrell@Sun.COM 	uchar_t				*data;
4057*11547SBill.Gumbrell@Sun.COM 	int				status = 0;
4058*11547SBill.Gumbrell@Sun.COM 	int				index;
40597836SJohn.Forte@Sun.COM 
40607836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
40617836SJohn.Forte@Sun.COM 	cdb.count = (uchar_t)(sizeof (L_inquiry00));
40627836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
40637836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
40647836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)&inq00;
40657836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = sizeof (inq00);
40667836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
40677836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense);
40687836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
40697836SJohn.Forte@Sun.COM 	status = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT);
40707836SJohn.Forte@Sun.COM 	if (status) {
40717836SJohn.Forte@Sun.COM 		return (0);
40727836SJohn.Forte@Sun.COM 	}
40737836SJohn.Forte@Sun.COM 	data = (uchar_t *)&inq00;
40747836SJohn.Forte@Sun.COM 	for (index = 4; (index <= inq00.len+3)&&
40757836SJohn.Forte@Sun.COM 	    (data[index] <= page_num); index ++) {
40767836SJohn.Forte@Sun.COM 		if (data[index] == page_num) {
40777836SJohn.Forte@Sun.COM 			return (1);
40787836SJohn.Forte@Sun.COM 		}
40797836SJohn.Forte@Sun.COM 	}
40807836SJohn.Forte@Sun.COM 	return (0);
40817836SJohn.Forte@Sun.COM }
40827836SJohn.Forte@Sun.COM 
40837836SJohn.Forte@Sun.COM int
g_get_perf_statistics(char * path,uchar_t * perf_ptr)40847836SJohn.Forte@Sun.COM g_get_perf_statistics(char *path, uchar_t *perf_ptr)
40857836SJohn.Forte@Sun.COM {
4086*11547SBill.Gumbrell@Sun.COM 	int	fd;
40877836SJohn.Forte@Sun.COM 
40887836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_perf_statistics: Get Performance Statistics:"
4089*11547SBill.Gumbrell@Sun.COM 	    "\n  Path:%s\n",
4090*11547SBill.Gumbrell@Sun.COM 	    path);
40917836SJohn.Forte@Sun.COM 
40927836SJohn.Forte@Sun.COM 	/* initialize tables */
40937836SJohn.Forte@Sun.COM 	(void) memset(perf_ptr, 0, sizeof (int));
40947836SJohn.Forte@Sun.COM 
40957836SJohn.Forte@Sun.COM 	/* open controller */
40967836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
40977836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
40987836SJohn.Forte@Sun.COM 
40997836SJohn.Forte@Sun.COM 
41007836SJohn.Forte@Sun.COM 	/* update parameters in the performance table */
41017836SJohn.Forte@Sun.COM 
41027836SJohn.Forte@Sun.COM 	/* get the period in seconds */
41037836SJohn.Forte@Sun.COM 
41047836SJohn.Forte@Sun.COM 
41057836SJohn.Forte@Sun.COM 	(void) close(fd);
41067836SJohn.Forte@Sun.COM 
41077836SJohn.Forte@Sun.COM 	return (0);
41087836SJohn.Forte@Sun.COM }
41097836SJohn.Forte@Sun.COM 
41107836SJohn.Forte@Sun.COM 
41117836SJohn.Forte@Sun.COM int
g_start(char * path)41127836SJohn.Forte@Sun.COM g_start(char *path)
41137836SJohn.Forte@Sun.COM {
4114*11547SBill.Gumbrell@Sun.COM 	int	status;
4115*11547SBill.Gumbrell@Sun.COM 	int	fd;
41167836SJohn.Forte@Sun.COM 
41177836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_start: Start: Path %s\n", path);
41187836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
41197836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
41207836SJohn.Forte@Sun.COM 	status = g_scsi_start_cmd(fd);
41217836SJohn.Forte@Sun.COM 	(void) close(fd);
41227836SJohn.Forte@Sun.COM 	return (status);
41237836SJohn.Forte@Sun.COM }
41247836SJohn.Forte@Sun.COM 
41257836SJohn.Forte@Sun.COM int
g_stop(char * path,int immediate_flag)41267836SJohn.Forte@Sun.COM g_stop(char *path, int immediate_flag)
41277836SJohn.Forte@Sun.COM {
4128*11547SBill.Gumbrell@Sun.COM 	int	status, fd;
41297836SJohn.Forte@Sun.COM 
41307836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_stop: Stop: Path %s\n", path);
41317836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
41327836SJohn.Forte@Sun.COM 		return (errno);
41337836SJohn.Forte@Sun.COM 	status = g_scsi_stop_cmd(fd, immediate_flag);
41347836SJohn.Forte@Sun.COM 	(void) close(fd);
41357836SJohn.Forte@Sun.COM 	return (status);
41367836SJohn.Forte@Sun.COM }
41377836SJohn.Forte@Sun.COM 
41387836SJohn.Forte@Sun.COM int
g_reserve(char * path)41397836SJohn.Forte@Sun.COM g_reserve(char *path)
41407836SJohn.Forte@Sun.COM {
4141*11547SBill.Gumbrell@Sun.COM 	int 	fd, status;
41427836SJohn.Forte@Sun.COM 
41437836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_reserve: Reserve: Path %s\n", path);
41447836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
41457836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
41467836SJohn.Forte@Sun.COM 	status = g_scsi_reserve_cmd(fd);
41477836SJohn.Forte@Sun.COM 	(void) close(fd);
41487836SJohn.Forte@Sun.COM 	return (status);
41497836SJohn.Forte@Sun.COM }
41507836SJohn.Forte@Sun.COM 
41517836SJohn.Forte@Sun.COM int
g_release(char * path)41527836SJohn.Forte@Sun.COM g_release(char *path)
41537836SJohn.Forte@Sun.COM {
4154*11547SBill.Gumbrell@Sun.COM 	int 	fd, status;
41557836SJohn.Forte@Sun.COM 
41567836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_release: Release: Path %s\n", path);
41577836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(path, O_NDELAY | O_RDONLY)) == -1)
41587836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
41597836SJohn.Forte@Sun.COM 	status = g_scsi_release_cmd(fd);
41607836SJohn.Forte@Sun.COM 	(void) close(fd);
41617836SJohn.Forte@Sun.COM 	return (status);
41627836SJohn.Forte@Sun.COM }
41637836SJohn.Forte@Sun.COM 
41647836SJohn.Forte@Sun.COM static char
ctoi(char c)41657836SJohn.Forte@Sun.COM ctoi(char c)
41667836SJohn.Forte@Sun.COM {
41677836SJohn.Forte@Sun.COM 	if ((c >= '0') && (c <= '9'))
41687836SJohn.Forte@Sun.COM 		c -= '0';
41697836SJohn.Forte@Sun.COM 	else if ((c >= 'A') && (c <= 'F'))
41707836SJohn.Forte@Sun.COM 		c = c - 'A' + 10;
41717836SJohn.Forte@Sun.COM 	else if ((c >= 'a') && (c <= 'f'))
41727836SJohn.Forte@Sun.COM 		c = c - 'a' + 10;
41737836SJohn.Forte@Sun.COM 	else
41747836SJohn.Forte@Sun.COM 		c = -1;
41757836SJohn.Forte@Sun.COM 	return (c);
41767836SJohn.Forte@Sun.COM }
41777836SJohn.Forte@Sun.COM 
41787836SJohn.Forte@Sun.COM int
g_string_to_wwn(uchar_t * wwn,uchar_t * wwnp)41797836SJohn.Forte@Sun.COM g_string_to_wwn(uchar_t *wwn, uchar_t *wwnp)
41807836SJohn.Forte@Sun.COM {
41817836SJohn.Forte@Sun.COM 	int	i;
41827836SJohn.Forte@Sun.COM 	char	c, c1;
41837836SJohn.Forte@Sun.COM 
41847836SJohn.Forte@Sun.COM 	*wwnp++ = 0;
41857836SJohn.Forte@Sun.COM 	*wwnp++ = 0;
41867836SJohn.Forte@Sun.COM 	for (i = 0; i < WWN_SIZE - 2; i++, wwnp++) {
41877836SJohn.Forte@Sun.COM 		c = ctoi(*wwn++);
41887836SJohn.Forte@Sun.COM 		c1 = ctoi(*wwn++);
41897836SJohn.Forte@Sun.COM 		if (c == -1 || c1 == -1)
41907836SJohn.Forte@Sun.COM 			return (-1);
41917836SJohn.Forte@Sun.COM 		*wwnp = ((c << 4) + c1);
41927836SJohn.Forte@Sun.COM 	}
41937836SJohn.Forte@Sun.COM 
41947836SJohn.Forte@Sun.COM 	return (0);
41957836SJohn.Forte@Sun.COM 
41967836SJohn.Forte@Sun.COM }
41977836SJohn.Forte@Sun.COM 
41987836SJohn.Forte@Sun.COM /*
41997836SJohn.Forte@Sun.COM  * Converts a string of WWN ASCII characters to a
42007836SJohn.Forte@Sun.COM  * binary representation.
42017836SJohn.Forte@Sun.COM  *
42027836SJohn.Forte@Sun.COM  * Input: string - pointer to uchar_t array
42037836SJohn.Forte@Sun.COM  *		WWN in ASCII
42047836SJohn.Forte@Sun.COM  *		length: 16 bytes
42057836SJohn.Forte@Sun.COM  * Output: wwn - pointer to uchar_t array
42067836SJohn.Forte@Sun.COM  *		containing WWN result
42077836SJohn.Forte@Sun.COM  *		length: 8 bytes
42087836SJohn.Forte@Sun.COM  * Returns:
42097836SJohn.Forte@Sun.COM  *	non-zero on error
42107836SJohn.Forte@Sun.COM  *	zero on success
42117836SJohn.Forte@Sun.COM  */
42127836SJohn.Forte@Sun.COM int
string_to_wwn(uchar_t * string,uchar_t * wwn)42137836SJohn.Forte@Sun.COM string_to_wwn(uchar_t *string, uchar_t *wwn)
42147836SJohn.Forte@Sun.COM {
42157836SJohn.Forte@Sun.COM 	int	i;
42167836SJohn.Forte@Sun.COM 	char	c, c1;
42177836SJohn.Forte@Sun.COM 	uchar_t *wwnp;
42187836SJohn.Forte@Sun.COM 
42197836SJohn.Forte@Sun.COM 	wwnp = wwn;
42207836SJohn.Forte@Sun.COM 
42217836SJohn.Forte@Sun.COM 	for (i = 0; i < WWN_SIZE; i++, wwnp++) {
42227836SJohn.Forte@Sun.COM 
42237836SJohn.Forte@Sun.COM 		c = ctoi(*string++);
42247836SJohn.Forte@Sun.COM 		c1 = ctoi(*string++);
42257836SJohn.Forte@Sun.COM 		if (c == -1 || c1 == -1)
42267836SJohn.Forte@Sun.COM 			return (-1);
42277836SJohn.Forte@Sun.COM 		*wwnp = ((c << 4) + c1);
42287836SJohn.Forte@Sun.COM 	}
42297836SJohn.Forte@Sun.COM 
42307836SJohn.Forte@Sun.COM 	return (0);
42317836SJohn.Forte@Sun.COM 
42327836SJohn.Forte@Sun.COM }
42337836SJohn.Forte@Sun.COM 
42347836SJohn.Forte@Sun.COM 
42357836SJohn.Forte@Sun.COM /*
42367836SJohn.Forte@Sun.COM  * Get multiple paths to a given device port.
42377836SJohn.Forte@Sun.COM  * INPUTS:
42387836SJohn.Forte@Sun.COM  *	port WWN string.
42397836SJohn.Forte@Sun.COM  */
42407836SJohn.Forte@Sun.COM int
g_get_port_multipath(char * port_wwn_s,struct dlist ** dlh,int verbose)42417836SJohn.Forte@Sun.COM g_get_port_multipath(char *port_wwn_s, struct dlist **dlh, int verbose)
42427836SJohn.Forte@Sun.COM {
4243*11547SBill.Gumbrell@Sun.COM 	int		err;
4244*11547SBill.Gumbrell@Sun.COM 	WWN_list	*wwn_list, *wwn_list_ptr;
4245*11547SBill.Gumbrell@Sun.COM 	struct dlist	*dlt, *dl;
42467836SJohn.Forte@Sun.COM 
42477836SJohn.Forte@Sun.COM 
42487836SJohn.Forte@Sun.COM 	/* Initialize list structures. */
42497836SJohn.Forte@Sun.COM 	dl = *dlh  = dlt = (struct dlist *)NULL;
42507836SJohn.Forte@Sun.COM 	wwn_list = wwn_list_ptr = NULL;
42517836SJohn.Forte@Sun.COM 
42527836SJohn.Forte@Sun.COM 	H_DPRINTF("  g_get_port_multipath: Looking for multiple paths for"
4253*11547SBill.Gumbrell@Sun.COM 	    " device with\n    port WWW:"
4254*11547SBill.Gumbrell@Sun.COM 	    "%s\n", port_wwn_s);
42557836SJohn.Forte@Sun.COM 
42567836SJohn.Forte@Sun.COM 	if (err = g_get_wwn_list(&wwn_list, verbose)) {
42577836SJohn.Forte@Sun.COM 		return (err);
42587836SJohn.Forte@Sun.COM 	}
42597836SJohn.Forte@Sun.COM 
42607836SJohn.Forte@Sun.COM 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4261*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
42627836SJohn.Forte@Sun.COM 		if (strcmp(port_wwn_s, wwn_list_ptr->port_wwn_s) == 0) {
42637836SJohn.Forte@Sun.COM 			if ((dl = (struct dlist *)
4264*11547SBill.Gumbrell@Sun.COM 			    g_zalloc(sizeof (struct dlist))) == NULL) {
42657836SJohn.Forte@Sun.COM 				while (*dlh != NULL) {
42667836SJohn.Forte@Sun.COM 					dl = (*dlh)->next;
42677836SJohn.Forte@Sun.COM 					(void) g_destroy_data(*dlh);
42687836SJohn.Forte@Sun.COM 					*dlh = dl;
42697836SJohn.Forte@Sun.COM 				}
42707836SJohn.Forte@Sun.COM 				(void) g_free_wwn_list(&wwn_list);
42717836SJohn.Forte@Sun.COM 				return (L_MALLOC_FAILED);
42727836SJohn.Forte@Sun.COM 			}
42737836SJohn.Forte@Sun.COM 			H_DPRINTF("  g_get_port_multipath:"
4274*11547SBill.Gumbrell@Sun.COM 			    " Found multipath:\n    %s\n",
4275*11547SBill.Gumbrell@Sun.COM 			    wwn_list_ptr->physical_path);
42767836SJohn.Forte@Sun.COM 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
42777836SJohn.Forte@Sun.COM 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
42787836SJohn.Forte@Sun.COM 			if (*dlh == NULL) {
42797836SJohn.Forte@Sun.COM 				*dlh = dlt = dl;
42807836SJohn.Forte@Sun.COM 			} else {
42817836SJohn.Forte@Sun.COM 				dlt->next = dl;
42827836SJohn.Forte@Sun.COM 				dl->prev = dlt;
42837836SJohn.Forte@Sun.COM 				dlt = dl;
42847836SJohn.Forte@Sun.COM 			}
42857836SJohn.Forte@Sun.COM 		}
42867836SJohn.Forte@Sun.COM 	}
42877836SJohn.Forte@Sun.COM 	(void) g_free_wwn_list(&wwn_list);
42887836SJohn.Forte@Sun.COM 	return (0);
42897836SJohn.Forte@Sun.COM }
42907836SJohn.Forte@Sun.COM 
42917836SJohn.Forte@Sun.COM 
42927836SJohn.Forte@Sun.COM 
42937836SJohn.Forte@Sun.COM /*
42947836SJohn.Forte@Sun.COM  * Get multiple paths to a given disk/tape device.
42957836SJohn.Forte@Sun.COM  * The arg: devpath should be the physical path to device.
42967836SJohn.Forte@Sun.COM  *
42977836SJohn.Forte@Sun.COM  * OUTPUT:
42987836SJohn.Forte@Sun.COM  *	multipath_list	points to a list of multiple paths to the device.
42997836SJohn.Forte@Sun.COM  *	NOTE: The caller must free the allocated list (dlist).
43007836SJohn.Forte@Sun.COM  *
43017836SJohn.Forte@Sun.COM  * RETURNS:
43027836SJohn.Forte@Sun.COM  *	0	 if O.K.
43037836SJohn.Forte@Sun.COM  *	non-zero otherwise
43047836SJohn.Forte@Sun.COM  */
43057836SJohn.Forte@Sun.COM int
g_get_multipath(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list,int verbose)43067836SJohn.Forte@Sun.COM g_get_multipath(char *devpath, struct dlist **multipath_list,
4307*11547SBill.Gumbrell@Sun.COM     struct wwn_list_struct *wwn_list, int verbose)
43087836SJohn.Forte@Sun.COM {
4309*11547SBill.Gumbrell@Sun.COM 	int	err;
43107836SJohn.Forte@Sun.COM 
43117836SJohn.Forte@Sun.COM 	H_DPRINTF("  g_get_multipath: Looking for multiple paths for"
4312*11547SBill.Gumbrell@Sun.COM 	    " device at path: %s\n", devpath);
43137836SJohn.Forte@Sun.COM 
43147836SJohn.Forte@Sun.COM 	/* return invalid path if devpath is NULL */
43157836SJohn.Forte@Sun.COM 	if (devpath == NULL) {
43167836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
43177836SJohn.Forte@Sun.COM 	}
43187836SJohn.Forte@Sun.COM 	/* return invalid arg if argument is NULL */
43197836SJohn.Forte@Sun.COM 	if ((multipath_list == NULL) || (wwn_list == NULL)) {
43207836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
43217836SJohn.Forte@Sun.COM 	}
43227836SJohn.Forte@Sun.COM 
43237836SJohn.Forte@Sun.COM 	if (strstr(devpath, DRV_NAME_SSD) != NULL) {
43247836SJohn.Forte@Sun.COM 		err = get_multipath_disk(devpath, multipath_list, wwn_list);
43257836SJohn.Forte@Sun.COM 	} else {
43267836SJohn.Forte@Sun.COM 		err = get_multipath(devpath, multipath_list, wwn_list);
43277836SJohn.Forte@Sun.COM 	}
43287836SJohn.Forte@Sun.COM 
43297836SJohn.Forte@Sun.COM 	return (err);
43307836SJohn.Forte@Sun.COM }
43317836SJohn.Forte@Sun.COM 
43327836SJohn.Forte@Sun.COM 
43337836SJohn.Forte@Sun.COM /*
43347836SJohn.Forte@Sun.COM  * Returns multipath information for a ssd device.
43357836SJohn.Forte@Sun.COM  * Inputs:
43367836SJohn.Forte@Sun.COM  *	devpath: device path to for requested multipath info
43377836SJohn.Forte@Sun.COM  *	wwn_list: returned from g_get_wwn_list or devices_get_all
43387836SJohn.Forte@Sun.COM  * Output:
43397836SJohn.Forte@Sun.COM  *	multipath_list: dlist list of paths
43407836SJohn.Forte@Sun.COM  * Returns:
43417836SJohn.Forte@Sun.COM  *	0 on success
43427836SJohn.Forte@Sun.COM  *	non-zero on failure
43437836SJohn.Forte@Sun.COM  */
43447836SJohn.Forte@Sun.COM int
get_multipath_disk(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list)43457836SJohn.Forte@Sun.COM get_multipath_disk(char *devpath, struct dlist **multipath_list,
4346*11547SBill.Gumbrell@Sun.COM     struct wwn_list_struct *wwn_list)
43477836SJohn.Forte@Sun.COM {
4348*11547SBill.Gumbrell@Sun.COM 	WWN_list	*wwn_list_ptr;
4349*11547SBill.Gumbrell@Sun.COM 	struct dlist	*dl = NULL, *dlt = NULL;
4350*11547SBill.Gumbrell@Sun.COM 	ddi_devid_t	devid = NULL;
4351*11547SBill.Gumbrell@Sun.COM 	int		err;
4352*11547SBill.Gumbrell@Sun.COM 	di_node_t	root;
4353*11547SBill.Gumbrell@Sun.COM 	struct mplist_struct	*mplistp = NULL, *mplisth = NULL;
43547836SJohn.Forte@Sun.COM 
43557836SJohn.Forte@Sun.COM 	if (wwn_list == NULL || multipath_list == NULL || devpath == NULL) {
43567836SJohn.Forte@Sun.COM 		return (L_NULL_WWN_LIST);
43577836SJohn.Forte@Sun.COM 	}
43587836SJohn.Forte@Sun.COM 
43597836SJohn.Forte@Sun.COM 	if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
43607836SJohn.Forte@Sun.COM 		return (L_DEV_SNAPSHOT_FAILED);
43617836SJohn.Forte@Sun.COM 	}
43627836SJohn.Forte@Sun.COM 
43637836SJohn.Forte@Sun.COM 	if ((err = g_devid_get(devpath, &devid, root, SSD_DRVR_NAME)) != 0) {
43647836SJohn.Forte@Sun.COM 		di_fini(root);
43657836SJohn.Forte@Sun.COM 		return (err);
43667836SJohn.Forte@Sun.COM 	}
43677836SJohn.Forte@Sun.COM 
43687836SJohn.Forte@Sun.COM 	*multipath_list = (struct dlist *)NULL;
43697836SJohn.Forte@Sun.COM 	if ((err = devid_get_all(devid, root, SSD_DRVR_NAME, &mplisth)) != 0) {
43707836SJohn.Forte@Sun.COM 		di_fini(root);
43717836SJohn.Forte@Sun.COM 		return (err);
43727836SJohn.Forte@Sun.COM 	}
43737836SJohn.Forte@Sun.COM 
43747836SJohn.Forte@Sun.COM 	if (mplisth == NULL) {
43757836SJohn.Forte@Sun.COM 		di_fini(root);
43767836SJohn.Forte@Sun.COM 		return (L_NULL_WWN_LIST);
43777836SJohn.Forte@Sun.COM 	}
43787836SJohn.Forte@Sun.COM 
43797836SJohn.Forte@Sun.COM 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4380*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
43817836SJohn.Forte@Sun.COM 		/*
43827836SJohn.Forte@Sun.COM 		 * When a path is found from the list, load the logical
43837836SJohn.Forte@Sun.COM 		 * and physical dev path
43847836SJohn.Forte@Sun.COM 		 */
43857836SJohn.Forte@Sun.COM 		for (mplistp = mplisth; mplistp != NULL;
4386*11547SBill.Gumbrell@Sun.COM 		    mplistp = mplistp->next) {
4387*11547SBill.Gumbrell@Sun.COM 			if (strncmp(mplistp->devpath,
4388*11547SBill.Gumbrell@Sun.COM 			    wwn_list_ptr->physical_path,
4389*11547SBill.Gumbrell@Sun.COM 			    strlen(mplistp->devpath)) == 0) {
4390*11547SBill.Gumbrell@Sun.COM 
4391*11547SBill.Gumbrell@Sun.COM 				/* Load multipath list */
4392*11547SBill.Gumbrell@Sun.COM 				if ((dl = (struct dlist *)
4393*11547SBill.Gumbrell@Sun.COM 				    calloc(1, sizeof (struct dlist))) == NULL) {
4394*11547SBill.Gumbrell@Sun.COM 					while (*multipath_list != NULL) {
4395*11547SBill.Gumbrell@Sun.COM 						dl = dlt->next;
4396*11547SBill.Gumbrell@Sun.COM 						g_destroy_data(dlt);
4397*11547SBill.Gumbrell@Sun.COM 						dlt = dl;
4398*11547SBill.Gumbrell@Sun.COM 					}
4399*11547SBill.Gumbrell@Sun.COM 					di_fini(root);
4400*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
4401*11547SBill.Gumbrell@Sun.COM 				}
4402*11547SBill.Gumbrell@Sun.COM 				H_DPRINTF(
4403*11547SBill.Gumbrell@Sun.COM 				    "  g_get_multipath: Found multipath=%s\n",
4404*11547SBill.Gumbrell@Sun.COM 				    wwn_list_ptr->physical_path);
4405*11547SBill.Gumbrell@Sun.COM 				dl->logical_path =
4406*11547SBill.Gumbrell@Sun.COM 				    strdup(wwn_list_ptr->logical_path);
4407*11547SBill.Gumbrell@Sun.COM 				dl->dev_path =
4408*11547SBill.Gumbrell@Sun.COM 				    strdup(wwn_list_ptr->physical_path);
4409*11547SBill.Gumbrell@Sun.COM 				if (*multipath_list == NULL) {
4410*11547SBill.Gumbrell@Sun.COM 					*multipath_list = dlt = dl;
4411*11547SBill.Gumbrell@Sun.COM 				} else {
4412*11547SBill.Gumbrell@Sun.COM 					dlt->next = dl;
4413*11547SBill.Gumbrell@Sun.COM 					dl->prev = dlt;
44147836SJohn.Forte@Sun.COM 					dlt = dl;
44157836SJohn.Forte@Sun.COM 				}
44167836SJohn.Forte@Sun.COM 			}
44177836SJohn.Forte@Sun.COM 		}
44187836SJohn.Forte@Sun.COM 	}
44197836SJohn.Forte@Sun.COM 	di_fini(root);
44207836SJohn.Forte@Sun.COM 	mplist_free(mplisth);
44217836SJohn.Forte@Sun.COM 	return (0);
44227836SJohn.Forte@Sun.COM }
44237836SJohn.Forte@Sun.COM 
44247836SJohn.Forte@Sun.COM int
get_multipath(char * devpath,struct dlist ** multipath_list,struct wwn_list_struct * wwn_list)44257836SJohn.Forte@Sun.COM get_multipath(char *devpath, struct dlist **multipath_list,
44267836SJohn.Forte@Sun.COM 	struct wwn_list_struct *wwn_list)
44277836SJohn.Forte@Sun.COM {
4428*11547SBill.Gumbrell@Sun.COM 	WWN_list	*wwn_list_ptr;
4429*11547SBill.Gumbrell@Sun.COM 	struct dlist	*dl, *dlt;
4430*11547SBill.Gumbrell@Sun.COM 	char		path[MAXPATHLEN], m_phys_path[MAXPATHLEN], *ptr;
4431*11547SBill.Gumbrell@Sun.COM 	int		len;
4432*11547SBill.Gumbrell@Sun.COM 	int		lun_a = -1;
4433*11547SBill.Gumbrell@Sun.COM 	char		node_wwn_s[WWN_S_LEN];
44347836SJohn.Forte@Sun.COM 
44357836SJohn.Forte@Sun.COM 	if (devpath == NULL) {
44367836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
44377836SJohn.Forte@Sun.COM 	}
44387836SJohn.Forte@Sun.COM 
44397836SJohn.Forte@Sun.COM 	/* Strip partition information. */
44407836SJohn.Forte@Sun.COM 	if ((ptr = strrchr(devpath, ':')) != NULL) {
44417836SJohn.Forte@Sun.COM 		len = strlen(devpath) - strlen(ptr);
44427836SJohn.Forte@Sun.COM 		(void) strncpy(path, devpath, len);
44437836SJohn.Forte@Sun.COM 		path[len] = '\0';
44447836SJohn.Forte@Sun.COM 	} else {
44457836SJohn.Forte@Sun.COM 		(void) strcpy(path, devpath);
44467836SJohn.Forte@Sun.COM 	}
44477836SJohn.Forte@Sun.COM 
44487836SJohn.Forte@Sun.COM 	*multipath_list = dl = dlt = (struct dlist *)NULL;
44497836SJohn.Forte@Sun.COM 
44507836SJohn.Forte@Sun.COM 
44517836SJohn.Forte@Sun.COM 	if (wwn_list == NULL) {
44527836SJohn.Forte@Sun.COM 		return (L_NULL_WWN_LIST);
44537836SJohn.Forte@Sun.COM 	}
44547836SJohn.Forte@Sun.COM 
44557836SJohn.Forte@Sun.COM 	for (*node_wwn_s = NULL, wwn_list_ptr = wwn_list;
4456*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr != NULL;
4457*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
44587836SJohn.Forte@Sun.COM 
44597836SJohn.Forte@Sun.COM 		if ((ptr = strrchr(wwn_list_ptr->physical_path, ':')) != NULL) {
44607836SJohn.Forte@Sun.COM 			len = strlen(wwn_list_ptr->physical_path) - strlen(ptr);
44617836SJohn.Forte@Sun.COM 			(void) strncpy(m_phys_path, wwn_list_ptr->physical_path,
4462*11547SBill.Gumbrell@Sun.COM 			    len);
44637836SJohn.Forte@Sun.COM 			m_phys_path[len] = '\0';
44647836SJohn.Forte@Sun.COM 		} else {
44657836SJohn.Forte@Sun.COM 			(void) strcpy(m_phys_path, wwn_list_ptr->physical_path);
44667836SJohn.Forte@Sun.COM 		}
44677836SJohn.Forte@Sun.COM 
44687836SJohn.Forte@Sun.COM 		if (strcasecmp(m_phys_path, path) == 0) {
44697836SJohn.Forte@Sun.COM 			(void) strcpy(node_wwn_s, wwn_list_ptr->node_wwn_s);
44707836SJohn.Forte@Sun.COM 			break;
44717836SJohn.Forte@Sun.COM 		}
44727836SJohn.Forte@Sun.COM 	}
44737836SJohn.Forte@Sun.COM 
44747836SJohn.Forte@Sun.COM 	if (*node_wwn_s == NULL) {
44757836SJohn.Forte@Sun.COM 		H_DPRINTF("node_wwn_s is NULL!\n");
44767836SJohn.Forte@Sun.COM 		return (L_NO_NODE_WWN_IN_WWNLIST);
44777836SJohn.Forte@Sun.COM 	}
44787836SJohn.Forte@Sun.COM 
44797836SJohn.Forte@Sun.COM 	lun_a = g_get_lun_number(wwn_list_ptr->physical_path);
44807836SJohn.Forte@Sun.COM 
44817836SJohn.Forte@Sun.COM 	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4482*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr = wwn_list_ptr->wwn_next) {
44837836SJohn.Forte@Sun.COM 		if ((strcmp(node_wwn_s, wwn_list_ptr->node_wwn_s) == 0) &&
4484*11547SBill.Gumbrell@Sun.COM 		    ((lun_a < 0) || (lun_a ==
4485*11547SBill.Gumbrell@Sun.COM 		    g_get_lun_number(wwn_list_ptr->physical_path)))) {
44867836SJohn.Forte@Sun.COM 
44877836SJohn.Forte@Sun.COM 			if ((dl = (struct dlist *)
4488*11547SBill.Gumbrell@Sun.COM 			    g_zalloc(sizeof (struct dlist))) == NULL) {
44897836SJohn.Forte@Sun.COM 				while (*multipath_list != NULL) {
44907836SJohn.Forte@Sun.COM 					dl = dlt->next;
44917836SJohn.Forte@Sun.COM 					(void) g_destroy_data(dlt);
44927836SJohn.Forte@Sun.COM 					dlt = dl;
44937836SJohn.Forte@Sun.COM 				}
44947836SJohn.Forte@Sun.COM 				return (L_MALLOC_FAILED);
44957836SJohn.Forte@Sun.COM 			}
44967836SJohn.Forte@Sun.COM 			H_DPRINTF("  g_get_multipath: Found multipath=%s\n",
4497*11547SBill.Gumbrell@Sun.COM 			    wwn_list_ptr->physical_path);
44987836SJohn.Forte@Sun.COM 			dl->dev_path = strdup(wwn_list_ptr->physical_path);
44997836SJohn.Forte@Sun.COM 			dl->logical_path = strdup(wwn_list_ptr->logical_path);
45007836SJohn.Forte@Sun.COM 			if (*multipath_list == NULL) {
45017836SJohn.Forte@Sun.COM 				*multipath_list = dlt = dl;
45027836SJohn.Forte@Sun.COM 			} else {
45037836SJohn.Forte@Sun.COM 				dlt->next = dl;
45047836SJohn.Forte@Sun.COM 				dl->prev = dlt;
45057836SJohn.Forte@Sun.COM 				dlt = dl;
45067836SJohn.Forte@Sun.COM 			}
45077836SJohn.Forte@Sun.COM 		}
45087836SJohn.Forte@Sun.COM 	}
45097836SJohn.Forte@Sun.COM 	return (0);
45107836SJohn.Forte@Sun.COM }
45117836SJohn.Forte@Sun.COM 
45127836SJohn.Forte@Sun.COM /*
45137836SJohn.Forte@Sun.COM  * Free a multipath list
45147836SJohn.Forte@Sun.COM  *
45157836SJohn.Forte@Sun.COM  */
45167836SJohn.Forte@Sun.COM void
g_free_multipath(struct dlist * dlh)45177836SJohn.Forte@Sun.COM g_free_multipath(struct dlist *dlh)
45187836SJohn.Forte@Sun.COM {
4519*11547SBill.Gumbrell@Sun.COM 	struct dlist	*dl;
45207836SJohn.Forte@Sun.COM 
45217836SJohn.Forte@Sun.COM 	while (dlh != NULL) {
45227836SJohn.Forte@Sun.COM 		dl = dlh->next;
45237836SJohn.Forte@Sun.COM 		if (dlh->dev_path != NULL)
45247836SJohn.Forte@Sun.COM 			(void) g_destroy_data(dlh->dev_path);
45257836SJohn.Forte@Sun.COM 		if (dlh->logical_path != NULL)
45267836SJohn.Forte@Sun.COM 			(void) g_destroy_data(dlh->logical_path);
45277836SJohn.Forte@Sun.COM 		(void) g_destroy_data(dlh);
45287836SJohn.Forte@Sun.COM 		dlh = dl;
45297836SJohn.Forte@Sun.COM 	}
45307836SJohn.Forte@Sun.COM }
45317836SJohn.Forte@Sun.COM 
45327836SJohn.Forte@Sun.COM 
45337836SJohn.Forte@Sun.COM 
45347836SJohn.Forte@Sun.COM /*
45357836SJohn.Forte@Sun.COM  * Get the path to the nexus (HBA) driver.
45367836SJohn.Forte@Sun.COM  * This assumes the path looks something like this:
45377836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
45387836SJohn.Forte@Sun.COM  * or maybe this
45397836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
45407836SJohn.Forte@Sun.COM  * or
45417836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@1,0
45427836SJohn.Forte@Sun.COM  * or
45437836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@1,0:1
45447836SJohn.Forte@Sun.COM  * or
45457836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
45467836SJohn.Forte@Sun.COM  * (or "qlc" instead of "socal" and "fp" for "sf")
45477836SJohn.Forte@Sun.COM  *
45487836SJohn.Forte@Sun.COM  * Which should resolve to a path like this:
45497836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@1,0:1
45507836SJohn.Forte@Sun.COM  * or
45517836SJohn.Forte@Sun.COM  * /devices/pci@6,2000/pci@2/SUNW,qlc@5
45527836SJohn.Forte@Sun.COM  *
45537836SJohn.Forte@Sun.COM  * or
45547836SJohn.Forte@Sun.COM  * /devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
45557836SJohn.Forte@Sun.COM  * which should resolve to
45567836SJohn.Forte@Sun.COM  * /devices/pci@4,2000/scsi@1:devctl
45577836SJohn.Forte@Sun.COM  */
45587836SJohn.Forte@Sun.COM int
g_get_nexus_path(char * path_phys,char ** nexus_path)45597836SJohn.Forte@Sun.COM g_get_nexus_path(char *path_phys, char **nexus_path)
45607836SJohn.Forte@Sun.COM {
4561*11547SBill.Gumbrell@Sun.COM 	uchar_t		port = 0;
4562*11547SBill.Gumbrell@Sun.COM 	int		port_flag = 0, i = 0, pathcnt = 1;
4563*11547SBill.Gumbrell@Sun.COM 	char		*char_ptr;
4564*11547SBill.Gumbrell@Sun.COM 	char		drvr_path[MAXPATHLEN];
4565*11547SBill.Gumbrell@Sun.COM 	char		buf[MAXPATHLEN];
4566*11547SBill.Gumbrell@Sun.COM 	char		temp_buf[MAXPATHLEN];
4567*11547SBill.Gumbrell@Sun.COM 	struct stat	stbuf;
4568*11547SBill.Gumbrell@Sun.COM 	uint_t		path_type;
4569*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
4570*11547SBill.Gumbrell@Sun.COM 	int		p_on = 0, p_st = 0;
45717836SJohn.Forte@Sun.COM 
45727836SJohn.Forte@Sun.COM 	/* return invalid path if the path_phys is NULL */
45737836SJohn.Forte@Sun.COM 	if (path_phys == NULL) {
45747836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
45757836SJohn.Forte@Sun.COM 	}
45767836SJohn.Forte@Sun.COM 
45777836SJohn.Forte@Sun.COM 	*nexus_path = NULL;
45787836SJohn.Forte@Sun.COM 	(void) strcpy(drvr_path, path_phys);
45797836SJohn.Forte@Sun.COM 
45807836SJohn.Forte@Sun.COM 	if (strstr(path_phys, SCSI_VHCI)) {
45817836SJohn.Forte@Sun.COM 		if (g_get_pathlist(drvr_path, &pathlist)) {
45827836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
45837836SJohn.Forte@Sun.COM 		}
45847836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
45857836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
45867836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
45877836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
45887836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
4589*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_ONLINE) {
45907836SJohn.Forte@Sun.COM 					p_on = i;
45917836SJohn.Forte@Sun.COM 					break;
45927836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
4593*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_STANDBY) {
45947836SJohn.Forte@Sun.COM 					p_st = i;
45957836SJohn.Forte@Sun.COM 				}
45967836SJohn.Forte@Sun.COM 			}
45977836SJohn.Forte@Sun.COM 		}
45987836SJohn.Forte@Sun.COM 		if (pathlist.path_info[p_on].path_state ==
45997836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
46007836SJohn.Forte@Sun.COM 			/* on_line path */
46017836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
4602*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_hba);
46037836SJohn.Forte@Sun.COM 		} else {
46047836SJohn.Forte@Sun.COM 			/* standby or path0 */
46057836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
4606*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_hba);
46077836SJohn.Forte@Sun.COM 		}
46087836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
46097836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, FC_CTLR);
46107836SJohn.Forte@Sun.COM 	} else {
46117836SJohn.Forte@Sun.COM 		if (strstr(drvr_path, DRV_NAME_SSD) || strstr(drvr_path,
4612*11547SBill.Gumbrell@Sun.COM 		    DRV_NAME_ST) || strstr(drvr_path, SES_NAME)) {
46137836SJohn.Forte@Sun.COM 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
46147836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
46157836SJohn.Forte@Sun.COM 			}
46167836SJohn.Forte@Sun.COM 			*char_ptr = '\0';   /* Terminate string  */
46177836SJohn.Forte@Sun.COM 		}
46187836SJohn.Forte@Sun.COM 
46197836SJohn.Forte@Sun.COM 	path_type = g_get_path_type(drvr_path);
46207836SJohn.Forte@Sun.COM 
46217836SJohn.Forte@Sun.COM 	if (path_type & FC4_SF_XPORT) {
46227836SJohn.Forte@Sun.COM 
46237836SJohn.Forte@Sun.COM 		/* sf driver in path so capture the port # */
46247836SJohn.Forte@Sun.COM 		if ((char_ptr = strstr(drvr_path, "sf@")) == NULL) {
46257836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
46267836SJohn.Forte@Sun.COM 		}
46277836SJohn.Forte@Sun.COM 		port = atoi(char_ptr + 3);
46287836SJohn.Forte@Sun.COM 		if (port > 1) {
46297836SJohn.Forte@Sun.COM 			return (L_INVLD_PORT_IN_PATH);
46307836SJohn.Forte@Sun.COM 		}
46317836SJohn.Forte@Sun.COM 
46327836SJohn.Forte@Sun.COM 		if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
46337836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
46347836SJohn.Forte@Sun.COM 		}
46357836SJohn.Forte@Sun.COM 		*char_ptr = '\0';   /* Terminate string  */
46367836SJohn.Forte@Sun.COM 		port_flag++;
46377836SJohn.Forte@Sun.COM 
46387836SJohn.Forte@Sun.COM 		L_DPRINTF("  g_get_nexus_path:"
4639*11547SBill.Gumbrell@Sun.COM 		    " sf driver in path so use port #%d.\n",
4640*11547SBill.Gumbrell@Sun.COM 		    port);
46417836SJohn.Forte@Sun.COM 	} else if (path_type & FC_GEN_XPORT) {
46427836SJohn.Forte@Sun.COM 		/*
46437836SJohn.Forte@Sun.COM 		 * check to see if it 3rd party vendor FCA.
46447836SJohn.Forte@Sun.COM 		 * if it is return error for this operation since
46457836SJohn.Forte@Sun.COM 		 * we don't know how they creates FCA port related minor node.
46467836SJohn.Forte@Sun.COM 		 *
46477836SJohn.Forte@Sun.COM 		 * As of now there is no supported operation on FCA node so
46487836SJohn.Forte@Sun.COM 		 * this should be okay.
46497836SJohn.Forte@Sun.COM 		 */
46507836SJohn.Forte@Sun.COM 		if ((path_type & FC_FCA_MASK) == FC_FCA_MASK) {
46517836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH_TYPE);
46527836SJohn.Forte@Sun.COM 		}
46537836SJohn.Forte@Sun.COM 		/*
46547836SJohn.Forte@Sun.COM 		 * For current Sun FCA driver, appending
46557836SJohn.Forte@Sun.COM 		 * port # doesn't work. Just remove transport layer from
46567836SJohn.Forte@Sun.COM 		 * input path.
46577836SJohn.Forte@Sun.COM 		 */
46587836SJohn.Forte@Sun.COM 		if ((char_ptr = strstr(drvr_path, "/fp@")) == NULL) {
46597836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
46607836SJohn.Forte@Sun.COM 		}
46617836SJohn.Forte@Sun.COM 		*char_ptr = '\0';   /* Terminate string  */
46627836SJohn.Forte@Sun.COM 	}
46637836SJohn.Forte@Sun.COM 
46647836SJohn.Forte@Sun.COM 	if (stat(drvr_path, &stbuf) != 0) {
46657836SJohn.Forte@Sun.COM 		return (L_LSTAT_ERROR);
46667836SJohn.Forte@Sun.COM 	}
46677836SJohn.Forte@Sun.COM 
46687836SJohn.Forte@Sun.COM 	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
46697836SJohn.Forte@Sun.COM 		/*
46707836SJohn.Forte@Sun.COM 		 * Found a directory.
46717836SJohn.Forte@Sun.COM 		 * Now append a port number or devctl to the path.
46727836SJohn.Forte@Sun.COM 		 */
46737836SJohn.Forte@Sun.COM 		if (port_flag) {
46747836SJohn.Forte@Sun.COM 			/* append port */
46757836SJohn.Forte@Sun.COM 			(void) sprintf(buf, ":%d", port);
46767836SJohn.Forte@Sun.COM 		} else {
46777836SJohn.Forte@Sun.COM 			/* Try adding port 0 and see if node exists. */
46787836SJohn.Forte@Sun.COM 			(void) sprintf(temp_buf, "%s:0", drvr_path);
46797836SJohn.Forte@Sun.COM 			if (stat(temp_buf, &stbuf) != 0) {
46807836SJohn.Forte@Sun.COM 				/*
46817836SJohn.Forte@Sun.COM 				 * Path we guessed at does not
46827836SJohn.Forte@Sun.COM 				 * exist so it may be a driver
46837836SJohn.Forte@Sun.COM 				 * that ends in :devctl.
46847836SJohn.Forte@Sun.COM 				 */
46857836SJohn.Forte@Sun.COM 				(void) sprintf(buf, ":devctl");
46867836SJohn.Forte@Sun.COM 			} else {
46877836SJohn.Forte@Sun.COM 				/*
46887836SJohn.Forte@Sun.COM 				 * The path that was entered
46897836SJohn.Forte@Sun.COM 				 * did not include a port number
46907836SJohn.Forte@Sun.COM 				 * so the port was set to zero, and
46917836SJohn.Forte@Sun.COM 				 * then checked. The default path
46927836SJohn.Forte@Sun.COM 				 * did exist.
46937836SJohn.Forte@Sun.COM 				 */
46947836SJohn.Forte@Sun.COM 				ER_DPRINTF("Since a complete path"
4695*11547SBill.Gumbrell@Sun.COM 				    " was not supplied "
4696*11547SBill.Gumbrell@Sun.COM 				    "a default path is being"
4697*11547SBill.Gumbrell@Sun.COM 				    " used:\n  %s\n",
4698*11547SBill.Gumbrell@Sun.COM 				    temp_buf);
46997836SJohn.Forte@Sun.COM 				(void) sprintf(buf, ":0");
47007836SJohn.Forte@Sun.COM 			}
47017836SJohn.Forte@Sun.COM 		}
47027836SJohn.Forte@Sun.COM 
47037836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, buf);
47047836SJohn.Forte@Sun.COM 	}
47057836SJohn.Forte@Sun.COM 
47067836SJohn.Forte@Sun.COM 	}
47077836SJohn.Forte@Sun.COM 	*nexus_path = g_alloc_string(drvr_path);
47087836SJohn.Forte@Sun.COM 	L_DPRINTF("  g_get_nexus_path: Nexus path = %s\n", drvr_path);
47097836SJohn.Forte@Sun.COM 	return (0);
47107836SJohn.Forte@Sun.COM }
47117836SJohn.Forte@Sun.COM 
47127836SJohn.Forte@Sun.COM 
47137836SJohn.Forte@Sun.COM /*
47147836SJohn.Forte@Sun.COM  * Get the FC topology for the input device or nexus(HBA) path.
47157836SJohn.Forte@Sun.COM  *
47167836SJohn.Forte@Sun.COM  * The routine calls g_get_path_type to determine the stack of
47177836SJohn.Forte@Sun.COM  * the input path.
47187836SJohn.Forte@Sun.COM  *
47197836SJohn.Forte@Sun.COM  * 	If it a socal path
47207836SJohn.Forte@Sun.COM  *		it returns FC_TOP_PRIVATE_LOOP
47217836SJohn.Forte@Sun.COM  *	else
47227836SJohn.Forte@Sun.COM  *		calls fc_get_topology ioctl to
47237836SJohn.Forte@Sun.COM  *		get the fp topolgy from the driver.
47247836SJohn.Forte@Sun.COM  *
47257836SJohn.Forte@Sun.COM  * INPUTS:
47267836SJohn.Forte@Sun.COM  *	path - a string of device path, transport path.
47277836SJohn.Forte@Sun.COM  *		NOTE:  "path" SHOULD NOT BE OPEN BEFORE CALLING
47287836SJohn.Forte@Sun.COM  *			THIS FUNCTION BECAUSE THIS FUNCTION DOES
47297836SJohn.Forte@Sun.COM  *			AN "O_EXCL" OPEN.
47307836SJohn.Forte@Sun.COM  *	port_top - a pointer to the toplogy type.
47317836SJohn.Forte@Sun.COM  *
47327836SJohn.Forte@Sun.COM  * RETURNS:
47337836SJohn.Forte@Sun.COM  *	0 if there is no error.
47347836SJohn.Forte@Sun.COM  *	error code.
47357836SJohn.Forte@Sun.COM  *
47367836SJohn.Forte@Sun.COM  * The input path is expected to be something like below:
47377836SJohn.Forte@Sun.COM  * 	1)
47387836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
47397836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@..
47407836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@1,0
47417836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0
47427836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0:1
47437836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
47447836SJohn.Forte@Sun.COM  * 	(or "qlc" instead of "socal" and "fp" for "sf")
47457836SJohn.Forte@Sun.COM  *
47467836SJohn.Forte@Sun.COM  * 	Which should resolve to a path like this:
47477836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0:1
47487836SJohn.Forte@Sun.COM  * 	/devices/pci@6,2000/pci@2/SUNW,qlc@5
47497836SJohn.Forte@Sun.COM  *
47507836SJohn.Forte@Sun.COM  * 	2)
47517836SJohn.Forte@Sun.COM  * 	/devices/pci@4,2000/scsi@1/ses@w50800200000000d2,0:0
47527836SJohn.Forte@Sun.COM  * 	which should resolve to
47537836SJohn.Forte@Sun.COM  * 	/devices/pci@4,2000/scsi@1:devctl
47547836SJohn.Forte@Sun.COM  *
47557836SJohn.Forte@Sun.COM  *      3) The nexus(hba or nexus) path will get an error only for qlc
47567836SJohn.Forte@Sun.COM  *	since the routine need to open fp :devctl node for fcio ioctl.
47577836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0
47587836SJohn.Forte@Sun.COM  * 	/devices/sbus@1f,0/SUNW,socal@1,0:1
47597836SJohn.Forte@Sun.COM  * 	/devices/pci@6,2000/pci@2/SUNW,qlc@5 => error
47607836SJohn.Forte@Sun.COM  */
47617836SJohn.Forte@Sun.COM int
g_get_fca_port_topology(char * path,uint32_t * port_top,int verbose)47627836SJohn.Forte@Sun.COM g_get_fca_port_topology(char *path, uint32_t *port_top, int verbose)
47637836SJohn.Forte@Sun.COM {
4764*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
4765*11547SBill.Gumbrell@Sun.COM 	int		fd, i = 0, pathcnt = 1;
4766*11547SBill.Gumbrell@Sun.COM 	char		drvr_path[MAXPATHLEN];
4767*11547SBill.Gumbrell@Sun.COM 	char		*char_ptr;
4768*11547SBill.Gumbrell@Sun.COM 	struct stat	stbuf;
4769*11547SBill.Gumbrell@Sun.COM 	uint_t		dev_type;
4770*11547SBill.Gumbrell@Sun.COM 	mp_pathlist_t	pathlist;
4771*11547SBill.Gumbrell@Sun.COM 	int		p_on = 0, p_st = 0;
47727836SJohn.Forte@Sun.COM 
47737836SJohn.Forte@Sun.COM 	/* return invalid path if the path is NULL */
47747836SJohn.Forte@Sun.COM 	if (path == NULL) {
47757836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
47767836SJohn.Forte@Sun.COM 	}
47777836SJohn.Forte@Sun.COM 	/* return invalid arg if the argument is NULL */
47787836SJohn.Forte@Sun.COM 	if (port_top == NULL) {
47797836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
47807836SJohn.Forte@Sun.COM 	}
47817836SJohn.Forte@Sun.COM 
47827836SJohn.Forte@Sun.COM 	(void) strcpy(drvr_path, path);
47837836SJohn.Forte@Sun.COM 	if (strstr(path, SCSI_VHCI)) {
47847836SJohn.Forte@Sun.COM 		if (g_get_pathlist(drvr_path, &pathlist)) {
47857836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
47867836SJohn.Forte@Sun.COM 		}
47877836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
47887836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
47897836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
47907836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
47917836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
4792*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_ONLINE) {
47937836SJohn.Forte@Sun.COM 					p_on = i;
47947836SJohn.Forte@Sun.COM 					break;
47957836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
4796*11547SBill.Gumbrell@Sun.COM 				    MDI_PATHINFO_STATE_STANDBY) {
47977836SJohn.Forte@Sun.COM 					p_st = i;
47987836SJohn.Forte@Sun.COM 				}
47997836SJohn.Forte@Sun.COM 			}
48007836SJohn.Forte@Sun.COM 		}
48017836SJohn.Forte@Sun.COM 		if (pathlist.path_info[p_on].path_state ==
48027836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
48037836SJohn.Forte@Sun.COM 			/* on_line path */
48047836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
4805*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_on].path_hba);
48067836SJohn.Forte@Sun.COM 		} else {
48077836SJohn.Forte@Sun.COM 			/* standby or path0 */
48087836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path,
4809*11547SBill.Gumbrell@Sun.COM 			    pathlist.path_info[p_st].path_hba);
48107836SJohn.Forte@Sun.COM 		}
48117836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
48127836SJohn.Forte@Sun.COM 		(void) strcat(drvr_path, FC_CTLR);
48137836SJohn.Forte@Sun.COM 	} else {
48147836SJohn.Forte@Sun.COM 	/*
48157836SJohn.Forte@Sun.COM 	 * Get the path to the :devctl driver
48167836SJohn.Forte@Sun.COM 	 *
48177836SJohn.Forte@Sun.COM 	 * This assumes the path looks something like this:
48187836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
48197836SJohn.Forte@Sun.COM 	 * or
48207836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0
48217836SJohn.Forte@Sun.COM 	 * or
48227836SJohn.Forte@Sun.COM 	 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0:devctl
48237836SJohn.Forte@Sun.COM 	 * or
48247836SJohn.Forte@Sun.COM 	 * a 1 level PCI type driver but still :devctl
48257836SJohn.Forte@Sun.COM 	 * (or "qlc" in the place of "socal" and "fp" for "sf")
48267836SJohn.Forte@Sun.COM 	 *
48277836SJohn.Forte@Sun.COM 	 * The dir below doesn't have corresponding :devctl node.
48287836SJohn.Forte@Sun.COM 	 * /devices/pci@6,2000/pci@2/SUNW,qlc@5
48297836SJohn.Forte@Sun.COM 	 * /devices/sbus@2,0/SUNW,socal@1,0
48307836SJohn.Forte@Sun.COM 	 *
48317836SJohn.Forte@Sun.COM 	 */
48327836SJohn.Forte@Sun.COM 		if ((strstr(drvr_path, DRV_NAME_SSD) ||
4833*11547SBill.Gumbrell@Sun.COM 		    strstr(drvr_path, SES_NAME)) ||
4834*11547SBill.Gumbrell@Sun.COM 		    strstr(drvr_path, DRV_NAME_ST)) {
48357836SJohn.Forte@Sun.COM 			if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
48367836SJohn.Forte@Sun.COM 				return (L_INVALID_PATH);
48377836SJohn.Forte@Sun.COM 			}
48387836SJohn.Forte@Sun.COM 			*char_ptr = '\0';   /* Terminate sting  */
48397836SJohn.Forte@Sun.COM 			/* append controller */
48407836SJohn.Forte@Sun.COM 			(void) strcat(drvr_path, FC_CTLR);
48417836SJohn.Forte@Sun.COM 		} else {
48427836SJohn.Forte@Sun.COM 			if (stat(drvr_path, &stbuf) < 0) {
48437836SJohn.Forte@Sun.COM 				return (L_LSTAT_ERROR);
48447836SJohn.Forte@Sun.COM 			}
48457836SJohn.Forte@Sun.COM 			if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
48467836SJohn.Forte@Sun.COM 				/* append controller */
48477836SJohn.Forte@Sun.COM 				(void) strcat(drvr_path, FC_CTLR);
48487836SJohn.Forte@Sun.COM 			}
48497836SJohn.Forte@Sun.COM 		}
48507836SJohn.Forte@Sun.COM 	}
48517836SJohn.Forte@Sun.COM 
48527836SJohn.Forte@Sun.COM 	if ((dev_type = g_get_path_type(drvr_path)) == 0) {
48537836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
48547836SJohn.Forte@Sun.COM 	}
48557836SJohn.Forte@Sun.COM 
48567836SJohn.Forte@Sun.COM 	if ((dev_type & FC4_XPORT_MASK) || (dev_type & FC4_FCA_MASK)) {
48577836SJohn.Forte@Sun.COM 		*port_top = FC_TOP_PRIVATE_LOOP;
48587836SJohn.Forte@Sun.COM 		return (0);
48597836SJohn.Forte@Sun.COM 	}
48607836SJohn.Forte@Sun.COM 
48617836SJohn.Forte@Sun.COM 	/* To contiue the path type should be fp :devctl node */
48627836SJohn.Forte@Sun.COM 	if (!(dev_type & FC_XPORT_MASK)) {
48637836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
48647836SJohn.Forte@Sun.COM 	}
48657836SJohn.Forte@Sun.COM 
48667836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(drvr_path, O_NDELAY | O_RDONLY)) == -1)
48677836SJohn.Forte@Sun.COM 		return (errno);
48687836SJohn.Forte@Sun.COM 
48697836SJohn.Forte@Sun.COM 	P_DPRINTF("  g_get_fca_port_topology: Geting topology from:"
4870*11547SBill.Gumbrell@Sun.COM 	    " %s\n", drvr_path);
48717836SJohn.Forte@Sun.COM 
48727836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_GET_TOPOLOGY;
48737836SJohn.Forte@Sun.COM 	fcio.fcio_olen = sizeof (uint32_t);
48747836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_READ;
48757836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = (caddr_t)port_top;
48767836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
48777836SJohn.Forte@Sun.COM 		I_DPRINTF(" FCIO_GET_TOPOLOGY ioctl failed.\n");
48787836SJohn.Forte@Sun.COM 		close(fd);
48797836SJohn.Forte@Sun.COM 		return (L_FCIO_GET_TOPOLOGY_FAIL);
48807836SJohn.Forte@Sun.COM 	}
48817836SJohn.Forte@Sun.COM 	close(fd);
48827836SJohn.Forte@Sun.COM 	return (0);
48837836SJohn.Forte@Sun.COM }
48847836SJohn.Forte@Sun.COM 
48857836SJohn.Forte@Sun.COM 
48867836SJohn.Forte@Sun.COM /*
48877836SJohn.Forte@Sun.COM  * This functions enables or disables a FCA port depending on the
48887836SJohn.Forte@Sun.COM  * argument, cmd, passed to it. If cmd is PORT_OFFLINE, the function
48897836SJohn.Forte@Sun.COM  * tries to disable the port specified by the argument 'phys_path'. If
48907836SJohn.Forte@Sun.COM  * cmd is PORT_ONLINE, the function tries to enable the port specified
48917836SJohn.Forte@Sun.COM  * by the argument 'phys_path'.
48927836SJohn.Forte@Sun.COM  * INPUTS :
48937836SJohn.Forte@Sun.COM  *	nexus_port_ptr - Pointer to the nexus path of the FCA port to
48947836SJohn.Forte@Sun.COM  *			operate on
48957836SJohn.Forte@Sun.COM  *	cmd       - PORT_OFFLINE or PORT_ONLINE
48967836SJohn.Forte@Sun.COM  * RETURNS :
48977836SJohn.Forte@Sun.COM  *	0 on success and non-zero otherwise
48987836SJohn.Forte@Sun.COM  */
48997836SJohn.Forte@Sun.COM static int
g_set_port_state(char * nexus_port_ptr,int cmd)49007836SJohn.Forte@Sun.COM g_set_port_state(char *nexus_port_ptr, int cmd)
49017836SJohn.Forte@Sun.COM {
49027836SJohn.Forte@Sun.COM 	int	path_type, fd;
49037836SJohn.Forte@Sun.COM 
49047836SJohn.Forte@Sun.COM 	if ((path_type = g_get_path_type(nexus_port_ptr)) == 0) {
49057836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
49067836SJohn.Forte@Sun.COM 	}
49077836SJohn.Forte@Sun.COM 
49087836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(nexus_port_ptr, O_NDELAY|O_RDONLY)) == -1) {
49097836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
49107836SJohn.Forte@Sun.COM 	}
49117836SJohn.Forte@Sun.COM 
49127836SJohn.Forte@Sun.COM 	switch (cmd) {
49137836SJohn.Forte@Sun.COM 		case PORT_OFFLINE:
49147836SJohn.Forte@Sun.COM 			if (path_type & FC4_SOCAL_FCA) {
49157836SJohn.Forte@Sun.COM 				/*
49167836SJohn.Forte@Sun.COM 				 * Socal/sf drivers -
49177836SJohn.Forte@Sun.COM 				 * The socal driver currently returns EFAULT
49187836SJohn.Forte@Sun.COM 				 * even if the ioctl has completed successfully.
49197836SJohn.Forte@Sun.COM 				 */
49207836SJohn.Forte@Sun.COM 				if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
4921*11547SBill.Gumbrell@Sun.COM 				    NULL) == -1) {
49227836SJohn.Forte@Sun.COM 					close(fd);
49237836SJohn.Forte@Sun.COM 					return (L_PORT_OFFLINE_FAIL);
49247836SJohn.Forte@Sun.COM 				}
49257836SJohn.Forte@Sun.COM 			} else {
49267836SJohn.Forte@Sun.COM 				/*
49277836SJohn.Forte@Sun.COM 				 * QLogic card -
49287836SJohn.Forte@Sun.COM 				 * Can't do much here since the driver currently
49297836SJohn.Forte@Sun.COM 				 * doesn't support this feature. We'll just fail
49307836SJohn.Forte@Sun.COM 				 * for now. Support can be added when the driver
49317836SJohn.Forte@Sun.COM 				 * is enabled with the feature at a later date.
49327836SJohn.Forte@Sun.COM 				 */
49337836SJohn.Forte@Sun.COM 				close(fd);
49347836SJohn.Forte@Sun.COM 				return (L_PORT_OFFLINE_UNSUPPORTED);
49357836SJohn.Forte@Sun.COM 			}
49367836SJohn.Forte@Sun.COM 			break;
49377836SJohn.Forte@Sun.COM 		case PORT_ONLINE:
49387836SJohn.Forte@Sun.COM 			if (path_type & FC4_SOCAL_FCA) {
49397836SJohn.Forte@Sun.COM 				/*
49407836SJohn.Forte@Sun.COM 				 * Socal/sf drivers
49417836SJohn.Forte@Sun.COM 				 * The socal driver currently returns EFAULT
49427836SJohn.Forte@Sun.COM 				 * even if the ioctl has completed successfully.
49437836SJohn.Forte@Sun.COM 				 */
49447836SJohn.Forte@Sun.COM 				if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
49457836SJohn.Forte@Sun.COM 					close(fd);
49467836SJohn.Forte@Sun.COM 					return (L_PORT_ONLINE_FAIL);
49477836SJohn.Forte@Sun.COM 				}
49487836SJohn.Forte@Sun.COM 			} else {
49497836SJohn.Forte@Sun.COM 				/*
49507836SJohn.Forte@Sun.COM 				 * QLogic card -
49517836SJohn.Forte@Sun.COM 				 * Can't do much here since the driver currently
49527836SJohn.Forte@Sun.COM 				 * doesn't support this feature. We'll just fail
49537836SJohn.Forte@Sun.COM 				 * for now. Support can be added when the driver
49547836SJohn.Forte@Sun.COM 				 * is enabled with the feature at a later date.
49557836SJohn.Forte@Sun.COM 				 */
49567836SJohn.Forte@Sun.COM 				close(fd);
49577836SJohn.Forte@Sun.COM 				return (L_PORT_ONLINE_UNSUPPORTED);
49587836SJohn.Forte@Sun.COM 			}
49597836SJohn.Forte@Sun.COM 			break;
49607836SJohn.Forte@Sun.COM 		default:
49617836SJohn.Forte@Sun.COM 			close(fd);
49627836SJohn.Forte@Sun.COM 			return (-1);
49637836SJohn.Forte@Sun.COM 	}
49647836SJohn.Forte@Sun.COM 	close(fd);
49657836SJohn.Forte@Sun.COM 	return (0);
49667836SJohn.Forte@Sun.COM }
49677836SJohn.Forte@Sun.COM 
49687836SJohn.Forte@Sun.COM /*
49697836SJohn.Forte@Sun.COM  * The interfaces defined below (g_port_offline() and g_port_online())
49707836SJohn.Forte@Sun.COM  * are what will be exposed to applications. We will hide g_set_port_state().
49717836SJohn.Forte@Sun.COM  * They have to be functions (as against macros) because making them
49727836SJohn.Forte@Sun.COM  * macros will mean exposing g_set_port_state() and we dont want to do that
49737836SJohn.Forte@Sun.COM  */
49747836SJohn.Forte@Sun.COM 
49757836SJohn.Forte@Sun.COM int
g_port_offline(char * path)49767836SJohn.Forte@Sun.COM g_port_offline(char *path)
49777836SJohn.Forte@Sun.COM {
49787836SJohn.Forte@Sun.COM 	return (g_set_port_state(path, PORT_OFFLINE));
49797836SJohn.Forte@Sun.COM }
49807836SJohn.Forte@Sun.COM 
49817836SJohn.Forte@Sun.COM int
g_port_online(char * path)49827836SJohn.Forte@Sun.COM g_port_online(char *path)
49837836SJohn.Forte@Sun.COM {
49847836SJohn.Forte@Sun.COM 	return (g_set_port_state(path, PORT_ONLINE));
49857836SJohn.Forte@Sun.COM }
49867836SJohn.Forte@Sun.COM 
49877836SJohn.Forte@Sun.COM /*
49887836SJohn.Forte@Sun.COM  * This function sets the loopback mode for a port on a HBA
49897836SJohn.Forte@Sun.COM  * INPUTS :
49907836SJohn.Forte@Sun.COM  *	portpath	- Pointer to the path of the FCA port on which to
49917836SJohn.Forte@Sun.COM  *			set the loopback mode
49927836SJohn.Forte@Sun.COM  *	cmd       	- EXT_LPBACK
49937836SJohn.Forte@Sun.COM  *			  INT_LPBACK
49947836SJohn.Forte@Sun.COM  *			  NO_LPBACK
49957836SJohn.Forte@Sun.COM  * RETURNS :
49967836SJohn.Forte@Sun.COM  *	0 on success and non-zero otherwise
49977836SJohn.Forte@Sun.COM  */
49987836SJohn.Forte@Sun.COM int
g_loopback_mode(char * portpath,int cmd)49997836SJohn.Forte@Sun.COM g_loopback_mode(char *portpath, int cmd)
50007836SJohn.Forte@Sun.COM {
50017836SJohn.Forte@Sun.COM 	int	path_type, fd;
50027836SJohn.Forte@Sun.COM 
50037836SJohn.Forte@Sun.COM 	if ((path_type = g_get_path_type(portpath)) == 0) {
50047836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
50057836SJohn.Forte@Sun.COM 	}
50067836SJohn.Forte@Sun.COM 
50077836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(portpath, O_NDELAY|O_RDONLY|O_EXCL)) == -1) {
50087836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
50097836SJohn.Forte@Sun.COM 	}
50107836SJohn.Forte@Sun.COM 
50117836SJohn.Forte@Sun.COM 	/*
50127836SJohn.Forte@Sun.COM 	 * The loopback calls are currently not fully supported
50137836SJohn.Forte@Sun.COM 	 * via fp.
50147836SJohn.Forte@Sun.COM 	 *
50157836SJohn.Forte@Sun.COM 	 * A fp based general solution is required to support Leadville FCAs
50167836SJohn.Forte@Sun.COM 	 * including Qlgc and 3rd party FCA. As of now qlgc provides
50177836SJohn.Forte@Sun.COM 	 * some diag functions like echo through qlc private ioctl
50187836SJohn.Forte@Sun.COM 	 * which is not supproted by luxadm and libraries.
50197836SJohn.Forte@Sun.COM 	 */
50207836SJohn.Forte@Sun.COM 	switch (cmd) {
50217836SJohn.Forte@Sun.COM 		case EXT_LPBACK:
50227836SJohn.Forte@Sun.COM 			if (path_type & FC4_SOCAL_FCA) {
50237836SJohn.Forte@Sun.COM 				if (ioctl(fd, FCIO_LOOPBACK_MANUAL,
5024*11547SBill.Gumbrell@Sun.COM 				    NULL) == -1) {
50257836SJohn.Forte@Sun.COM 					/* Check for previous mode set */
50267836SJohn.Forte@Sun.COM 					if (errno != EALREADY) {
50277836SJohn.Forte@Sun.COM 						close(fd);
50287836SJohn.Forte@Sun.COM 						return (L_LOOPBACK_FAILED);
50297836SJohn.Forte@Sun.COM 					}
50307836SJohn.Forte@Sun.COM 				}
50317836SJohn.Forte@Sun.COM 			} else {
50327836SJohn.Forte@Sun.COM 				/*
50337836SJohn.Forte@Sun.COM 				 * Well, it wasn't one of the above cards so..
50347836SJohn.Forte@Sun.COM 				 */
50357836SJohn.Forte@Sun.COM 				close(fd);
50367836SJohn.Forte@Sun.COM 				return (L_LOOPBACK_UNSUPPORTED);
50377836SJohn.Forte@Sun.COM 			}
50387836SJohn.Forte@Sun.COM 			break;
50397836SJohn.Forte@Sun.COM 		case NO_LPBACK:
50407836SJohn.Forte@Sun.COM 			if (path_type & FC4_SOCAL_FCA) {
50417836SJohn.Forte@Sun.COM 				if (ioctl(fd, FCIO_NO_LOOPBACK, NULL) == -1) {
50427836SJohn.Forte@Sun.COM 					close(fd);
50437836SJohn.Forte@Sun.COM 					return (L_LOOPBACK_FAILED);
50447836SJohn.Forte@Sun.COM 				}
50457836SJohn.Forte@Sun.COM 			} else {
50467836SJohn.Forte@Sun.COM 				/*
50477836SJohn.Forte@Sun.COM 				 * Well, it wasn't one of the above cards so..
50487836SJohn.Forte@Sun.COM 				 */
50497836SJohn.Forte@Sun.COM 				close(fd);
50507836SJohn.Forte@Sun.COM 				return (L_LOOPBACK_UNSUPPORTED);
50517836SJohn.Forte@Sun.COM 			}
50527836SJohn.Forte@Sun.COM 			break;
50537836SJohn.Forte@Sun.COM 		case INT_LPBACK:
50547836SJohn.Forte@Sun.COM 			if (path_type & FC4_SOCAL_FCA) {
50557836SJohn.Forte@Sun.COM 				if (ioctl(fd, FCIO_LOOPBACK_INTERNAL,
5056*11547SBill.Gumbrell@Sun.COM 				    NULL) == -1) {
50577836SJohn.Forte@Sun.COM 					/* Check for previous mode set */
50587836SJohn.Forte@Sun.COM 					if (errno != EALREADY) {
50597836SJohn.Forte@Sun.COM 						close(fd);
50607836SJohn.Forte@Sun.COM 						return (L_LOOPBACK_FAILED);
50617836SJohn.Forte@Sun.COM 					}
50627836SJohn.Forte@Sun.COM 				}
50637836SJohn.Forte@Sun.COM 			} else {
50647836SJohn.Forte@Sun.COM 				/*
50657836SJohn.Forte@Sun.COM 				 * Well, it wasn't one of the above cards so..
50667836SJohn.Forte@Sun.COM 				 */
50677836SJohn.Forte@Sun.COM 				close(fd);
50687836SJohn.Forte@Sun.COM 				return (L_LOOPBACK_UNSUPPORTED);
50697836SJohn.Forte@Sun.COM 			}
50707836SJohn.Forte@Sun.COM 			break;
50717836SJohn.Forte@Sun.COM 		default:
50727836SJohn.Forte@Sun.COM 			close(fd);
50737836SJohn.Forte@Sun.COM 			return (L_LOOPBACK_UNSUPPORTED);
50747836SJohn.Forte@Sun.COM 	}
50757836SJohn.Forte@Sun.COM 	close(fd);
50767836SJohn.Forte@Sun.COM 	return (0);
50777836SJohn.Forte@Sun.COM }
50787836SJohn.Forte@Sun.COM 
50797836SJohn.Forte@Sun.COM /*
50807836SJohn.Forte@Sun.COM  * g_get_port_state(char *portpath, int port_state)
50817836SJohn.Forte@Sun.COM  * Purpose: Get port state for a path
50827836SJohn.Forte@Sun.COM  * Input:   portpath
50837836SJohn.Forte@Sun.COM  *		set to path of port
50847836SJohn.Forte@Sun.COM  * Output:  port_state
50857836SJohn.Forte@Sun.COM  *	Set to one of the following:
50867836SJohn.Forte@Sun.COM  *		PORT_CONNECTED
50877836SJohn.Forte@Sun.COM  *		PORT_NOTCONNECTED
50887836SJohn.Forte@Sun.COM  * Returns: 0 on success
50897836SJohn.Forte@Sun.COM  *	    non-zero on failure
50907836SJohn.Forte@Sun.COM  */
50917836SJohn.Forte@Sun.COM int
g_get_port_state(char * portpath,int * portstate,int verbose)50927836SJohn.Forte@Sun.COM g_get_port_state(char *portpath, int *portstate, int verbose)
50937836SJohn.Forte@Sun.COM {
50947836SJohn.Forte@Sun.COM 	int	fd, err, num_devices = 0;
50957836SJohn.Forte@Sun.COM 	struct lilpmap	map;
50967836SJohn.Forte@Sun.COM 	uint_t	dev_type;
50977836SJohn.Forte@Sun.COM 	gfc_dev_t	map_root;
50987836SJohn.Forte@Sun.COM 
50997836SJohn.Forte@Sun.COM 
51007836SJohn.Forte@Sun.COM 	(void) memset(&map, 0, sizeof (struct lilpmap));
51017836SJohn.Forte@Sun.COM 
51027836SJohn.Forte@Sun.COM 	/* return invalid path if portpath is NULL */
51037836SJohn.Forte@Sun.COM 	if (portpath == NULL) {
51047836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
51057836SJohn.Forte@Sun.COM 	}
51067836SJohn.Forte@Sun.COM 	/* return invalid arg if argument is NULL */
51077836SJohn.Forte@Sun.COM 	if ((portpath == NULL) || (portstate == NULL)) {
51087836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
51097836SJohn.Forte@Sun.COM 	}
51107836SJohn.Forte@Sun.COM 
51117836SJohn.Forte@Sun.COM 	if ((dev_type = g_get_path_type(portpath)) == 0) {
51127836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
51137836SJohn.Forte@Sun.COM 	}
51147836SJohn.Forte@Sun.COM 
51157836SJohn.Forte@Sun.COM 	/*
51167836SJohn.Forte@Sun.COM 	 * FCIO_GETMAP returns error when there are * no devices attached.
51177836SJohn.Forte@Sun.COM 	 * ENOMEM is returned when no devices are attached.
51187836SJohn.Forte@Sun.COM 	 * g_get_first_dev returns NULL without error when there is no
51197836SJohn.Forte@Sun.COM 	 * devices are attached.
51207836SJohn.Forte@Sun.COM 	 */
51217836SJohn.Forte@Sun.COM 	if (dev_type & FC_FCA_MASK) {
51227836SJohn.Forte@Sun.COM 		if ((map_root = g_dev_map_init(portpath, &err,
5123*11547SBill.Gumbrell@Sun.COM 		    MAP_XPORT_PROP_ONLY)) == NULL) {
51247836SJohn.Forte@Sun.COM 			return (err);
51257836SJohn.Forte@Sun.COM 		}
51267836SJohn.Forte@Sun.COM 
51277836SJohn.Forte@Sun.COM 		if (g_get_first_dev(map_root, &err) == NULL) {
51287836SJohn.Forte@Sun.COM 			/* no device is found if err == 0 */
51297836SJohn.Forte@Sun.COM 			if (err == L_NO_SUCH_DEV_FOUND) {
51307836SJohn.Forte@Sun.COM 				*portstate = PORT_NOTCONNECTED;
51317836SJohn.Forte@Sun.COM 			}
51327836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
51337836SJohn.Forte@Sun.COM 			return (0);
51347836SJohn.Forte@Sun.COM 		} else {
51357836SJohn.Forte@Sun.COM 			/* Device found okay */
51367836SJohn.Forte@Sun.COM 			*portstate = PORT_CONNECTED;
51377836SJohn.Forte@Sun.COM 			g_dev_map_fini(map_root);
51387836SJohn.Forte@Sun.COM 		}
51397836SJohn.Forte@Sun.COM 
51407836SJohn.Forte@Sun.COM 	} else {
51417836SJohn.Forte@Sun.COM 		/* open controller */
51427836SJohn.Forte@Sun.COM 		if ((fd = g_object_open(portpath, O_NDELAY | O_RDONLY)) == -1) {
51437836SJohn.Forte@Sun.COM 			return (errno);
51447836SJohn.Forte@Sun.COM 		}
51457836SJohn.Forte@Sun.COM 
51467836SJohn.Forte@Sun.COM 		/*
51477836SJohn.Forte@Sun.COM 		 * Note: There is only one error returned by this ioctl. ENOMEM.
51487836SJohn.Forte@Sun.COM 		 * Hence the lack of return on error.
51497836SJohn.Forte@Sun.COM 		 */
51507836SJohn.Forte@Sun.COM 		if (ioctl(fd, FCIO_GETMAP, &map) != 0) {
51517836SJohn.Forte@Sun.COM 			map.lilp_length = 0;
51527836SJohn.Forte@Sun.COM 		}
51537836SJohn.Forte@Sun.COM 		num_devices = map.lilp_length;
51547836SJohn.Forte@Sun.COM 
51557836SJohn.Forte@Sun.COM 		/* Non-Leadville stacks report the FCA in the count */
51567836SJohn.Forte@Sun.COM 		*portstate = (num_devices > 1) ? PORT_CONNECTED :
5157*11547SBill.Gumbrell@Sun.COM 		    PORT_NOTCONNECTED;
51587836SJohn.Forte@Sun.COM 		(void) close(fd);
51597836SJohn.Forte@Sun.COM 	}
51607836SJohn.Forte@Sun.COM 	return (0);
51617836SJohn.Forte@Sun.COM }
51627836SJohn.Forte@Sun.COM 
51637836SJohn.Forte@Sun.COM /*
51647836SJohn.Forte@Sun.COM  * g_dev_login(char *port_path, la_wwn_t port_wwn)
51657836SJohn.Forte@Sun.COM  * Purpose: port login via g_dev_log_in_out()
51667836SJohn.Forte@Sun.COM  * Input:   port_path
51677836SJohn.Forte@Sun.COM  *		fc transport port with fabric/public loop topology
51687836SJohn.Forte@Sun.COM  *	    port_wwn
51697836SJohn.Forte@Sun.COM  *		port wwn of device node to login
51707836SJohn.Forte@Sun.COM  *
51717836SJohn.Forte@Sun.COM  * Returns: return code from g_dev_log_in_out()
51727836SJohn.Forte@Sun.COM  */
51737836SJohn.Forte@Sun.COM int
g_dev_login(char * port_path,la_wwn_t port_wwn)51747836SJohn.Forte@Sun.COM g_dev_login(char *port_path, la_wwn_t port_wwn)
51757836SJohn.Forte@Sun.COM {
51767836SJohn.Forte@Sun.COM 	return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGIN));
51777836SJohn.Forte@Sun.COM }
51787836SJohn.Forte@Sun.COM 
51797836SJohn.Forte@Sun.COM 
51807836SJohn.Forte@Sun.COM /*
51817836SJohn.Forte@Sun.COM  * g_dev_logout(char *port_path, la_wwn_t port_wwn)
51827836SJohn.Forte@Sun.COM  * Purpose: port login via g_dev_log_in_out()
51837836SJohn.Forte@Sun.COM  * Input:   port_path
51847836SJohn.Forte@Sun.COM  *		fc transport port with fabric/public loop topology
51857836SJohn.Forte@Sun.COM  *	    port_wwn
51867836SJohn.Forte@Sun.COM  *		port wwn of device node to logout
51877836SJohn.Forte@Sun.COM  *
51887836SJohn.Forte@Sun.COM  * Returns: return code from g_dev_log_in_out()
51897836SJohn.Forte@Sun.COM  */
51907836SJohn.Forte@Sun.COM int
g_dev_logout(char * port_path,la_wwn_t port_wwn)51917836SJohn.Forte@Sun.COM g_dev_logout(char *port_path, la_wwn_t port_wwn)
51927836SJohn.Forte@Sun.COM {
51937836SJohn.Forte@Sun.COM 	return (g_dev_log_in_out(port_path, port_wwn, FCIO_DEV_LOGOUT));
51947836SJohn.Forte@Sun.COM }
51957836SJohn.Forte@Sun.COM 
51967836SJohn.Forte@Sun.COM 
51977836SJohn.Forte@Sun.COM /*
51987836SJohn.Forte@Sun.COM  * g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
51997836SJohn.Forte@Sun.COM  * Purpose: port login via FCIO_DEV_LOGOUT and port logout via FCIO_DEV_LOGOUT
52007836SJohn.Forte@Sun.COM  *	    IOCTL requires EXCLUSIVE open.
52017836SJohn.Forte@Sun.COM  * Input:   port_path
52027836SJohn.Forte@Sun.COM  *		fc transport port with fabric/public loop topology
52037836SJohn.Forte@Sun.COM  *	    port_wwn
52047836SJohn.Forte@Sun.COM  *		port wwn of device node to logout
52057836SJohn.Forte@Sun.COM  *	    cmd
52067836SJohn.Forte@Sun.COM  *		FCIO_DEV_LOGON or FCIO_DEV_LOGOUT
52077836SJohn.Forte@Sun.COM  *
52087836SJohn.Forte@Sun.COM  * Returns: 0 on success
52097836SJohn.Forte@Sun.COM  *	    non-zero on failure
52107836SJohn.Forte@Sun.COM  */
52117836SJohn.Forte@Sun.COM static int
g_dev_log_in_out(char * port_path,la_wwn_t port_wwn,uint16_t cmd)52127836SJohn.Forte@Sun.COM g_dev_log_in_out(char *port_path, la_wwn_t port_wwn, uint16_t cmd)
52137836SJohn.Forte@Sun.COM {
5214*11547SBill.Gumbrell@Sun.COM 	int		fd, err;
5215*11547SBill.Gumbrell@Sun.COM 	uint32_t	hba_port_top;
5216*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
5217*11547SBill.Gumbrell@Sun.COM 	int		verbose = 0;
52187836SJohn.Forte@Sun.COM 
52197836SJohn.Forte@Sun.COM 	if ((err = g_get_fca_port_topology(port_path,
5220*11547SBill.Gumbrell@Sun.COM 	    &hba_port_top, verbose)) != 0) {
52217836SJohn.Forte@Sun.COM 		return (err);
52227836SJohn.Forte@Sun.COM 	}
52237836SJohn.Forte@Sun.COM 
52247836SJohn.Forte@Sun.COM 	if (!((hba_port_top == FC_TOP_PUBLIC_LOOP) ||
5225*11547SBill.Gumbrell@Sun.COM 	    (hba_port_top == FC_TOP_FABRIC))) {
52267836SJohn.Forte@Sun.COM 		return (L_OPNOSUPP_ON_TOPOLOGY);
52277836SJohn.Forte@Sun.COM 	}
52287836SJohn.Forte@Sun.COM 
52297836SJohn.Forte@Sun.COM 	/* open controller */
52307836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(port_path, O_NDELAY | O_RDONLY | O_EXCL)) == -1)
52317836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
52327836SJohn.Forte@Sun.COM 
52337836SJohn.Forte@Sun.COM 	/*
52347836SJohn.Forte@Sun.COM 	 * stores port_wwn to la_wwn_t raw_wwn field
52357836SJohn.Forte@Sun.COM 	 * and construct fcio structures for FCIO_DEV_LOGIN.
52367836SJohn.Forte@Sun.COM 	 */
52377836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = cmd;
52387836SJohn.Forte@Sun.COM 	fcio.fcio_ilen = sizeof (port_wwn);
52397836SJohn.Forte@Sun.COM 	fcio.fcio_ibuf = (caddr_t)&port_wwn;
52407836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_WRITE;
52417836SJohn.Forte@Sun.COM 	fcio.fcio_olen = fcio.fcio_alen = 0;
52427836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = fcio.fcio_abuf = NULL;
52437836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
52447836SJohn.Forte@Sun.COM 		I_DPRINTF((cmd == FCIO_DEV_LOGIN) ?
5245*11547SBill.Gumbrell@Sun.COM 		    " FCIO_DEV_LOGIN ioctl failed.\n"
5246*11547SBill.Gumbrell@Sun.COM 		    : " FCIO_DEV_LOGOUT ioctl failed.\n");
52477836SJohn.Forte@Sun.COM 		(void) close(fd);
52487836SJohn.Forte@Sun.COM 		return ((cmd == FCIO_DEV_LOGIN) ?
5249*11547SBill.Gumbrell@Sun.COM 		    L_FCIO_DEV_LOGIN_FAIL
5250*11547SBill.Gumbrell@Sun.COM 		    : L_FCIO_DEV_LOGOUT_FAIL);
52517836SJohn.Forte@Sun.COM 	} else {
52527836SJohn.Forte@Sun.COM 		(void) close(fd);
52537836SJohn.Forte@Sun.COM 		return (0);
52547836SJohn.Forte@Sun.COM 	}
52557836SJohn.Forte@Sun.COM }
52567836SJohn.Forte@Sun.COM 
52577836SJohn.Forte@Sun.COM /*
52587836SJohn.Forte@Sun.COM  * This function will verify if a FC device (represented by input WWN
52597836SJohn.Forte@Sun.COM  * is connected on a FCA port by searching the device list from
52607836SJohn.Forte@Sun.COM  * g_get_dev_list() for a WWN match.
52617836SJohn.Forte@Sun.COM  *
52627836SJohn.Forte@Sun.COM  * input:
52637836SJohn.Forte@Sun.COM  *   fca_path: pointer to the physical path string, path to a fp node.
52647836SJohn.Forte@Sun.COM  *             possible forms are
52657836SJohn.Forte@Sun.COM  *		/devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl
52667836SJohn.Forte@Sun.COM  *   dev_wwn: WWN string
52677836SJohn.Forte@Sun.COM  *   flag: indicate that the input WWN is node or port
52687836SJohn.Forte@Sun.COM  *
52697836SJohn.Forte@Sun.COM  * returned values
52707836SJohn.Forte@Sun.COM  *   0: if a match is found.
52717836SJohn.Forte@Sun.COM  *   L_WWN_NOT_FOUND_IN_DEV_LIST: if no match found
52727836SJohn.Forte@Sun.COM  *   L_UNEXPECTED_FC_TOPOLOGY: existing error code for an error
52737836SJohn.Forte@Sun.COM  *	from the topology checking of the input fca path.
52747836SJohn.Forte@Sun.COM  *   L_MALLOC_FAILED: existing error code for allocation eror from the
52757836SJohn.Forte@Sun.COM  *	g_get_dev_list().
52767836SJohn.Forte@Sun.COM  *   L_FCIO_GETMAP_IOCTL_FAIL: existing error code for an error from the
52777836SJohn.Forte@Sun.COM  *	FCIO ioctl called by the g_get_dev_list()
52787836SJohn.Forte@Sun.COM  *   -1: other failure
52797836SJohn.Forte@Sun.COM  *
52807836SJohn.Forte@Sun.COM  */
52817836SJohn.Forte@Sun.COM int
g_wwn_in_dev_list(char * fca_path,la_wwn_t dev_wwn,int flag)52827836SJohn.Forte@Sun.COM g_wwn_in_dev_list(char *fca_path, la_wwn_t dev_wwn, int flag)
52837836SJohn.Forte@Sun.COM {
5284*11547SBill.Gumbrell@Sun.COM 	uint_t		dev_type;
5285*11547SBill.Gumbrell@Sun.COM 	int		i, err;
5286*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	*dev_list;
5287*11547SBill.Gumbrell@Sun.COM 	fc_port_dev_t	*dev_list_save;
5288*11547SBill.Gumbrell@Sun.COM 	int		num_devices = 0;
52897836SJohn.Forte@Sun.COM 
52907836SJohn.Forte@Sun.COM 	if ((dev_type = g_get_path_type(fca_path)) == 0) {
52917836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
52927836SJohn.Forte@Sun.COM 	}
52937836SJohn.Forte@Sun.COM 
52947836SJohn.Forte@Sun.COM 	if (!(dev_type & FC_XPORT_MASK)) {
52957836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
52967836SJohn.Forte@Sun.COM 	}
52977836SJohn.Forte@Sun.COM 
52987836SJohn.Forte@Sun.COM 	if (((err = g_get_dev_list(fca_path, &dev_list, &num_devices))
5299*11547SBill.Gumbrell@Sun.COM 	    != 0) && (err != L_GET_DEV_LIST_ULP_FAILURE)) {
53007836SJohn.Forte@Sun.COM 		return (err);
53017836SJohn.Forte@Sun.COM 	}
53027836SJohn.Forte@Sun.COM 
53037836SJohn.Forte@Sun.COM 	dev_list_save = dev_list;
53047836SJohn.Forte@Sun.COM 
53057836SJohn.Forte@Sun.COM 	switch (flag) {
53067836SJohn.Forte@Sun.COM 	case MATCH_NODE_WWN:
53077836SJohn.Forte@Sun.COM 		for (i = 0; i < num_devices; i++, dev_list++) {
53087836SJohn.Forte@Sun.COM 			if (memcmp(dev_list->dev_nwwn.raw_wwn,
5309*11547SBill.Gumbrell@Sun.COM 			    dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
53107836SJohn.Forte@Sun.COM 				(void) free(dev_list_save);
53117836SJohn.Forte@Sun.COM 				return (0);
53127836SJohn.Forte@Sun.COM 			}
53137836SJohn.Forte@Sun.COM 		}
53147836SJohn.Forte@Sun.COM 		(void) free(dev_list_save);
53157836SJohn.Forte@Sun.COM 		/* consider a new error code for not found. */
53167836SJohn.Forte@Sun.COM 		return (L_WWN_NOT_FOUND_IN_DEV_LIST);
53177836SJohn.Forte@Sun.COM 
53187836SJohn.Forte@Sun.COM 	case MATCH_PORT_WWN:
53197836SJohn.Forte@Sun.COM 		for (i = 0; i < num_devices; i++, dev_list++) {
53207836SJohn.Forte@Sun.COM 			if (memcmp(dev_list->dev_pwwn.raw_wwn,
5321*11547SBill.Gumbrell@Sun.COM 			    dev_wwn.raw_wwn, FC_WWN_SIZE) == 0) {
53227836SJohn.Forte@Sun.COM 				(void) free(dev_list_save);
53237836SJohn.Forte@Sun.COM 				return (0);
53247836SJohn.Forte@Sun.COM 			}
53257836SJohn.Forte@Sun.COM 		}
53267836SJohn.Forte@Sun.COM 		(void) free(dev_list_save);
53277836SJohn.Forte@Sun.COM 		/* consider a new error code for not found. */
53287836SJohn.Forte@Sun.COM 		return (L_WWN_NOT_FOUND_IN_DEV_LIST);
53297836SJohn.Forte@Sun.COM 	}
53307836SJohn.Forte@Sun.COM 	(void) free(dev_list_save);
53317836SJohn.Forte@Sun.COM 	return (-1);
53327836SJohn.Forte@Sun.COM }
53337836SJohn.Forte@Sun.COM 
53347836SJohn.Forte@Sun.COM 
53357836SJohn.Forte@Sun.COM /*
53367836SJohn.Forte@Sun.COM  * g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
53377836SJohn.Forte@Sun.COM  * Purpose: get the state of device port login via FCIO_GET_STATE ioctl.
53387836SJohn.Forte@Sun.COM  *
53397836SJohn.Forte@Sun.COM  * Input:   fca_path
53407836SJohn.Forte@Sun.COM  *		fc transport port with fabric/public loop topology
53417836SJohn.Forte@Sun.COM  *	    port_wwn
53427836SJohn.Forte@Sun.COM  *		port wwn of device node to logout
53437836SJohn.Forte@Sun.COM  *	    state
53447836SJohn.Forte@Sun.COM  *		port login or not
53457836SJohn.Forte@Sun.COM  *
53467836SJohn.Forte@Sun.COM  * Returns: 0 on success
53477836SJohn.Forte@Sun.COM  *	    non-zero on failure
53487836SJohn.Forte@Sun.COM  */
53497836SJohn.Forte@Sun.COM static int
g_get_dev_port_state(char * fca_path,la_wwn_t port_wwn,uint32_t * state)53507836SJohn.Forte@Sun.COM g_get_dev_port_state(char *fca_path, la_wwn_t port_wwn, uint32_t *state)
53517836SJohn.Forte@Sun.COM {
5352*11547SBill.Gumbrell@Sun.COM 	int		fd;
5353*11547SBill.Gumbrell@Sun.COM 	int		dev_type;
5354*11547SBill.Gumbrell@Sun.COM 	fcio_t		fcio;
5355*11547SBill.Gumbrell@Sun.COM 	int		verbose = 0;
53567836SJohn.Forte@Sun.COM 
53577836SJohn.Forte@Sun.COM 	if ((dev_type = g_get_path_type(fca_path)) == 0) {
53587836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH);
53597836SJohn.Forte@Sun.COM 	}
53607836SJohn.Forte@Sun.COM 
53617836SJohn.Forte@Sun.COM 	if (!(dev_type & FC_XPORT_MASK)) {
53627836SJohn.Forte@Sun.COM 		return (L_INVALID_PATH_TYPE);
53637836SJohn.Forte@Sun.COM 	}
53647836SJohn.Forte@Sun.COM 
53657836SJohn.Forte@Sun.COM 	/* open controller */
53667836SJohn.Forte@Sun.COM 	if ((fd = g_object_open(fca_path, O_NDELAY | O_RDONLY)) == -1)
53677836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
53687836SJohn.Forte@Sun.COM 
53697836SJohn.Forte@Sun.COM 	/*
53707836SJohn.Forte@Sun.COM 	 * stores port_wwn to la_wwn_t raw_wwn field
53717836SJohn.Forte@Sun.COM 	 * and construct fcio structures for FCIO_DEV_LOGIN.
53727836SJohn.Forte@Sun.COM 	 */
53737836SJohn.Forte@Sun.COM 	fcio.fcio_cmd = FCIO_GET_STATE;
53747836SJohn.Forte@Sun.COM 	fcio.fcio_ilen = sizeof (port_wwn);
53757836SJohn.Forte@Sun.COM 	fcio.fcio_ibuf = (caddr_t)&port_wwn;
53767836SJohn.Forte@Sun.COM 	fcio.fcio_xfer = FCIO_XFER_READ | FCIO_XFER_WRITE;
53777836SJohn.Forte@Sun.COM 	fcio.fcio_olen = sizeof (uint32_t);
53787836SJohn.Forte@Sun.COM 	fcio.fcio_obuf = (caddr_t)state;
53797836SJohn.Forte@Sun.COM 	fcio.fcio_alen = 0;
53807836SJohn.Forte@Sun.COM 	fcio.fcio_abuf = NULL;
53817836SJohn.Forte@Sun.COM 	if (g_issue_fcio_ioctl(fd, &fcio, verbose) != 0) {
53827836SJohn.Forte@Sun.COM 		I_DPRINTF(" FCIO_GET_STATE ioctl failed.\n");
53837836SJohn.Forte@Sun.COM 		(void) close(fd);
53847836SJohn.Forte@Sun.COM 		return (L_FCIO_GET_STATE_FAIL);
53857836SJohn.Forte@Sun.COM 	} else {
53867836SJohn.Forte@Sun.COM 		(void) close(fd);
53877836SJohn.Forte@Sun.COM 		return (0);
53887836SJohn.Forte@Sun.COM 	}
53897836SJohn.Forte@Sun.COM }
53907836SJohn.Forte@Sun.COM 
53917836SJohn.Forte@Sun.COM /*
53927836SJohn.Forte@Sun.COM  * Name: lilp_map_cmp
53937836SJohn.Forte@Sun.COM  *
53947836SJohn.Forte@Sun.COM  * Description: This function is used to compare the physical location
53957836SJohn.Forte@Sun.COM  *              of to fc devices in a gfc_map_t.dev_addr arrary.
53967836SJohn.Forte@Sun.COM  *
53977836SJohn.Forte@Sun.COM  * Params:
53987836SJohn.Forte@Sun.COM  *	First device to compare
53997836SJohn.Forte@Sun.COM  *	Second device to compare
54007836SJohn.Forte@Sun.COM  *
54017836SJohn.Forte@Sun.COM  * Return:
54027836SJohn.Forte@Sun.COM  *   0 = Devices at equal phyiscal location, How did this happen?
54037836SJohn.Forte@Sun.COM  *  >0 = First device have a higher physical location than second
54047836SJohn.Forte@Sun.COM  *  <0 = Second device have a higher physical location than first
54057836SJohn.Forte@Sun.COM  */
lilp_map_cmp(const void * dev1,const void * dev2)54067836SJohn.Forte@Sun.COM static int lilp_map_cmp(const void* dev1, const void* dev2) {
54077836SJohn.Forte@Sun.COM 	int i_dev1 = ((fc_port_dev_t *)dev1)->dev_did.priv_lilp_posit;
54087836SJohn.Forte@Sun.COM 	int i_dev2 = ((fc_port_dev_t *)dev2)->dev_did.priv_lilp_posit;
54097836SJohn.Forte@Sun.COM 
54107836SJohn.Forte@Sun.COM 	if (i_dev1 > i_dev2)
54117836SJohn.Forte@Sun.COM 		return (1);
54127836SJohn.Forte@Sun.COM 	if (i_dev1 < i_dev2)
54137836SJohn.Forte@Sun.COM 		return (-1);
54147836SJohn.Forte@Sun.COM 	return (0);
54157836SJohn.Forte@Sun.COM }
54167836SJohn.Forte@Sun.COM 
54177836SJohn.Forte@Sun.COM /*
54187836SJohn.Forte@Sun.COM  * Description:
54197836SJohn.Forte@Sun.COM  *    Retrieves multiple paths to a device based on devid
54207836SJohn.Forte@Sun.COM  *    Caller must use mplist_free to free mplist structure
54217836SJohn.Forte@Sun.COM  *    This currently only supports ssd devices.
54227836SJohn.Forte@Sun.COM  *    The st driver does not register a device id.
54237836SJohn.Forte@Sun.COM  *
54247836SJohn.Forte@Sun.COM  * Input Values:
54257836SJohn.Forte@Sun.COM  *
54267836SJohn.Forte@Sun.COM  *    devid: ptr to valid ddi_devid_t struct
54277836SJohn.Forte@Sun.COM  *    root: root handle to device tree snapshot
54287836SJohn.Forte@Sun.COM  *    drvr_name: driver name to start the node tree search
54297836SJohn.Forte@Sun.COM  *
54307836SJohn.Forte@Sun.COM  * Return Value:
54317836SJohn.Forte@Sun.COM  *    0 on success
54327836SJohn.Forte@Sun.COM  *    non-zero on failure
54337836SJohn.Forte@Sun.COM  */
54347836SJohn.Forte@Sun.COM 
54357836SJohn.Forte@Sun.COM static int
devid_get_all(ddi_devid_t devid,di_node_t root,char * drvr_name,struct mplist_struct ** mplistp)54367836SJohn.Forte@Sun.COM devid_get_all(ddi_devid_t devid, di_node_t root, char *drvr_name,
5437*11547SBill.Gumbrell@Sun.COM     struct mplist_struct **mplistp)
54387836SJohn.Forte@Sun.COM {
5439*11547SBill.Gumbrell@Sun.COM 	ddi_devid_t mydevid;
5440*11547SBill.Gumbrell@Sun.COM 	di_node_t node;
5441*11547SBill.Gumbrell@Sun.COM 	char *devfs_path = NULL;
5442*11547SBill.Gumbrell@Sun.COM 	struct mplist_struct *mpl, *mpln;
54437836SJohn.Forte@Sun.COM 
54447836SJohn.Forte@Sun.COM 	if (devid == NULL || root == NULL || drvr_name == NULL ||
5445*11547SBill.Gumbrell@Sun.COM 	    mplistp == NULL ||
5446*11547SBill.Gumbrell@Sun.COM 	    (strncmp(drvr_name, SSD_DRVR_NAME, strlen(SSD_DRVR_NAME))
5447*11547SBill.Gumbrell@Sun.COM 	    != 0)) {
54487836SJohn.Forte@Sun.COM 		return (EINVAL);
54497836SJohn.Forte@Sun.COM 	}
54507836SJohn.Forte@Sun.COM 
54517836SJohn.Forte@Sun.COM 	*mplistp = mpl = mpln = (struct mplist_struct *)NULL;
54527836SJohn.Forte@Sun.COM 
54537836SJohn.Forte@Sun.COM 	/* point to first node which matches portdrvr */
54547836SJohn.Forte@Sun.COM 	node = di_drv_first_node(drvr_name, root);
54557836SJohn.Forte@Sun.COM 	if (node == DI_NODE_NIL) {
54567836SJohn.Forte@Sun.COM 		return (L_NO_DRIVER_NODES_FOUND);
54577836SJohn.Forte@Sun.COM 	}
54587836SJohn.Forte@Sun.COM 
54597836SJohn.Forte@Sun.COM 	while (node != DI_NODE_NIL) {
54607836SJohn.Forte@Sun.COM 		if ((mydevid = di_devid(node)) != NULL) {
54617836SJohn.Forte@Sun.COM 			if (((devid_compare(mydevid, devid)) == 0)) {
5462*11547SBill.Gumbrell@Sun.COM 				/* Load multipath list */
5463*11547SBill.Gumbrell@Sun.COM 				if ((mpl = (struct mplist_struct *)
5464*11547SBill.Gumbrell@Sun.COM 				    calloc(1, sizeof (struct mplist_struct)))
5465*11547SBill.Gumbrell@Sun.COM 				    == NULL) {
5466*11547SBill.Gumbrell@Sun.COM 					mplist_free(*mplistp);
5467*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
5468*11547SBill.Gumbrell@Sun.COM 				}
5469*11547SBill.Gumbrell@Sun.COM 				if ((devfs_path = my_devfs_path(node)) ==
5470*11547SBill.Gumbrell@Sun.COM 				    NULL) {
5471*11547SBill.Gumbrell@Sun.COM 					node = di_drv_next_node(node);
5472*11547SBill.Gumbrell@Sun.COM 					S_FREE(mpl);
5473*11547SBill.Gumbrell@Sun.COM 					continue;
5474*11547SBill.Gumbrell@Sun.COM 				}
5475*11547SBill.Gumbrell@Sun.COM 				mpl->devpath = (char *)calloc(1,
5476*11547SBill.Gumbrell@Sun.COM 				    strlen(devfs_path) +
5477*11547SBill.Gumbrell@Sun.COM 				    strlen(SSD_MINOR_NAME) + 1);
5478*11547SBill.Gumbrell@Sun.COM 				if (mpl->devpath == NULL) {
5479*11547SBill.Gumbrell@Sun.COM 					S_FREE(mpl);
5480*11547SBill.Gumbrell@Sun.COM 					mplist_free(*mplistp);
5481*11547SBill.Gumbrell@Sun.COM 					my_devfs_path_free(devfs_path);
5482*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
5483*11547SBill.Gumbrell@Sun.COM 				}
5484*11547SBill.Gumbrell@Sun.COM 				sprintf(mpl->devpath, "%s%s", devfs_path,
5485*11547SBill.Gumbrell@Sun.COM 				    SSD_MINOR_NAME);
5486*11547SBill.Gumbrell@Sun.COM 				if (*mplistp == NULL) {
5487*11547SBill.Gumbrell@Sun.COM 					*mplistp = mpln = mpl;
5488*11547SBill.Gumbrell@Sun.COM 				} else {
5489*11547SBill.Gumbrell@Sun.COM 					mpln->next = mpl;
5490*11547SBill.Gumbrell@Sun.COM 					mpln = mpl;
5491*11547SBill.Gumbrell@Sun.COM 				}
54927836SJohn.Forte@Sun.COM 				my_devfs_path_free(devfs_path);
54937836SJohn.Forte@Sun.COM 			}
54947836SJohn.Forte@Sun.COM 		}
54957836SJohn.Forte@Sun.COM 	node = di_drv_next_node(node);
54967836SJohn.Forte@Sun.COM 	}
54977836SJohn.Forte@Sun.COM 	return (0);
54987836SJohn.Forte@Sun.COM }
54997836SJohn.Forte@Sun.COM 
55007836SJohn.Forte@Sun.COM /*
55017836SJohn.Forte@Sun.COM  * Frees a previously allocated mplist_struct
55027836SJohn.Forte@Sun.COM  */
55037836SJohn.Forte@Sun.COM static void
mplist_free(struct mplist_struct * mplistp)55047836SJohn.Forte@Sun.COM mplist_free(struct mplist_struct *mplistp)
55057836SJohn.Forte@Sun.COM {
5506*11547SBill.Gumbrell@Sun.COM 	struct mplist_struct *mplistn;
55077836SJohn.Forte@Sun.COM 
55087836SJohn.Forte@Sun.COM 	while (mplistp != NULL) {
55097836SJohn.Forte@Sun.COM 		mplistn = mplistp->next;
55107836SJohn.Forte@Sun.COM 		if (mplistp->devpath != NULL) {
55117836SJohn.Forte@Sun.COM 			free(mplistp->devpath);
55127836SJohn.Forte@Sun.COM 			mplistp->devpath = NULL;
55137836SJohn.Forte@Sun.COM 		}
55147836SJohn.Forte@Sun.COM 		free(mplistp);
55157836SJohn.Forte@Sun.COM 		mplistp = mplistn;
55167836SJohn.Forte@Sun.COM 	}
55177836SJohn.Forte@Sun.COM }
55187836SJohn.Forte@Sun.COM 
55197836SJohn.Forte@Sun.COM /*
55207836SJohn.Forte@Sun.COM  * Description
55217836SJohn.Forte@Sun.COM  *	Retrieves all device nodes based on drvr_name
55227836SJohn.Forte@Sun.COM  *	Currently supports SSD_DRVR_NAME, ST_DRVR_NAME
55237836SJohn.Forte@Sun.COM  *	There will be a device node in the libdevinfo
55247836SJohn.Forte@Sun.COM  *	snapshot only if there is at least one node bound.
55257836SJohn.Forte@Sun.COM  *
55267836SJohn.Forte@Sun.COM  * Input values:
55277836SJohn.Forte@Sun.COM  *	root		valid snapshot handle from di_init(3DEVINFO)
55287836SJohn.Forte@Sun.COM  *	drvr_name	name of driver to start node search
55297836SJohn.Forte@Sun.COM  *	wwn_list_ptr	ptr to ptr to WWN_list struct
55307836SJohn.Forte@Sun.COM  *
55317836SJohn.Forte@Sun.COM  *
55327836SJohn.Forte@Sun.COM  */
55337836SJohn.Forte@Sun.COM static int
devices_get_all(di_node_t root,char * drvr_name,char * minor_name,struct wwn_list_struct ** wwn_list_ptr)55347836SJohn.Forte@Sun.COM devices_get_all(di_node_t root, char *drvr_name, char *minor_name,
5535*11547SBill.Gumbrell@Sun.COM     struct wwn_list_struct **wwn_list_ptr)
55367836SJohn.Forte@Sun.COM {
5537*11547SBill.Gumbrell@Sun.COM 	di_node_t node;
5538*11547SBill.Gumbrell@Sun.COM 	char *devfs_path;
5539*11547SBill.Gumbrell@Sun.COM 	char devicepath[MAXPATHLEN];
5540*11547SBill.Gumbrell@Sun.COM 	uchar_t *nwwn = NULL, *pwwn = NULL;
5541*11547SBill.Gumbrell@Sun.COM 	uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
5542*11547SBill.Gumbrell@Sun.COM 	WWN_list *wwn_list, *l1, *l2;
5543*11547SBill.Gumbrell@Sun.COM 	int scsi_vhci = 0;
5544*11547SBill.Gumbrell@Sun.COM 	int err, devtype;
55457836SJohn.Forte@Sun.COM 
55467836SJohn.Forte@Sun.COM 	if (root == DI_NODE_NIL || drvr_name == NULL ||
5547*11547SBill.Gumbrell@Sun.COM 	    wwn_list_ptr == NULL) {
55487836SJohn.Forte@Sun.COM 		return (EINVAL);
55497836SJohn.Forte@Sun.COM 	}
55507836SJohn.Forte@Sun.COM 
55517836SJohn.Forte@Sun.COM 	wwn_list = *wwn_list_ptr = NULL;
55527836SJohn.Forte@Sun.COM 
55537836SJohn.Forte@Sun.COM 	memset(port_wwn, 0, sizeof (port_wwn));
55547836SJohn.Forte@Sun.COM 	memset(node_wwn, 0, sizeof (node_wwn));
55557836SJohn.Forte@Sun.COM 
55567836SJohn.Forte@Sun.COM 	if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
55577836SJohn.Forte@Sun.COM 		devtype = DTYPE_DIRECT;
55587836SJohn.Forte@Sun.COM 	} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
55597836SJohn.Forte@Sun.COM 		devtype = DTYPE_SEQUENTIAL;
55607836SJohn.Forte@Sun.COM 	} else {
55617836SJohn.Forte@Sun.COM 		/*
55627836SJohn.Forte@Sun.COM 		 * An unsupported driver name was passed in
55637836SJohn.Forte@Sun.COM 		 */
55647836SJohn.Forte@Sun.COM 		return (L_DRIVER_NOTSUPP);
55657836SJohn.Forte@Sun.COM 	}
55667836SJohn.Forte@Sun.COM 
55677836SJohn.Forte@Sun.COM 	/* point to first node which matches portdrvr */
55687836SJohn.Forte@Sun.COM 	node = di_drv_first_node(drvr_name, root);
55697836SJohn.Forte@Sun.COM 	if (node == DI_NODE_NIL) {
55707836SJohn.Forte@Sun.COM 		return (L_NO_DEVICES_FOUND);
55717836SJohn.Forte@Sun.COM 	}
55727836SJohn.Forte@Sun.COM 
55737836SJohn.Forte@Sun.COM 	while (node != DI_NODE_NIL) {
55747836SJohn.Forte@Sun.COM 
5575*11547SBill.Gumbrell@Sun.COM 		if ((devfs_path = my_devfs_path(node)) != NULL) {
5576*11547SBill.Gumbrell@Sun.COM 
5577*11547SBill.Gumbrell@Sun.COM 			/*
5578*11547SBill.Gumbrell@Sun.COM 			 * Check for offline state
5579*11547SBill.Gumbrell@Sun.COM 			 */
5580*11547SBill.Gumbrell@Sun.COM 			if ((di_state(node) &
5581*11547SBill.Gumbrell@Sun.COM 			    DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE) {
55827836SJohn.Forte@Sun.COM 				my_devfs_path_free(devfs_path);
5583*11547SBill.Gumbrell@Sun.COM 				node = di_drv_next_node(node);
5584*11547SBill.Gumbrell@Sun.COM 				continue;
55857836SJohn.Forte@Sun.COM 			}
5586*11547SBill.Gumbrell@Sun.COM 
5587*11547SBill.Gumbrell@Sun.COM 			/*
5588*11547SBill.Gumbrell@Sun.COM 			 * Only support st, ssd nodes
5589*11547SBill.Gumbrell@Sun.COM 			 */
5590*11547SBill.Gumbrell@Sun.COM 			if (!strstr(devfs_path, SLSH_DRV_NAME_SSD) &&
5591*11547SBill.Gumbrell@Sun.COM 			    !strstr(devfs_path, SLSH_DRV_NAME_ST)) {
5592*11547SBill.Gumbrell@Sun.COM 				my_devfs_path_free(devfs_path);
5593*11547SBill.Gumbrell@Sun.COM 				node = di_drv_next_node(node);
5594*11547SBill.Gumbrell@Sun.COM 				continue;
5595*11547SBill.Gumbrell@Sun.COM 			}
5596*11547SBill.Gumbrell@Sun.COM 
5597*11547SBill.Gumbrell@Sun.COM 			devicepath[0] = '\0';
5598*11547SBill.Gumbrell@Sun.COM 
55997836SJohn.Forte@Sun.COM 			/*
5600*11547SBill.Gumbrell@Sun.COM 			 * form device path
56017836SJohn.Forte@Sun.COM 			 */
5602*11547SBill.Gumbrell@Sun.COM 			sprintf(devicepath, "%s%s", devfs_path, minor_name);
5603*11547SBill.Gumbrell@Sun.COM 
5604*11547SBill.Gumbrell@Sun.COM 			if ((strstr(devicepath, SCSI_VHCI) == NULL)) {
5605*11547SBill.Gumbrell@Sun.COM 				if ((err = get_wwn_data(node, &nwwn, &pwwn)) !=
5606*11547SBill.Gumbrell@Sun.COM 				    0) {
5607*11547SBill.Gumbrell@Sun.COM 					my_devfs_path_free(devfs_path);
5608*11547SBill.Gumbrell@Sun.COM 					return (err);
5609*11547SBill.Gumbrell@Sun.COM 				} else {
5610*11547SBill.Gumbrell@Sun.COM 					memcpy(node_wwn, nwwn,
5611*11547SBill.Gumbrell@Sun.COM 					    sizeof (node_wwn));
5612*11547SBill.Gumbrell@Sun.COM 					memcpy(port_wwn, pwwn,
5613*11547SBill.Gumbrell@Sun.COM 					    sizeof (port_wwn));
5614*11547SBill.Gumbrell@Sun.COM 				}
5615*11547SBill.Gumbrell@Sun.COM 			} else {
5616*11547SBill.Gumbrell@Sun.COM 				/*
5617*11547SBill.Gumbrell@Sun.COM 				 * Clear values for SCSI VHCI devices.
5618*11547SBill.Gumbrell@Sun.COM 				 * node wwn, port wwn are irrevelant at
5619*11547SBill.Gumbrell@Sun.COM 				 * the SCSI VHCI level
5620*11547SBill.Gumbrell@Sun.COM 				 */
5621*11547SBill.Gumbrell@Sun.COM 				scsi_vhci++;
5622*11547SBill.Gumbrell@Sun.COM 				memset(port_wwn, 0, sizeof (port_wwn));
5623*11547SBill.Gumbrell@Sun.COM 				memset(node_wwn, 0, sizeof (node_wwn));
5624*11547SBill.Gumbrell@Sun.COM 			}
5625*11547SBill.Gumbrell@Sun.COM 
5626*11547SBill.Gumbrell@Sun.COM 			/* Got wwns, load data in list */
5627*11547SBill.Gumbrell@Sun.COM 			if ((l2 = (struct  wwn_list_struct *)
5628*11547SBill.Gumbrell@Sun.COM 			    calloc(1, sizeof (struct  wwn_list_struct))) ==
5629*11547SBill.Gumbrell@Sun.COM 			    NULL) {
5630*11547SBill.Gumbrell@Sun.COM 				my_devfs_path_free(devfs_path);
5631*11547SBill.Gumbrell@Sun.COM 				return (L_MALLOC_FAILED);
5632*11547SBill.Gumbrell@Sun.COM 			}
5633*11547SBill.Gumbrell@Sun.COM 			if ((l2->physical_path = (char *)
5634*11547SBill.Gumbrell@Sun.COM 			    calloc(1, strlen(devicepath) +1)) == NULL) {
5635*11547SBill.Gumbrell@Sun.COM 				my_devfs_path_free(devfs_path);
5636*11547SBill.Gumbrell@Sun.COM 				return (L_MALLOC_FAILED);
5637*11547SBill.Gumbrell@Sun.COM 			}
5638*11547SBill.Gumbrell@Sun.COM 
5639*11547SBill.Gumbrell@Sun.COM 			memcpy(l2->w_node_wwn, node_wwn, WWN_SIZE);
5640*11547SBill.Gumbrell@Sun.COM 
5641*11547SBill.Gumbrell@Sun.COM 			if (scsi_vhci) {
5642*11547SBill.Gumbrell@Sun.COM 				strcpy(l2->node_wwn_s, MSGSTR(12000, "N/A"));
5643*11547SBill.Gumbrell@Sun.COM 			} else {
5644*11547SBill.Gumbrell@Sun.COM 				copy_wwn_data_to_str(l2->node_wwn_s, node_wwn);
5645*11547SBill.Gumbrell@Sun.COM 				copy_wwn_data_to_str(l2->port_wwn_s, port_wwn);
5646*11547SBill.Gumbrell@Sun.COM 			}
5647*11547SBill.Gumbrell@Sun.COM 
5648*11547SBill.Gumbrell@Sun.COM 			strcpy(l2->physical_path, devicepath);
5649*11547SBill.Gumbrell@Sun.COM 
5650*11547SBill.Gumbrell@Sun.COM 			l2->device_type = devtype;
5651*11547SBill.Gumbrell@Sun.COM 			if (wwn_list == NULL) {
5652*11547SBill.Gumbrell@Sun.COM 				l1 = wwn_list = l2;
5653*11547SBill.Gumbrell@Sun.COM 			} else {
5654*11547SBill.Gumbrell@Sun.COM 				l2->wwn_prev = l1;
5655*11547SBill.Gumbrell@Sun.COM 				l1 = l1->wwn_next = l2;
5656*11547SBill.Gumbrell@Sun.COM 			}
56577836SJohn.Forte@Sun.COM 			my_devfs_path_free(devfs_path);
5658*11547SBill.Gumbrell@Sun.COM 			scsi_vhci = 0;
56597836SJohn.Forte@Sun.COM 		}
5660*11547SBill.Gumbrell@Sun.COM 		node = di_drv_next_node(node);
56617836SJohn.Forte@Sun.COM 	}
56627836SJohn.Forte@Sun.COM 
56637836SJohn.Forte@Sun.COM 	*wwn_list_ptr = wwn_list; /* pass back ptr to list */
56647836SJohn.Forte@Sun.COM 
56657836SJohn.Forte@Sun.COM 	if (*wwn_list_ptr == NULL) {
56667836SJohn.Forte@Sun.COM 		return (L_NO_DEVICES_FOUND);
56677836SJohn.Forte@Sun.COM 	} else {
56687836SJohn.Forte@Sun.COM 		/*
56697836SJohn.Forte@Sun.COM 		 * Now load the /dev/ paths
56707836SJohn.Forte@Sun.COM 		 */
56717836SJohn.Forte@Sun.COM 		if (strcmp(drvr_name, SSD_DRVR_NAME) == 0) {
56727836SJohn.Forte@Sun.COM 			if ((err = get_dev_path(wwn_list_ptr, DEV_RDIR,
5673*11547SBill.Gumbrell@Sun.COM 			    DIR_MATCH_SSD)) != 0) {
56747836SJohn.Forte@Sun.COM 				g_free_wwn_list(wwn_list_ptr);
56757836SJohn.Forte@Sun.COM 				return (err);
56767836SJohn.Forte@Sun.COM 			}
56777836SJohn.Forte@Sun.COM 		} else if (strcmp(drvr_name, ST_DRVR_NAME) == 0) {
56787836SJohn.Forte@Sun.COM 			if ((err = get_dev_path(wwn_list_ptr, DEV_TAPE_DIR,
5679*11547SBill.Gumbrell@Sun.COM 			    DIR_MATCH_ST)) != 0) {
56807836SJohn.Forte@Sun.COM 				g_free_wwn_list(wwn_list_ptr);
56817836SJohn.Forte@Sun.COM 				return (err);
56827836SJohn.Forte@Sun.COM 			}
56837836SJohn.Forte@Sun.COM 		}
56847836SJohn.Forte@Sun.COM 		return (0);
56857836SJohn.Forte@Sun.COM 	}
56867836SJohn.Forte@Sun.COM }
56877836SJohn.Forte@Sun.COM 
56887836SJohn.Forte@Sun.COM 
56897836SJohn.Forte@Sun.COM /*
56907836SJohn.Forte@Sun.COM  * Access the properties for the node to get the node-wwn, port-wwn property
56917836SJohn.Forte@Sun.COM  * On error, contents of nwwn, pwwn are unspecified.
56927836SJohn.Forte@Sun.COM  * On successful return nwwn and pwwn are WWN_SIZE bytes.
56937836SJohn.Forte@Sun.COM  */
56947836SJohn.Forte@Sun.COM static int
get_wwn_data(di_node_t node,uchar_t ** nwwn,uchar_t ** pwwn)56957836SJohn.Forte@Sun.COM get_wwn_data(di_node_t node, uchar_t **nwwn, uchar_t **pwwn)
56967836SJohn.Forte@Sun.COM {
56977836SJohn.Forte@Sun.COM 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, NODE_WWN_PROP,
5698*11547SBill.Gumbrell@Sun.COM 	    nwwn) != WWN_SIZE) {
5699*11547SBill.Gumbrell@Sun.COM 		/* If we didn't get back the right count, return error */
57007836SJohn.Forte@Sun.COM 		return (L_NO_WWN_PROP_FOUND);
57017836SJohn.Forte@Sun.COM 	}
57027836SJohn.Forte@Sun.COM 	if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, PORT_WWN_PROP,
5703*11547SBill.Gumbrell@Sun.COM 	    pwwn) != WWN_SIZE) {
5704*11547SBill.Gumbrell@Sun.COM 		/* If we didn't get back the right count, return error */
57057836SJohn.Forte@Sun.COM 		return (L_NO_WWN_PROP_FOUND);
57067836SJohn.Forte@Sun.COM 	}
57077836SJohn.Forte@Sun.COM 	return (0);
57087836SJohn.Forte@Sun.COM }
57097836SJohn.Forte@Sun.COM 
57107836SJohn.Forte@Sun.COM /*
57117836SJohn.Forte@Sun.COM  * Description
57127836SJohn.Forte@Sun.COM  *	retrieves the /dev logical path for a WWN_list of devices.
57137836SJohn.Forte@Sun.COM  * Input values
57147836SJohn.Forte@Sun.COM  *	wwn_list_ptr	ptr to list returned by devices_get_all
57157836SJohn.Forte@Sun.COM  *	dir_name	/dev/ directory to search
57167836SJohn.Forte@Sun.COM  *
57177836SJohn.Forte@Sun.COM  */
57187836SJohn.Forte@Sun.COM static int
get_dev_path(struct wwn_list_struct ** wwn_list_ptr,char * dir_name,char * pattern_match)57197836SJohn.Forte@Sun.COM get_dev_path(struct wwn_list_struct **wwn_list_ptr, char *dir_name,
5720*11547SBill.Gumbrell@Sun.COM     char *pattern_match)
57217836SJohn.Forte@Sun.COM {
5722*11547SBill.Gumbrell@Sun.COM 	DIR		*dirp;
5723*11547SBill.Gumbrell@Sun.COM 	struct dirent	*entp;
5724*11547SBill.Gumbrell@Sun.COM 	char		namebuf[MAXPATHLEN];
5725*11547SBill.Gumbrell@Sun.COM 	char		*result = NULL;
5726*11547SBill.Gumbrell@Sun.COM 	WWN_list	*wwn_list, *wwn_list_save;
5727*11547SBill.Gumbrell@Sun.COM 	char		*env;
5728*11547SBill.Gumbrell@Sun.COM 	hrtime_t	start_time, end_time;
57297836SJohn.Forte@Sun.COM 
57307836SJohn.Forte@Sun.COM 	if (wwn_list_ptr == NULL || *wwn_list_ptr == NULL ||
5731*11547SBill.Gumbrell@Sun.COM 	    dir_name == NULL || pattern_match == NULL) {
57327836SJohn.Forte@Sun.COM 		return (EINVAL);
57337836SJohn.Forte@Sun.COM 	}
57347836SJohn.Forte@Sun.COM 
57357836SJohn.Forte@Sun.COM 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
57367836SJohn.Forte@Sun.COM 		start_time = gethrtime();
57377836SJohn.Forte@Sun.COM 	}
57387836SJohn.Forte@Sun.COM 
57397836SJohn.Forte@Sun.COM 	wwn_list = *wwn_list_ptr;
57407836SJohn.Forte@Sun.COM 
57417836SJohn.Forte@Sun.COM 	if ((dirp = opendir(dir_name)) == NULL) {
57427836SJohn.Forte@Sun.COM 		P_DPRINTF("  get_dev_path: No devices found\n");
57437836SJohn.Forte@Sun.COM 		return (L_NO_DEVICES_FOUND);
57447836SJohn.Forte@Sun.COM 	}
57457836SJohn.Forte@Sun.COM 
57467836SJohn.Forte@Sun.COM 	while ((entp = readdir(dirp)) != NULL) {
57477836SJohn.Forte@Sun.COM 		/*
57487836SJohn.Forte@Sun.COM 		 * Ignore current directory and parent directory
57497836SJohn.Forte@Sun.COM 		 * entries.
57507836SJohn.Forte@Sun.COM 		 */
57517836SJohn.Forte@Sun.COM 		if ((strcmp(entp->d_name, ".") == 0) ||
57527836SJohn.Forte@Sun.COM 		    (strcmp(entp->d_name, "..") == 0) ||
57537836SJohn.Forte@Sun.COM 		    (fnmatch(pattern_match, entp->d_name, 0) != 0))
57547836SJohn.Forte@Sun.COM 			continue;
57557836SJohn.Forte@Sun.COM 
57567836SJohn.Forte@Sun.COM 		memset(namebuf, 0, sizeof (namebuf));
57577836SJohn.Forte@Sun.COM 		sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
57587836SJohn.Forte@Sun.COM 
57597836SJohn.Forte@Sun.COM 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
57607836SJohn.Forte@Sun.COM 			ER_DPRINTF("  Warning: Get physical name from"
5761*11547SBill.Gumbrell@Sun.COM 			    " link failed. Link=%s\n", namebuf);
57627836SJohn.Forte@Sun.COM 			continue;
57637836SJohn.Forte@Sun.COM 		}
57647836SJohn.Forte@Sun.COM 		for (wwn_list = *wwn_list_ptr; wwn_list != NULL;
57657836SJohn.Forte@Sun.COM 		    wwn_list = wwn_list->wwn_next) {
5766*11547SBill.Gumbrell@Sun.COM 			if (strcmp(wwn_list->physical_path, result) == 0) {
5767*11547SBill.Gumbrell@Sun.COM 				/*
5768*11547SBill.Gumbrell@Sun.COM 				 * Add information to the list.
5769*11547SBill.Gumbrell@Sun.COM 				 */
5770*11547SBill.Gumbrell@Sun.COM 				if ((wwn_list->logical_path = (char *)
5771*11547SBill.Gumbrell@Sun.COM 				    calloc(1, strlen(namebuf) + 1)) == NULL) {
5772*11547SBill.Gumbrell@Sun.COM 					free(result);
5773*11547SBill.Gumbrell@Sun.COM 					return (L_MALLOC_FAILED);
5774*11547SBill.Gumbrell@Sun.COM 				}
5775*11547SBill.Gumbrell@Sun.COM 				strcpy(wwn_list->logical_path, namebuf);
5776*11547SBill.Gumbrell@Sun.COM 				break;
57777836SJohn.Forte@Sun.COM 			}
57787836SJohn.Forte@Sun.COM 		}
57797836SJohn.Forte@Sun.COM 		free(result);
57807836SJohn.Forte@Sun.COM 	}
57817836SJohn.Forte@Sun.COM 	closedir(dirp);
57827836SJohn.Forte@Sun.COM 
57837836SJohn.Forte@Sun.COM 	/*
57847836SJohn.Forte@Sun.COM 	 * Did we load all of the paths?
57857836SJohn.Forte@Sun.COM 	 * Note: if there is a missing entry in /dev then
57867836SJohn.Forte@Sun.COM 	 * the user probably did a cleanup of /dev.
57877836SJohn.Forte@Sun.COM 	 * Whatever the case, remove the entry as it
57887836SJohn.Forte@Sun.COM 	 * is invalid.
57897836SJohn.Forte@Sun.COM 	 */
57907836SJohn.Forte@Sun.COM 	wwn_list = *wwn_list_ptr;
57917836SJohn.Forte@Sun.COM 	while (wwn_list != NULL) {
57927836SJohn.Forte@Sun.COM 		if (wwn_list->logical_path == NULL) {
57937836SJohn.Forte@Sun.COM 			free(wwn_list->physical_path);
57947836SJohn.Forte@Sun.COM 			wwn_list_save = wwn_list;
57957836SJohn.Forte@Sun.COM 			if (wwn_list->wwn_prev != NULL) {
57967836SJohn.Forte@Sun.COM 				wwn_list->wwn_prev->wwn_next =
5797*11547SBill.Gumbrell@Sun.COM 				    wwn_list->wwn_next;
57987836SJohn.Forte@Sun.COM 			} else {
57997836SJohn.Forte@Sun.COM 				/*
58007836SJohn.Forte@Sun.COM 				 * No previous entries
58017836SJohn.Forte@Sun.COM 				 */
58027836SJohn.Forte@Sun.COM 				*wwn_list_ptr = wwn_list->wwn_next;
58037836SJohn.Forte@Sun.COM 			}
58047836SJohn.Forte@Sun.COM 			if (wwn_list->wwn_next != NULL) {
58057836SJohn.Forte@Sun.COM 				wwn_list->wwn_next->wwn_prev =
5806*11547SBill.Gumbrell@Sun.COM 				    wwn_list->wwn_prev;
58077836SJohn.Forte@Sun.COM 			}
58087836SJohn.Forte@Sun.COM 			wwn_list = wwn_list->wwn_next;
58097836SJohn.Forte@Sun.COM 			free(wwn_list_save);
58107836SJohn.Forte@Sun.COM 		} else {
58117836SJohn.Forte@Sun.COM 			wwn_list = wwn_list->wwn_next;
58127836SJohn.Forte@Sun.COM 		}
58137836SJohn.Forte@Sun.COM 	}
58147836SJohn.Forte@Sun.COM 
58157836SJohn.Forte@Sun.COM 	if (env != NULL) {
58167836SJohn.Forte@Sun.COM 		end_time = gethrtime();
58177836SJohn.Forte@Sun.COM 		fprintf(stdout,
5818*11547SBill.Gumbrell@Sun.COM 		    "      get_dev_path %s:  "
5819*11547SBill.Gumbrell@Sun.COM 		    "\t\tTime = %lld millisec\n",
5820*11547SBill.Gumbrell@Sun.COM 		    dir_name, (end_time - start_time)/1000000);
58217836SJohn.Forte@Sun.COM 	}
58227836SJohn.Forte@Sun.COM 
58237836SJohn.Forte@Sun.COM 	if (*wwn_list_ptr == NULL) {
58247836SJohn.Forte@Sun.COM 		return (L_NO_DEVICES_FOUND);
58257836SJohn.Forte@Sun.COM 	} else {
58267836SJohn.Forte@Sun.COM 		return (0);
58277836SJohn.Forte@Sun.COM 	}
58287836SJohn.Forte@Sun.COM }
58297836SJohn.Forte@Sun.COM 
58307836SJohn.Forte@Sun.COM /*
58317836SJohn.Forte@Sun.COM  * This functions calls di_devfs_path and gets the path associated with a
58327836SJohn.Forte@Sun.COM  * given devinfo node. If the path returned does not have a '@' in it, it
58337836SJohn.Forte@Sun.COM  * checks if the driver is detached and creates a path after looking at the
58347836SJohn.Forte@Sun.COM  * driver properties.
58357836SJohn.Forte@Sun.COM  *
58367836SJohn.Forte@Sun.COM  * di_devfs_path_free is called internally.
58377836SJohn.Forte@Sun.COM  *
58387836SJohn.Forte@Sun.COM  * The argument 'path' points to the final value upon return.
58397836SJohn.Forte@Sun.COM  * Caller must use my_devfs_path_free on returned char *
58407836SJohn.Forte@Sun.COM  * Note: Only support FC/SCSI_VHCI devices,
5841*11547SBill.Gumbrell@Sun.COM  *       for FC check for initiator-interconnect-type prop
58427836SJohn.Forte@Sun.COM  *
58437836SJohn.Forte@Sun.COM  */
58447836SJohn.Forte@Sun.COM static char *
my_devfs_path(di_node_t node)58457836SJohn.Forte@Sun.COM my_devfs_path(di_node_t node)
58467836SJohn.Forte@Sun.COM {
58477836SJohn.Forte@Sun.COM 	uchar_t	*pwwn = NULL;
5848*11547SBill.Gumbrell@Sun.COM 	char	*interconnect = NULL;
58497836SJohn.Forte@Sun.COM 	char	pwwns[WWN_SIZE*2+1];
58507836SJohn.Forte@Sun.COM 	char	*mypath;
58517836SJohn.Forte@Sun.COM 	int	scsi_vhci = 0;
5852*11547SBill.Gumbrell@Sun.COM 	int	rval;
58537836SJohn.Forte@Sun.COM 	char	*tptr = NULL, *lun_guid = NULL;
58547836SJohn.Forte@Sun.COM 	int	*lunnump = NULL;
5855*11547SBill.Gumbrell@Sun.COM 	di_node_t	parentnode;
58567836SJohn.Forte@Sun.COM 
58577836SJohn.Forte@Sun.COM 	/* sanity check */
58587836SJohn.Forte@Sun.COM 	if (node == DI_NODE_NIL) {
58597836SJohn.Forte@Sun.COM 		return (NULL);
58607836SJohn.Forte@Sun.COM 	}
58617836SJohn.Forte@Sun.COM 
58627836SJohn.Forte@Sun.COM 	/* Now go get the path for this node */
58637836SJohn.Forte@Sun.COM 	if ((tptr = di_devfs_path(node)) == NULL) {
58647836SJohn.Forte@Sun.COM 		return (NULL);
58657836SJohn.Forte@Sun.COM 	}
58667836SJohn.Forte@Sun.COM 
5867*11547SBill.Gumbrell@Sun.COM 	parentnode = di_parent_node(node);
5868*11547SBill.Gumbrell@Sun.COM 
58697836SJohn.Forte@Sun.COM 	if ((mypath = (char *)calloc(1, MAXPATHLEN + 1)) == NULL) {
58707836SJohn.Forte@Sun.COM 		di_devfs_path_free(tptr);
58717836SJohn.Forte@Sun.COM 		return (NULL);
58727836SJohn.Forte@Sun.COM 	}
58737836SJohn.Forte@Sun.COM 
58747836SJohn.Forte@Sun.COM 	/* Prepend "/devices" to libdevinfo-returned paths */
58757836SJohn.Forte@Sun.COM 	sprintf(mypath, "%s%s", DEVICES_DIR, tptr);
58767836SJohn.Forte@Sun.COM 
58777836SJohn.Forte@Sun.COM 	di_devfs_path_free(tptr);
58787836SJohn.Forte@Sun.COM 
58797836SJohn.Forte@Sun.COM 	/*
58807836SJohn.Forte@Sun.COM 	 * Is this a FC device?
5881*11547SBill.Gumbrell@Sun.COM 	 * Check initiator-interconnect-type property
58827836SJohn.Forte@Sun.COM 	 */
58837836SJohn.Forte@Sun.COM 	if (strstr(mypath, SCSI_VHCI) == NULL) {
5884*11547SBill.Gumbrell@Sun.COM 		rval = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode,
5885*11547SBill.Gumbrell@Sun.COM 		    "initiator-interconnect-type", &interconnect);
5886*11547SBill.Gumbrell@Sun.COM 		/* Check for INTERCONNECT_FABRIC_STR & INTERCONNECT_FIBRE_STR */
5887*11547SBill.Gumbrell@Sun.COM 		if ((rval <= 0) ||
5888*11547SBill.Gumbrell@Sun.COM 		    ((strcmp(interconnect, "FABRIC") != 0) &&
5889*11547SBill.Gumbrell@Sun.COM 		    (strcmp(interconnect, "FIBRE") != 0))) {
58907836SJohn.Forte@Sun.COM 			/* Not a FC device. Free path and return */
58917836SJohn.Forte@Sun.COM 			free(mypath);
58927836SJohn.Forte@Sun.COM 			return (NULL);
58937836SJohn.Forte@Sun.COM 		}
58947836SJohn.Forte@Sun.COM 	} else {
58957836SJohn.Forte@Sun.COM 		scsi_vhci++;
58967836SJohn.Forte@Sun.COM 	}
58977836SJohn.Forte@Sun.COM 
58987836SJohn.Forte@Sun.COM 	if ((tptr = strrchr(mypath, '/')) == NULL) {
58997836SJohn.Forte@Sun.COM 		free(mypath);
59007836SJohn.Forte@Sun.COM 		return (NULL);
59017836SJohn.Forte@Sun.COM 	}
59027836SJohn.Forte@Sun.COM 
59037836SJohn.Forte@Sun.COM 	if (strchr(tptr, '@') != NULL) {
59047836SJohn.Forte@Sun.COM 		return (mypath);
59057836SJohn.Forte@Sun.COM 	}
59067836SJohn.Forte@Sun.COM 
59077836SJohn.Forte@Sun.COM 	/*
59087836SJohn.Forte@Sun.COM 	 * No '@' in path. This can happen when driver is detached.
59097836SJohn.Forte@Sun.COM 	 * We'll check if the state is detached and if it is, we'll construct
59107836SJohn.Forte@Sun.COM 	 * the path by looking at the properties.
59117836SJohn.Forte@Sun.COM 	 */
59127836SJohn.Forte@Sun.COM 
59137836SJohn.Forte@Sun.COM 	if ((di_state(node) & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
59147836SJohn.Forte@Sun.COM 		/*
59157836SJohn.Forte@Sun.COM 		 * Driver is not detached and no '@' in path.
59167836SJohn.Forte@Sun.COM 		 * Can't handle it.
59177836SJohn.Forte@Sun.COM 		 */
59187836SJohn.Forte@Sun.COM 		free(mypath);
59197836SJohn.Forte@Sun.COM 		return (NULL);
59207836SJohn.Forte@Sun.COM 	}
59217836SJohn.Forte@Sun.COM 
59227836SJohn.Forte@Sun.COM 	if (!scsi_vhci) {
59237836SJohn.Forte@Sun.COM 		copy_wwn_data_to_str(pwwns, pwwn);
59247836SJohn.Forte@Sun.COM 		di_prop_lookup_ints(DDI_DEV_T_ANY, node, LUN_PROP, &lunnump);
59257836SJohn.Forte@Sun.COM 		sprintf(&mypath[strlen(mypath)], "@w%s,%x", pwwn, *lunnump);
59267836SJohn.Forte@Sun.COM 	} else {
59277836SJohn.Forte@Sun.COM 		di_prop_lookup_strings(DDI_DEV_T_ANY, node,
5928*11547SBill.Gumbrell@Sun.COM 		    LUN_GUID_PROP, &lun_guid);
59297836SJohn.Forte@Sun.COM 		sprintf(&mypath[strlen(mypath)], "@g%s", lun_guid);
59307836SJohn.Forte@Sun.COM 	}
59317836SJohn.Forte@Sun.COM 	return (mypath);
59327836SJohn.Forte@Sun.COM }
59337836SJohn.Forte@Sun.COM 
59347836SJohn.Forte@Sun.COM static void
my_devfs_path_free(char * path)59357836SJohn.Forte@Sun.COM my_devfs_path_free(char *path)
59367836SJohn.Forte@Sun.COM {
59377836SJohn.Forte@Sun.COM 	if (path != NULL) {
59387836SJohn.Forte@Sun.COM 		free(path);
59397836SJohn.Forte@Sun.COM 	}
59407836SJohn.Forte@Sun.COM }
59417836SJohn.Forte@Sun.COM 
59427836SJohn.Forte@Sun.COM /*
59437836SJohn.Forte@Sun.COM  * from_ptr: ptr to uchar_t array of size WWN_SIZE
59447836SJohn.Forte@Sun.COM  * to_ptr: char ptr to string of size WWN_SIZE*2+1
59457836SJohn.Forte@Sun.COM  */
59467836SJohn.Forte@Sun.COM static void
copy_wwn_data_to_str(char * to_ptr,const uchar_t * from_ptr)59477836SJohn.Forte@Sun.COM copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
59487836SJohn.Forte@Sun.COM {
59497836SJohn.Forte@Sun.COM 	if ((to_ptr == NULL) || (from_ptr == NULL))
59507836SJohn.Forte@Sun.COM 		return;
59517836SJohn.Forte@Sun.COM 
59527836SJohn.Forte@Sun.COM 	sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
5953*11547SBill.Gumbrell@Sun.COM 	    from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
5954*11547SBill.Gumbrell@Sun.COM 	    from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
59557836SJohn.Forte@Sun.COM }
59567836SJohn.Forte@Sun.COM 
59577836SJohn.Forte@Sun.COM /*
59587836SJohn.Forte@Sun.COM  * Open the requested directory and get one valid open.
59597836SJohn.Forte@Sun.COM  * If a device is busy, return.
59607836SJohn.Forte@Sun.COM  * Only need to open one device since
59617836SJohn.Forte@Sun.COM  * that implies there will be a node returned from
59627836SJohn.Forte@Sun.COM  * di_drv_first_node()
59637836SJohn.Forte@Sun.COM  * dir_name: logical device name directory
59647836SJohn.Forte@Sun.COM  *	(DEV_TAPE_DIR, DEV_RDIR)
59657836SJohn.Forte@Sun.COM  * pattern_match: used by fnmatch on directory entry
59667836SJohn.Forte@Sun.COM  *	(DIR_MATCH_SSD, DIR_MATCH_ST)
59677836SJohn.Forte@Sun.COM  * drvr_path: path type to verify ("/ssd@", "/st@")
59687836SJohn.Forte@Sun.COM  *	(SLSH_DRV_NAME_ST, SLSH_DRV_NAME_SSD)
59697836SJohn.Forte@Sun.COM  *
59707836SJohn.Forte@Sun.COM  * Returns: None
59717836SJohn.Forte@Sun.COM  */
59727836SJohn.Forte@Sun.COM static void
init_drv(char * dir_name,char * pattern_match,char * drvr_path)59737836SJohn.Forte@Sun.COM init_drv(char *dir_name, char *pattern_match, char *drvr_path)
59747836SJohn.Forte@Sun.COM {
5975*11547SBill.Gumbrell@Sun.COM 	DIR		*dirp;
5976*11547SBill.Gumbrell@Sun.COM 	struct dirent	*entp;
5977*11547SBill.Gumbrell@Sun.COM 	char		namebuf[MAXPATHLEN];
5978*11547SBill.Gumbrell@Sun.COM 	char		*result = NULL;
5979*11547SBill.Gumbrell@Sun.COM 	int		fd;
59807836SJohn.Forte@Sun.COM 
59817836SJohn.Forte@Sun.COM 	if ((dirp = opendir(dir_name)) == NULL) {
59827836SJohn.Forte@Sun.COM 		return;
59837836SJohn.Forte@Sun.COM 	}
59847836SJohn.Forte@Sun.COM 
59857836SJohn.Forte@Sun.COM 	while ((entp = readdir(dirp)) != NULL) {
59867836SJohn.Forte@Sun.COM 		/*
59877836SJohn.Forte@Sun.COM 		 * Ignore current directory and parent directory
59887836SJohn.Forte@Sun.COM 		 * entries.
59897836SJohn.Forte@Sun.COM 		 */
59907836SJohn.Forte@Sun.COM 		if ((strcmp(entp->d_name, ".") == 0) ||
59917836SJohn.Forte@Sun.COM 		    (strcmp(entp->d_name, "..") == 0) ||
59927836SJohn.Forte@Sun.COM 		    (fnmatch(pattern_match, entp->d_name, 0) != 0)) {
59937836SJohn.Forte@Sun.COM 			continue;
59947836SJohn.Forte@Sun.COM 		}
59957836SJohn.Forte@Sun.COM 
59967836SJohn.Forte@Sun.COM 		memset(namebuf, 0, sizeof (namebuf));
59977836SJohn.Forte@Sun.COM 		sprintf(namebuf, "%s/%s", dir_name, entp->d_name);
59987836SJohn.Forte@Sun.COM 
59997836SJohn.Forte@Sun.COM 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
60007836SJohn.Forte@Sun.COM 			ER_DPRINTF("  Warning: Get physical name from"
6001*11547SBill.Gumbrell@Sun.COM 			    " link failed. Link=%s\n", namebuf);
60027836SJohn.Forte@Sun.COM 			continue;
60037836SJohn.Forte@Sun.COM 		}
60047836SJohn.Forte@Sun.COM 
60057836SJohn.Forte@Sun.COM 		if (strstr(result, drvr_path) == NULL) {
60067836SJohn.Forte@Sun.COM 			free(result);
60077836SJohn.Forte@Sun.COM 			result = NULL;
60087836SJohn.Forte@Sun.COM 			continue;
60097836SJohn.Forte@Sun.COM 		}
60107836SJohn.Forte@Sun.COM 
60117836SJohn.Forte@Sun.COM 		if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) != -1) {
60127836SJohn.Forte@Sun.COM 			close(fd);
60137836SJohn.Forte@Sun.COM 			break;
60147836SJohn.Forte@Sun.COM 		} else if (errno != EBUSY) {
60157836SJohn.Forte@Sun.COM 			free(result);
60167836SJohn.Forte@Sun.COM 			result = NULL;
60177836SJohn.Forte@Sun.COM 			continue;
60187836SJohn.Forte@Sun.COM 		} else {
60197836SJohn.Forte@Sun.COM 			break;
60207836SJohn.Forte@Sun.COM 		}
60217836SJohn.Forte@Sun.COM 	}
60227836SJohn.Forte@Sun.COM 	free(result);
60237836SJohn.Forte@Sun.COM 	closedir(dirp);
60247836SJohn.Forte@Sun.COM }
6025