19e86db79SHyon Kim /*
29e86db79SHyon Kim  * CDDL HEADER START
39e86db79SHyon Kim  *
49e86db79SHyon Kim  * The contents of this file are subject to the terms of the
59e86db79SHyon Kim  * Common Development and Distribution License (the "License").
69e86db79SHyon Kim  * You may not use this file except in compliance with the License.
79e86db79SHyon Kim  *
89e86db79SHyon Kim  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e86db79SHyon Kim  * or http://www.opensolaris.org/os/licensing.
109e86db79SHyon Kim  * See the License for the specific language governing permissions
119e86db79SHyon Kim  * and limitations under the License.
129e86db79SHyon Kim  *
139e86db79SHyon Kim  * When distributing Covered Code, include this CDDL HEADER in each
149e86db79SHyon Kim  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e86db79SHyon Kim  * If applicable, add the following below this CDDL HEADER, with the
169e86db79SHyon Kim  * fields enclosed by brackets "[]" replaced with your own identifying
179e86db79SHyon Kim  * information: Portions Copyright [yyyy] [name of copyright owner]
189e86db79SHyon Kim  *
199e86db79SHyon Kim  * CDDL HEADER END
209e86db79SHyon Kim  */
219e86db79SHyon Kim /*
229e86db79SHyon Kim  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239e86db79SHyon Kim  * Use is subject to license terms.
249e86db79SHyon Kim  */
259e86db79SHyon Kim 
269e86db79SHyon Kim #include <unistd.h>
279e86db79SHyon Kim #include <stdlib.h>
289e86db79SHyon Kim #include <ctype.h>
299e86db79SHyon Kim #include <errno.h>
309e86db79SHyon Kim #include <printAttrs.h>
319e86db79SHyon Kim #include <smhbaapi.h>
329e86db79SHyon Kim 
339e86db79SHyon Kim #define	TABLEN	2
349e86db79SHyon Kim typedef struct inputArgs {
359e86db79SHyon Kim 	int 		wwnCount;
369e86db79SHyon Kim 	char 		**wwn_argv;
379e86db79SHyon Kim 	uint64_t 	portWWN;
389e86db79SHyon Kim 	char		*hbaName;
399e86db79SHyon Kim 	int		pflag;
409e86db79SHyon Kim 	int		*wwn_flag;
419e86db79SHyon Kim } inputArg_t;
429e86db79SHyon Kim 
439e86db79SHyon Kim typedef struct tgt_mapping {
449e86db79SHyon Kim 	SMHBA_SCSIENTRY	tgtentry;
459e86db79SHyon Kim 	uchar_t		inq_vid[8];
469e86db79SHyon Kim 	uchar_t		inq_pid[16];
479e86db79SHyon Kim 	uchar_t		inq_dtype;
489e86db79SHyon Kim 	struct tgt_mapping *next;
499e86db79SHyon Kim }tgt_mapping;
509e86db79SHyon Kim 
519e86db79SHyon Kim /*
529e86db79SHyon Kim  * Remote port tree node structure.
539e86db79SHyon Kim  */
549e86db79SHyon Kim typedef struct smhba_rp_tree {
559e86db79SHyon Kim 	SMHBA_PORTATTRIBUTES	portattr;
569e86db79SHyon Kim 	SMHBA_SAS_PORT		sasattr;
579e86db79SHyon Kim 	tgt_mapping		*first_entry;
589e86db79SHyon Kim 	int			printed;
599e86db79SHyon Kim 	struct smhba_rp_tree	*parent;
609e86db79SHyon Kim 	struct smhba_rp_tree	*child;
619e86db79SHyon Kim 	struct smhba_rp_tree	*sibling;
629e86db79SHyon Kim }rp_tree_t;
639e86db79SHyon Kim 
649e86db79SHyon Kim /*
659e86db79SHyon Kim  * Report LUN data structure.
669e86db79SHyon Kim  */
679e86db79SHyon Kim struct lun {
689e86db79SHyon Kim 	uchar_t	val[8];
699e86db79SHyon Kim };
709e86db79SHyon Kim 
719e86db79SHyon Kim typedef struct rep_luns_rsp {
729e86db79SHyon Kim 	uint32_t    length;
739e86db79SHyon Kim 	uint32_t    rsrvd;
749e86db79SHyon Kim 	struct lun  lun[1];
759e86db79SHyon Kim } rep_luns_rsp_t;
769e86db79SHyon Kim 
779e86db79SHyon Kim /*
789e86db79SHyon Kim  * The following flag is used for printing HBA header on-demand.
799e86db79SHyon Kim  */
809e86db79SHyon Kim static int g_printHBA = 0;
819e86db79SHyon Kim 
829e86db79SHyon Kim /*
839e86db79SHyon Kim  * The following structure is for sorted output of HBA and HBA Port.
849e86db79SHyon Kim  */
859e86db79SHyon Kim typedef struct _sas_elem {
869e86db79SHyon Kim 	char	name[256];
879e86db79SHyon Kim 	int	index;
889e86db79SHyon Kim }sas_elem_t;
899e86db79SHyon Kim 
909e86db79SHyon Kim /*
919e86db79SHyon Kim  * The following two functions are for generating hierachy of expander
929e86db79SHyon Kim  * subcommand.
939e86db79SHyon Kim  */
949e86db79SHyon Kim static int
959e86db79SHyon Kim sas_rp_tree_insert(rp_tree_t **rproot, rp_tree_t *rpnode);
969e86db79SHyon Kim static int
979e86db79SHyon Kim sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
989e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
999e86db79SHyon Kim     rp_tree_t *rpnode, inputArg_t *input, int gident,
1009e86db79SHyon Kim     int *printPort);
1019e86db79SHyon Kim static int
1029e86db79SHyon Kim sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
1039e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
1049e86db79SHyon Kim     inputArg_t *input, int lident, int gident);
1059e86db79SHyon Kim static int
1069e86db79SHyon Kim sas_print_rpnode(inputArg_t *input,
1079e86db79SHyon Kim     rp_tree_t *rpnode, int lident, int gident);
1089e86db79SHyon Kim static void sas_rp_tree_free(rp_tree_t *rproot);
1099e86db79SHyon Kim 
1109e86db79SHyon Kim typedef int (*processPortFunc)(HBA_HANDLE handle, char *adapterName,
1119e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1129e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
1139e86db79SHyon Kim 
1149e86db79SHyon Kim static int processHBA(inputArg_t *input,
1159e86db79SHyon Kim     processPortFunc processPort);
1169e86db79SHyon Kim 
1179e86db79SHyon Kim static int isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN);
1189e86db79SHyon Kim static int isStringInArgv(inputArg_t *input, const char *adapterName);
1199e86db79SHyon Kim static boolean_t compareLUName(char *cmdArg, char *osName);
1209e86db79SHyon Kim static discoveredDevice *LUList = NULL;
1219e86db79SHyon Kim static targetPortList_t *gTargetPortList = NULL;
1229e86db79SHyon Kim 
1239e86db79SHyon Kim /* processes for hanlding local HBA info */
1249e86db79SHyon Kim static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
1259e86db79SHyon Kim     int numberOfPorts, const char *adapterName);
1269e86db79SHyon Kim static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
1279e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1289e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
1299e86db79SHyon Kim static int processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
1309e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, int pflag);
1319e86db79SHyon Kim static int processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex,
1329e86db79SHyon Kim     int phyIndex, PSMHBA_SAS_PHY phyattrs, int pflag);
1339e86db79SHyon Kim 
1349e86db79SHyon Kim /* process for handling expander info */
1359e86db79SHyon Kim static int handleExpander(HBA_HANDLE handle, char *adapterName,
1369e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1379e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
1389e86db79SHyon Kim 
1399e86db79SHyon Kim /* process for handling target port info */
1409e86db79SHyon Kim static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
1419e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1429e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
1439e86db79SHyon Kim 
1449e86db79SHyon Kim /* process for handling logical unit info */
1459e86db79SHyon Kim static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
1469e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1479e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
1489e86db79SHyon Kim 
1499e86db79SHyon Kim /* process for target port SCSI processing */
1509e86db79SHyon Kim static int
1519e86db79SHyon Kim searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
1529e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
1539e86db79SHyon Kim     struct targetPortConfig *configData);
1549e86db79SHyon Kim 
1559e86db79SHyon Kim /* process for target port config processing */
1569e86db79SHyon Kim static int searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
1579e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
1589e86db79SHyon Kim     SMHBA_SAS_PORT *sasattr, int pflag);
1599e86db79SHyon Kim 
1609e86db79SHyon Kim /* process for logical-unit config processing */
1619e86db79SHyon Kim static int
1629e86db79SHyon Kim searchDevice(PSMHBA_SCSIENTRY entryP, HBA_HANDLE handle, HBA_WWN hbaPortWWN,
1639e86db79SHyon Kim     HBA_WWN domainPortWWN, char *portName, int pflag);
1649e86db79SHyon Kim 
1659e86db79SHyon Kim /* get domain port out of hba-port phy attr. */
1669e86db79SHyon Kim HBA_STATUS get_domainPort(HBA_HANDLE handle,
1679e86db79SHyon Kim     int portindex, PSMHBA_PORTATTRIBUTES port,
1689e86db79SHyon Kim     HBA_WWN *pdomainPort);
1699e86db79SHyon Kim 
1709e86db79SHyon Kim static int
1719e86db79SHyon Kim sas_name_comp(const char *name1, const char *name2);
1729e86db79SHyon Kim static void
1739e86db79SHyon Kim sas_elem_sort(sas_elem_t *array, int nelem);
1749e86db79SHyon Kim 
1759e86db79SHyon Kim /*
1769e86db79SHyon Kim  * function for hba subcommand
1779e86db79SHyon Kim  *
1789e86db79SHyon Kim  * Arguments:
1799e86db79SHyon Kim  *	wwnCount - count of the number of WWNs in wwn_argv
1809e86db79SHyon Kim  *	    if wwnCount > 0, then we will only print information for
1819e86db79SHyon Kim  *		the hba ports listed in wwn_argv
1829e86db79SHyon Kim  *	    if wwnCount == 0, then we will print information on all hba ports
1839e86db79SHyon Kim  *	wwn_argv - argument array of hba port WWNs
1849e86db79SHyon Kim  *	options - any options specified by the caller
1859e86db79SHyon Kim  *
1869e86db79SHyon Kim  * returns:
1879e86db79SHyon Kim  *	0	if successful
1889e86db79SHyon Kim  *	>0	otherwise
1899e86db79SHyon Kim  */
1909e86db79SHyon Kim int
sas_util_list_hba(int hbaCount,char ** hba_argv,cmdOptions_t * options)1919e86db79SHyon Kim sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options)
1929e86db79SHyon Kim {
1939e86db79SHyon Kim 	HBA_STATUS		status;
1949e86db79SHyon Kim 	int			processHBA_flags = 0;
1959e86db79SHyon Kim 	inputArg_t		input;
1969e86db79SHyon Kim 	int 			err_cnt = 0;
1979e86db79SHyon Kim 
1989e86db79SHyon Kim 	/* process each of the options */
1999e86db79SHyon Kim 	for (; options->optval; options++) {
2009e86db79SHyon Kim 		switch (options->optval) {
2019e86db79SHyon Kim 		case 'v':
2029e86db79SHyon Kim 			processHBA_flags |= PRINT_VERBOSE;
2039e86db79SHyon Kim 			break;
2049e86db79SHyon Kim 		default:
2059e86db79SHyon Kim 			break;
2069e86db79SHyon Kim 		}
2079e86db79SHyon Kim 	}
2089e86db79SHyon Kim 
2099e86db79SHyon Kim 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
210*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %s\n",
2119e86db79SHyon Kim 		    gettext("Failed to load SM-HBA libraries."
2129e86db79SHyon Kim 		    "Reason:"), getHBAStatus(status));
2139e86db79SHyon Kim 		err_cnt++;
2149e86db79SHyon Kim 		return (err_cnt);
2159e86db79SHyon Kim 	}
2169e86db79SHyon Kim 
217*b172429eSMarco van Wieringen 	(void) memset(&input, 0, sizeof (input));
2189e86db79SHyon Kim 	/* utilize wwnCount and wwn_argv for hbaCount and hba_argv */
2199e86db79SHyon Kim 	input.wwnCount = hbaCount;
2209e86db79SHyon Kim 	input.wwn_argv = hba_argv;
2219e86db79SHyon Kim 	input.pflag = processHBA_flags;
2229e86db79SHyon Kim 
2239e86db79SHyon Kim 	/*
2249e86db79SHyon Kim 	 * Process and filter for every local hba,
2259e86db79SHyon Kim 	 * when the hba is not specificed, print all hba(s).
2269e86db79SHyon Kim 	 */
2279e86db79SHyon Kim 	err_cnt += processHBA(&input, NULL);
2289e86db79SHyon Kim 
2299e86db79SHyon Kim 	(void) HBA_FreeLibrary();
2309e86db79SHyon Kim 
2319e86db79SHyon Kim 	return (err_cnt);
2329e86db79SHyon Kim }
2339e86db79SHyon Kim 
2349e86db79SHyon Kim /*
2359e86db79SHyon Kim  * function for hba-port subcommand
2369e86db79SHyon Kim  *
2379e86db79SHyon Kim  * Arguments:
2389e86db79SHyon Kim  *	wwnCount - count of the number of WWNs in wwn_argv
2399e86db79SHyon Kim  *	    if wwnCount > 0, then we will only print information for
2409e86db79SHyon Kim  *		the hba ports listed in wwn_argv
2419e86db79SHyon Kim  *	    if wwnCount == 0, then we will print information on all hba ports
2429e86db79SHyon Kim  *	wwn_argv - argument array of hba port WWNs
2439e86db79SHyon Kim  *	options - any options specified by the caller
2449e86db79SHyon Kim  *
2459e86db79SHyon Kim  * returns:
2469e86db79SHyon Kim  *	0	if successful
2479e86db79SHyon Kim  *	>0	otherwise
2489e86db79SHyon Kim  */
2499e86db79SHyon Kim int
sas_util_list_hbaport(int wwnCount,char ** wwn_argv,cmdOptions_t * options)2509e86db79SHyon Kim sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
2519e86db79SHyon Kim {
2529e86db79SHyon Kim 	HBA_STATUS		status;
2539e86db79SHyon Kim 	int			processHBA_flags = 0;
2549e86db79SHyon Kim 	inputArg_t		input;
2559e86db79SHyon Kim 	int 			err_cnt = 0;
2569e86db79SHyon Kim 	char			hbaName[256] = {'\0'};
2579e86db79SHyon Kim 
2589e86db79SHyon Kim 	/* process each of the options */
2599e86db79SHyon Kim 	for (; options->optval; options++) {
2609e86db79SHyon Kim 		switch (options->optval) {
2619e86db79SHyon Kim 		case 'a':
262*b172429eSMarco van Wieringen 			(void) strlcpy(hbaName,
2639e86db79SHyon Kim 			    options->optarg, sizeof (hbaName));
2649e86db79SHyon Kim 			break;
2659e86db79SHyon Kim 		case 'y':
2669e86db79SHyon Kim 			processHBA_flags |= PRINT_PHY;
2679e86db79SHyon Kim 			break;
2689e86db79SHyon Kim 		case 'l':
2699e86db79SHyon Kim 			processHBA_flags |= PRINT_PHY_LINKSTAT;
2709e86db79SHyon Kim 			break;
2719e86db79SHyon Kim 		case 'v':
2729e86db79SHyon Kim 			processHBA_flags |= PRINT_VERBOSE;
2739e86db79SHyon Kim 			break;
2749e86db79SHyon Kim 		default:
2759e86db79SHyon Kim 			break;
2769e86db79SHyon Kim 		}
2779e86db79SHyon Kim 	}
2789e86db79SHyon Kim 
2799e86db79SHyon Kim 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
280*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %s\n",
2819e86db79SHyon Kim 		    gettext("Failed to load SM-HBA libraries."
2829e86db79SHyon Kim 		    "Reason:"), getHBAStatus(status));
2839e86db79SHyon Kim 		err_cnt++;
2849e86db79SHyon Kim 		return (err_cnt);
2859e86db79SHyon Kim 	}
2869e86db79SHyon Kim 
287*b172429eSMarco van Wieringen 	(void) memset(&input, 0, sizeof (input));
2889e86db79SHyon Kim 	input.wwnCount = wwnCount;
2899e86db79SHyon Kim 	input.wwn_argv = wwn_argv;
2909e86db79SHyon Kim 	input.hbaName = hbaName;
2919e86db79SHyon Kim 	input.pflag = processHBA_flags;
2929e86db79SHyon Kim 
2939e86db79SHyon Kim 	/*
2949e86db79SHyon Kim 	 * Process and filter for every local hba-port,
2959e86db79SHyon Kim 	 * when the hba-port is not specificed, print all hba-port(s).
2969e86db79SHyon Kim 	 */
2979e86db79SHyon Kim 	err_cnt += processHBA(&input, handleHBAPort);
2989e86db79SHyon Kim 
2999e86db79SHyon Kim 	(void) HBA_FreeLibrary();
3009e86db79SHyon Kim 
3019e86db79SHyon Kim 	return (err_cnt);
3029e86db79SHyon Kim }
3039e86db79SHyon Kim 
3049e86db79SHyon Kim /*
3059e86db79SHyon Kim  * function for expander subcommand
3069e86db79SHyon Kim  *
3079e86db79SHyon Kim  * Arguments:
3089e86db79SHyon Kim  *	wwnCount - the number of Remote Port SAS Address in wwn_argv
3099e86db79SHyon Kim  *	    if wwnCount == 0, then print information on all
3109e86db79SHyon Kim  *		expander devices.
3119e86db79SHyon Kim  *	    if wwnCount > 0, then print information for the exapnders
3129e86db79SHyon Kim  *		given in wwn_argv.
3139e86db79SHyon Kim  *	wwn_argv - array of WWNs
3149e86db79SHyon Kim  *	options - options specified by the caller
3159e86db79SHyon Kim  *
3169e86db79SHyon Kim  * returns:
3179e86db79SHyon Kim  *	0	if successful
3189e86db79SHyon Kim  *	>0	otherwise
3199e86db79SHyon Kim  */
3209e86db79SHyon Kim int
sas_util_list_expander(int wwnCount,char ** wwn_argv,cmdOptions_t * options)3219e86db79SHyon Kim sas_util_list_expander(int wwnCount, char **wwn_argv, cmdOptions_t *options)
3229e86db79SHyon Kim {
3239e86db79SHyon Kim 	HBA_STATUS		status;
3249e86db79SHyon Kim 	int			processHBA_flags = 0;
3259e86db79SHyon Kim 	char			hbaPort[MAXPATHLEN + 1] = {0};
3269e86db79SHyon Kim 	inputArg_t		input;
3279e86db79SHyon Kim 	int			err_cnt = 0;
3289e86db79SHyon Kim 
3299e86db79SHyon Kim 	/* process each of the options */
3309e86db79SHyon Kim 	for (; options->optval; options++) {
3319e86db79SHyon Kim 		switch (options->optval) {
3329e86db79SHyon Kim 		case 'p':
3339e86db79SHyon Kim 			(void) strlcpy(hbaPort, options->optarg,
3349e86db79SHyon Kim 			    sizeof (hbaPort));
3359e86db79SHyon Kim 			break;
3369e86db79SHyon Kim 		case 't':
3379e86db79SHyon Kim 			processHBA_flags |= PRINT_TARGET_PORT;
3389e86db79SHyon Kim 			break;
3399e86db79SHyon Kim 		case 'v':
3409e86db79SHyon Kim 			processHBA_flags |= PRINT_VERBOSE;
3419e86db79SHyon Kim 			break;
3429e86db79SHyon Kim 		default:
3439e86db79SHyon Kim 			break;
3449e86db79SHyon Kim 		}
3459e86db79SHyon Kim 	}
3469e86db79SHyon Kim 
3479e86db79SHyon Kim 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
348*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %s\n",
3499e86db79SHyon Kim 		    gettext("Failed to load SM-HBA libraries."
3509e86db79SHyon Kim 		    "Reason:"), getHBAStatus(status));
3519e86db79SHyon Kim 		err_cnt++;
3529e86db79SHyon Kim 		return (err_cnt);
3539e86db79SHyon Kim 	}
3549e86db79SHyon Kim 
355*b172429eSMarco van Wieringen 	(void) memset(&input, 0, sizeof (input));
3569e86db79SHyon Kim 	input.wwnCount = wwnCount;
3579e86db79SHyon Kim 	input.wwn_argv = wwn_argv;
3589e86db79SHyon Kim 	input.pflag = processHBA_flags;
3599e86db79SHyon Kim 	input.hbaName = hbaPort;
3609e86db79SHyon Kim 
3619e86db79SHyon Kim 	/*
3629e86db79SHyon Kim 	 * Process and filter for every hba-port,
3639e86db79SHyon Kim 	 * when the hba-port is not specificed, print all hba-port(s).
3649e86db79SHyon Kim 	 */
3659e86db79SHyon Kim 	err_cnt += processHBA(&input, handleExpander);
3669e86db79SHyon Kim 
3679e86db79SHyon Kim 	(void) HBA_FreeLibrary();
3689e86db79SHyon Kim 
3699e86db79SHyon Kim 	return (err_cnt);
3709e86db79SHyon Kim }
3719e86db79SHyon Kim 
3729e86db79SHyon Kim /*
3739e86db79SHyon Kim  * function for target-port subcommand
3749e86db79SHyon Kim  *
3759e86db79SHyon Kim  * Arguments:
3769e86db79SHyon Kim  *	wwnCount - the number of Remote Port SAS Address in wwn_argv
3779e86db79SHyon Kim  *	    if wwnCount == 0, then print information on all
3789e86db79SHyon Kim  *		target ports.
3799e86db79SHyon Kim  *	    if wwnCount > 0, then print information for the target ports
3809e86db79SHyon Kim  *		given in wwn_argv.
3819e86db79SHyon Kim  *	wwn_argv - array of WWNs
3829e86db79SHyon Kim  *	options - options specified by the caller
3839e86db79SHyon Kim  *
3849e86db79SHyon Kim  * returns:
3859e86db79SHyon Kim  *	0	if successful
3869e86db79SHyon Kim  *	>0	otherwise
3879e86db79SHyon Kim  */
3889e86db79SHyon Kim int
sas_util_list_targetport(int tpCount,char ** tpArgv,cmdOptions_t * options)3899e86db79SHyon Kim sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options)
3909e86db79SHyon Kim {
3919e86db79SHyon Kim 	HBA_STATUS		status;
3929e86db79SHyon Kim 	int			processHBA_flags = 0;
3939e86db79SHyon Kim 	int			tp, tpFound;
3949e86db79SHyon Kim 	inputArg_t		input;
3959e86db79SHyon Kim 	targetPortList_t	*tpListWalk;
3969e86db79SHyon Kim 	int			err_cnt = 0;
3979e86db79SHyon Kim 	uint64_t		tmpAddr;
3989e86db79SHyon Kim 
3999e86db79SHyon Kim 	/* process each of the options */
4009e86db79SHyon Kim 	for (; options->optval; options++) {
4019e86db79SHyon Kim 		switch (options->optval) {
4029e86db79SHyon Kim 		case 's':
4039e86db79SHyon Kim 			processHBA_flags |= PRINT_TARGET_SCSI;
4049e86db79SHyon Kim 			break;
4059e86db79SHyon Kim 		case 'v':
4069e86db79SHyon Kim 			processHBA_flags |= PRINT_VERBOSE;
4079e86db79SHyon Kim 			break;
4089e86db79SHyon Kim 		default:
4099e86db79SHyon Kim 			break;
4109e86db79SHyon Kim 		}
4119e86db79SHyon Kim 	}
4129e86db79SHyon Kim 
4139e86db79SHyon Kim 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
414*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %s\n",
4159e86db79SHyon Kim 		    gettext("Failed to load SM-HBA libraries."
4169e86db79SHyon Kim 		    "Reason:"), getHBAStatus(status));
4179e86db79SHyon Kim 		err_cnt++;
4189e86db79SHyon Kim 		return (err_cnt);
4199e86db79SHyon Kim 	}
4209e86db79SHyon Kim 
421*b172429eSMarco van Wieringen 	(void) memset(&input, 0, sizeof (input));
4229e86db79SHyon Kim 	input.wwnCount = tpCount;
4239e86db79SHyon Kim 	input.wwn_argv = tpArgv;
4249e86db79SHyon Kim 	input.pflag = processHBA_flags;
4259e86db79SHyon Kim 
4269e86db79SHyon Kim 	/*
4279e86db79SHyon Kim 	 * Process and filter for every hba-port,
4289e86db79SHyon Kim 	 * when the hba-port is not specificed, print all hba-port(s).
4299e86db79SHyon Kim 	 */
4309e86db79SHyon Kim 	err_cnt += processHBA(&input, handleTargetPort);
4319e86db79SHyon Kim 
4329e86db79SHyon Kim 	if (tpCount == 0) {
4339e86db79SHyon Kim 		/* list all target port */
4349e86db79SHyon Kim 		for (tpListWalk = gTargetPortList; tpListWalk != NULL;
4359e86db79SHyon Kim 		    tpListWalk = tpListWalk->next) {
4369e86db79SHyon Kim 			err_cnt += printTargetPortInfo(tpListWalk, input.pflag);
4379e86db79SHyon Kim 		}
4389e86db79SHyon Kim 	} else {
4399e86db79SHyon Kim 		/*
4409e86db79SHyon Kim 		 * When operands provided, we should set the error code
4419e86db79SHyon Kim 		 * only if there are issues related with the operands.
4429e86db79SHyon Kim 		 */
4439e86db79SHyon Kim 		err_cnt = 0;
4449e86db79SHyon Kim 		/*
4459e86db79SHyon Kim 		 * list any paths not found first
4469e86db79SHyon Kim 		 * this gives the user cleaner output
4479e86db79SHyon Kim 		 */
4489e86db79SHyon Kim 		for (tp = 0; tp < tpCount; tp++) {
4499e86db79SHyon Kim 			errno = 0;
4509e86db79SHyon Kim 			tmpAddr = strtoull(tpArgv[tp], NULL, 16);
4519e86db79SHyon Kim 			if ((tmpAddr == 0) && (errno != 0)) {
4529e86db79SHyon Kim 				err_cnt++;
4539e86db79SHyon Kim 				continue;
4549e86db79SHyon Kim 			}
4559e86db79SHyon Kim 			for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
4569e86db79SHyon Kim 			    tpListWalk != NULL;
4579e86db79SHyon Kim 			    tpListWalk = tpListWalk->next) {
4589e86db79SHyon Kim 				if (wwnConversion(tpListWalk->sasattr.
4599e86db79SHyon Kim 				    LocalSASAddress.wwn) == tmpAddr) {
4609e86db79SHyon Kim 					tpFound = B_TRUE;
4619e86db79SHyon Kim 					break;
4629e86db79SHyon Kim 				}
4639e86db79SHyon Kim 			}
4649e86db79SHyon Kim 			if (tpFound == B_FALSE) {
465*b172429eSMarco van Wieringen 				(void) fprintf(stderr,
4669e86db79SHyon Kim 				    "Error: Target Port %s Not Found \n",
4679e86db79SHyon Kim 				    tpArgv[tp]);
4689e86db79SHyon Kim 				err_cnt++;
4699e86db79SHyon Kim 			}
4709e86db79SHyon Kim 		}
4719e86db79SHyon Kim 		/* list all paths requested in order requested */
4729e86db79SHyon Kim 		for (tp = 0; tp < tpCount; tp++) {
4739e86db79SHyon Kim 			errno = 0;
4749e86db79SHyon Kim 			tmpAddr = strtoull(tpArgv[tp], NULL, 16);
4759e86db79SHyon Kim 			if ((tmpAddr == 0) && (errno != 0)) {
4769e86db79SHyon Kim 				continue;
4779e86db79SHyon Kim 			}
4789e86db79SHyon Kim 			for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
4799e86db79SHyon Kim 			    tpListWalk != NULL;
4809e86db79SHyon Kim 			    tpListWalk = tpListWalk->next) {
4819e86db79SHyon Kim 				if (wwnConversion(tpListWalk->sasattr.
4829e86db79SHyon Kim 				    LocalSASAddress.wwn) == tmpAddr) {
4839e86db79SHyon Kim 					err_cnt += printTargetPortInfo(
4849e86db79SHyon Kim 					    tpListWalk,
4859e86db79SHyon Kim 					    processHBA_flags);
4869e86db79SHyon Kim 				}
4879e86db79SHyon Kim 			}
4889e86db79SHyon Kim 		}
4899e86db79SHyon Kim 	}
4909e86db79SHyon Kim 	(void) HBA_FreeLibrary();
4919e86db79SHyon Kim 	return (err_cnt);
4929e86db79SHyon Kim }
4939e86db79SHyon Kim /*
4949e86db79SHyon Kim  * This function will enumerate all the hba and hba ports,
4959e86db79SHyon Kim  * call the callback function to proceed with futher process.
4969e86db79SHyon Kim  *
4979e86db79SHyon Kim  * Arguments:
4989e86db79SHyon Kim  *	input - contains all the input parameters.
4999e86db79SHyon Kim  *	processPort - a callback function when handling each port.
5009e86db79SHyon Kim  *
5019e86db79SHyon Kim  *  Return Value:
5029e86db79SHyon Kim  *	    0		sucessfully processed handle
5039e86db79SHyon Kim  *	    >0		error has occured
5049e86db79SHyon Kim  */
5059e86db79SHyon Kim static int
processHBA(inputArg_t * input,processPortFunc processPort)5069e86db79SHyon Kim processHBA(inputArg_t *input, processPortFunc processPort)
5079e86db79SHyon Kim {
5089e86db79SHyon Kim 	int			numAdapters = 0;
5099e86db79SHyon Kim 	int			matchedHBAs = 0;
5109e86db79SHyon Kim 	int			matchedHBAPorts = 0;
5119e86db79SHyon Kim 	int			hbaPortExist = 0;
5129e86db79SHyon Kim 	HBA_STATUS		status;
5139e86db79SHyon Kim 	HBA_HANDLE		handle;
5149e86db79SHyon Kim 	HBA_UINT32		numberOfPorts = 0;
5159e86db79SHyon Kim 	int			portIndex = 0;
5169e86db79SHyon Kim 	HBA_PORTTYPE		porttype;
5179e86db79SHyon Kim 	SMHBA_LIBRARYATTRIBUTES libattrs;
5189e86db79SHyon Kim 	SMHBA_ADAPTERATTRIBUTES	attrs;
5199e86db79SHyon Kim 	SMHBA_PORTATTRIBUTES	port;
5209e86db79SHyon Kim 	SMHBA_SAS_PORT		sasattrs;
5219e86db79SHyon Kim 	int			i, sum, ret = 0;
5229e86db79SHyon Kim 	int			remote_avail = 0;
5239e86db79SHyon Kim 	int			local_avail = 0;
5249e86db79SHyon Kim 	sas_elem_t		*adpt_array = NULL;
5259e86db79SHyon Kim 	sas_elem_t		*port_array = NULL;
5269e86db79SHyon Kim 
5279e86db79SHyon Kim 	numAdapters = HBA_GetNumberOfAdapters();
5289e86db79SHyon Kim 	if (numAdapters == 0) {
529*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
5309e86db79SHyon Kim 		    gettext("Error: No Adapters Found."));
5319e86db79SHyon Kim 		return (++ret);
5329e86db79SHyon Kim 	}
5339e86db79SHyon Kim 
5349e86db79SHyon Kim 	/*
5359e86db79SHyon Kim 	 * To deal with mismatching HBA/HBA Port/Expander Port, we need an
5369e86db79SHyon Kim 	 * array of flags for each operands.
5379e86db79SHyon Kim 	 */
5389e86db79SHyon Kim 	if (input->wwnCount && (processPort != handleTargetPort) &&
5399e86db79SHyon Kim 	    (processPort != handleLogicalUnit)) {
5409e86db79SHyon Kim 		input->wwn_flag = calloc(input->wwnCount, sizeof (int));
5419e86db79SHyon Kim 		if (input->wwn_flag == NULL) {
542*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n",
5439e86db79SHyon Kim 			    gettext("No enough memory on heap"));
5449e86db79SHyon Kim 			return (++ret);
5459e86db79SHyon Kim 		}
5469e86db79SHyon Kim 	}
5479e86db79SHyon Kim 
5489e86db79SHyon Kim 	adpt_array = calloc(numAdapters, sizeof (sas_elem_t));
5499e86db79SHyon Kim 	if (adpt_array == NULL) {
550*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
5519e86db79SHyon Kim 		    gettext("No enough memory on heap"));
5529e86db79SHyon Kim 		if (input->wwn_flag) {
5539e86db79SHyon Kim 			free(input->wwn_flag);
5549e86db79SHyon Kim 			input->wwn_flag = NULL;
5559e86db79SHyon Kim 		}
5569e86db79SHyon Kim 		return (++ret);
5579e86db79SHyon Kim 	}
5589e86db79SHyon Kim 	for (i = 0; i < numAdapters; i++) {
5599e86db79SHyon Kim 		status =
5609e86db79SHyon Kim 		    SMHBA_GetVendorLibraryAttributes(i, &libattrs);
5619e86db79SHyon Kim 		/*
5629e86db79SHyon Kim 		 * If we get SAS incompatible library warning here,
5639e86db79SHyon Kim 		 * just skip the following steps.
5649e86db79SHyon Kim 		 */
5659e86db79SHyon Kim 		if (status != 1) {
5669e86db79SHyon Kim 			continue;
5679e86db79SHyon Kim 		}
5689e86db79SHyon Kim 		status = HBA_GetAdapterName(i, adpt_array[i].name);
5699e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
570*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s %d %s %s\n",
5719e86db79SHyon Kim 			    gettext("Error: Failed to get the name for"
5729e86db79SHyon Kim 			    " HBA index"),
5739e86db79SHyon Kim 			    i, gettext("Reason:"),
5749e86db79SHyon Kim 			    getHBAStatus(status));
5759e86db79SHyon Kim 			ret++;
5769e86db79SHyon Kim 			continue;
5779e86db79SHyon Kim 		}
5789e86db79SHyon Kim 		adpt_array[i].index = i;
5799e86db79SHyon Kim 	}
5809e86db79SHyon Kim 	/* Sort the HBA Name in place. */
5819e86db79SHyon Kim 	sas_elem_sort(adpt_array, numAdapters);
5829e86db79SHyon Kim 
5839e86db79SHyon Kim 	for (i = 0; i < numAdapters; i++) {
5849e86db79SHyon Kim 		int times = 0;
5859e86db79SHyon Kim 		if (adpt_array[i].name[0] != '\0') {
5869e86db79SHyon Kim 			if ((handle = HBA_OpenAdapter(adpt_array[i].name))
5879e86db79SHyon Kim 			    == 0) {
588*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s %s.\n",
5899e86db79SHyon Kim 				    gettext("Error: Failed to open adapter"),
5909e86db79SHyon Kim 				    adpt_array[i].name);
5919e86db79SHyon Kim 				ret++;
5929e86db79SHyon Kim 				continue;
5939e86db79SHyon Kim 			}
5949e86db79SHyon Kim 		} else {
5959e86db79SHyon Kim 			continue;
5969e86db79SHyon Kim 		}
5979e86db79SHyon Kim 
5989e86db79SHyon Kim 		/*
5999e86db79SHyon Kim 		 * We need to support an adapter without hba port.
6009e86db79SHyon Kim 		 * So get attributes anyway.
6019e86db79SHyon Kim 		 */
602*b172429eSMarco van Wieringen 		(void) memset(&attrs, 0, sizeof (attrs));
6039e86db79SHyon Kim 		status = SMHBA_GetAdapterAttributes(handle, &attrs);
6049e86db79SHyon Kim 		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
6059e86db79SHyon Kim 		    status == HBA_STATUS_ERROR_BUSY) &&
6069e86db79SHyon Kim 		    times++ < HBA_MAX_RETRIES) {
6079e86db79SHyon Kim 			(void) sleep(1);
6089e86db79SHyon Kim 			status = SMHBA_GetAdapterAttributes(handle,
6099e86db79SHyon Kim 			    &attrs);
6109e86db79SHyon Kim 		}
6119e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
612*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s %s %s %s\n",
6139e86db79SHyon Kim 			    gettext("Error: Failed to get attributes"
6149e86db79SHyon Kim 			    " for HBA "), adpt_array[i].name,
6159e86db79SHyon Kim 			    gettext("Reason:"),
6169e86db79SHyon Kim 			    getHBAStatus(status));
6179e86db79SHyon Kim 
6189e86db79SHyon Kim 			HBA_CloseAdapter(handle);
6199e86db79SHyon Kim 			ret++;
6209e86db79SHyon Kim 			continue;
6219e86db79SHyon Kim 		}
6229e86db79SHyon Kim 
6239e86db79SHyon Kim 		status = SMHBA_GetNumberOfPorts(handle, &numberOfPorts);
6249e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
625*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s %s %s %s\n",
6269e86db79SHyon Kim 			    gettext("Error: Failed to get number of ports "
6279e86db79SHyon Kim 			    "for HBA"), adpt_array[i].name,
6289e86db79SHyon Kim 			    gettext("Reason:"),
6299e86db79SHyon Kim 			    getHBAStatus(status));
6309e86db79SHyon Kim 			HBA_CloseAdapter(handle);
6319e86db79SHyon Kim 			ret++;
6329e86db79SHyon Kim 			continue;
6339e86db79SHyon Kim 		}
6349e86db79SHyon Kim 
6359e86db79SHyon Kim 		/*
6369e86db79SHyon Kim 		 * Deal with each subcommand for hba filter here,
6379e86db79SHyon Kim 		 * processPort is NULL for hba subcommand.
6389e86db79SHyon Kim 		 */
6399e86db79SHyon Kim 		if (processPort == NULL) {
6409e86db79SHyon Kim 			matchedHBAs += handleHBA(&attrs, input,
6419e86db79SHyon Kim 			    numberOfPorts, adpt_array[i].name);
6429e86db79SHyon Kim 			HBA_CloseAdapter(handle);
6439e86db79SHyon Kim 			continue;
6449e86db79SHyon Kim 		} else if (processPort == handleHBAPort) {
6459e86db79SHyon Kim 			if (input->hbaName[0] != '\0') {
6469e86db79SHyon Kim 				if (strcmp(input->hbaName,
6479e86db79SHyon Kim 				    adpt_array[i].name) == 0) {
6489e86db79SHyon Kim 					matchedHBAs++;
6499e86db79SHyon Kim 				} else {
6509e86db79SHyon Kim 					continue;
6519e86db79SHyon Kim 				}
6529e86db79SHyon Kim 			} else {
6539e86db79SHyon Kim 				matchedHBAs++;
6549e86db79SHyon Kim 			}
6559e86db79SHyon Kim 		} else {
6569e86db79SHyon Kim 			matchedHBAs++;
6579e86db79SHyon Kim 		}
6589e86db79SHyon Kim 
6599e86db79SHyon Kim 		/*
6609e86db79SHyon Kim 		 * In order to have a sorted output for HBA Port, we should
6619e86db79SHyon Kim 		 * do the sorting before moving on.
6629e86db79SHyon Kim 		 */
6639e86db79SHyon Kim 		if (numberOfPorts) {
6649e86db79SHyon Kim 			port_array = calloc(numberOfPorts, sizeof (sas_elem_t));
6659e86db79SHyon Kim 		}
6669e86db79SHyon Kim 		for (portIndex = 0; portIndex < numberOfPorts; portIndex++) {
6679e86db79SHyon Kim 			if ((status = SMHBA_GetPortType(handle,
6689e86db79SHyon Kim 			    portIndex, &porttype)) != HBA_STATUS_OK) {
669*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s %s %s %s\n",
6709e86db79SHyon Kim 				    gettext("Failed to get adapter port type "
6719e86db79SHyon Kim 				    "for HBA"), adpt_array[i].name,
6729e86db79SHyon Kim 				    gettext("Reason:"),
6739e86db79SHyon Kim 				    getHBAStatus(status));
6749e86db79SHyon Kim 				ret++;
6759e86db79SHyon Kim 				continue;
6769e86db79SHyon Kim 			}
6779e86db79SHyon Kim 			if (porttype != HBA_PORTTYPE_SASDEVICE) {
6789e86db79SHyon Kim 				/* skip any non-sas hba port */
6799e86db79SHyon Kim 				continue;
6809e86db79SHyon Kim 			}
681*b172429eSMarco van Wieringen 			(void) memset(&port, 0, sizeof (port));
682*b172429eSMarco van Wieringen 			(void) memset(&sasattrs, 0, sizeof (sasattrs));
6839e86db79SHyon Kim 			port.PortSpecificAttribute.SASPort = &sasattrs;
6849e86db79SHyon Kim 			if ((status = SMHBA_GetAdapterPortAttributes(
6859e86db79SHyon Kim 			    handle, portIndex, &port)) != HBA_STATUS_OK) {
6869e86db79SHyon Kim 				/*
6879e86db79SHyon Kim 				 * Not able to get port attributes.
6889e86db79SHyon Kim 				 * print out error message and
6899e86db79SHyon Kim 				 * move on to the next port
6909e86db79SHyon Kim 				 */
691*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s %s %s %d %s %s\n",
6929e86db79SHyon Kim 				    gettext("Error: Failed to get port "
6939e86db79SHyon Kim 				    "attributes for HBA"), adpt_array[i].name,
6949e86db79SHyon Kim 				    gettext("port index"), portIndex,
6959e86db79SHyon Kim 				    gettext("Reason:"),
6969e86db79SHyon Kim 				    getHBAStatus(status));
6979e86db79SHyon Kim 				ret++;
6989e86db79SHyon Kim 				continue;
6999e86db79SHyon Kim 			}
7009e86db79SHyon Kim 			(void) strlcpy(port_array[portIndex].name,
7019e86db79SHyon Kim 			    port.OSDeviceName,
7029e86db79SHyon Kim 			    sizeof (port_array[portIndex].name));
7039e86db79SHyon Kim 			port_array[portIndex].index = portIndex;
7049e86db79SHyon Kim 		}
7059e86db79SHyon Kim 		/* Sort the HBA Port Name here. */
7069e86db79SHyon Kim 		if (port_array) {
7079e86db79SHyon Kim 			sas_elem_sort(port_array, numberOfPorts);
7089e86db79SHyon Kim 		}
7099e86db79SHyon Kim 		/*
7109e86db79SHyon Kim 		 * Sum up the local hba ports available.
7119e86db79SHyon Kim 		 */
7129e86db79SHyon Kim 		local_avail += numberOfPorts;
7139e86db79SHyon Kim 
7149e86db79SHyon Kim 		/*
7159e86db79SHyon Kim 		 * Clear g_printHBA flag for expander subcommand.
7169e86db79SHyon Kim 		 */
7179e86db79SHyon Kim 		g_printHBA = 0;
7189e86db79SHyon Kim 
7199e86db79SHyon Kim 		/* process each port on the given adapter */
7209e86db79SHyon Kim 		for (portIndex = 0;
7219e86db79SHyon Kim 		    portIndex < numberOfPorts;
7229e86db79SHyon Kim 		    portIndex++) {
7239e86db79SHyon Kim 			/*
7249e86db79SHyon Kim 			 * We only handle the port which is valid.
7259e86db79SHyon Kim 			 */
7269e86db79SHyon Kim 			if (port_array[portIndex].name[0] == '\0') {
7279e86db79SHyon Kim 				continue;
7289e86db79SHyon Kim 			}
729*b172429eSMarco van Wieringen 			(void) memset(&port, 0, sizeof (port));
730*b172429eSMarco van Wieringen 			(void) memset(&sasattrs, 0, sizeof (sasattrs));
7319e86db79SHyon Kim 			port.PortSpecificAttribute.SASPort = &sasattrs;
7329e86db79SHyon Kim 
7339e86db79SHyon Kim 			(void) SMHBA_GetAdapterPortAttributes(handle,
7349e86db79SHyon Kim 			    port_array[portIndex].index, &port);
7359e86db79SHyon Kim 
7369e86db79SHyon Kim 			/*
7379e86db79SHyon Kim 			 * We have different things to do for the three
7389e86db79SHyon Kim 			 * sub-commands here.
7399e86db79SHyon Kim 			 */
7409e86db79SHyon Kim 			if (processPort == handleHBAPort) {
7419e86db79SHyon Kim 				/*
7429e86db79SHyon Kim 				 * For hba-port, we will check whether the
7439e86db79SHyon Kim 				 * specified hba port exist first.
7449e86db79SHyon Kim 				 * But if no hba port specified, we should
7459e86db79SHyon Kim 				 * by pass this check(just let hbaPortExist
7469e86db79SHyon Kim 				 * be 1).
7479e86db79SHyon Kim 				 */
7489e86db79SHyon Kim 				if (input->wwnCount > 0) {
7499e86db79SHyon Kim 					if (isStringInArgv(input,
7509e86db79SHyon Kim 					    port.OSDeviceName)) {
7519e86db79SHyon Kim 						hbaPortExist = 1;
7529e86db79SHyon Kim 						if (g_printHBA == 0) {
753*b172429eSMarco van Wieringen 							(void) fprintf(stdout,
7549e86db79SHyon Kim 							    "%s %s\n",
7559e86db79SHyon Kim 							    "HBA Name:",
7569e86db79SHyon Kim 							    adpt_array[i].name);
7579e86db79SHyon Kim 							g_printHBA = 1;
7589e86db79SHyon Kim 						}
7599e86db79SHyon Kim 					}
7609e86db79SHyon Kim 				} else {
7619e86db79SHyon Kim 					hbaPortExist = 1;
7629e86db79SHyon Kim 					if (g_printHBA == 0) {
763*b172429eSMarco van Wieringen 						(void) fprintf(stdout,
7649e86db79SHyon Kim 						    "%s %s\n",
7659e86db79SHyon Kim 						    "HBA Name:",
7669e86db79SHyon Kim 						    adpt_array[i].name);
7679e86db79SHyon Kim 						g_printHBA = 1;
7689e86db79SHyon Kim 					}
7699e86db79SHyon Kim 				}
7709e86db79SHyon Kim 			}
7719e86db79SHyon Kim 
7729e86db79SHyon Kim 			if (processPort == handleExpander) {
7739e86db79SHyon Kim 				/*
7749e86db79SHyon Kim 				 * For expander device, input->hbaName is
7759e86db79SHyon Kim 				 * the hba port name specified on the
7769e86db79SHyon Kim 				 * command line(with -p option).
7779e86db79SHyon Kim 				 */
7789e86db79SHyon Kim 				if (input->hbaName[0] != '\0') {
7799e86db79SHyon Kim 					if (strcmp(input->hbaName,
7809e86db79SHyon Kim 					    port.OSDeviceName) == 0)
7819e86db79SHyon Kim 						hbaPortExist = 1;
7829e86db79SHyon Kim 				} else
7839e86db79SHyon Kim 					hbaPortExist = 1;
7849e86db79SHyon Kim 			}
7859e86db79SHyon Kim 
7869e86db79SHyon Kim 			if (processPort == handleTargetPort) {
7879e86db79SHyon Kim 				/*
7889e86db79SHyon Kim 				 * For target port, we don't need to check the
7899e86db79SHyon Kim 				 * hba port address, so let it go here.
7909e86db79SHyon Kim 				 */
7919e86db79SHyon Kim 				hbaPortExist = 1;
7929e86db79SHyon Kim 			}
7939e86db79SHyon Kim 
7949e86db79SHyon Kim 			if (processPort == handleLogicalUnit) {
7959e86db79SHyon Kim 				/*
7969e86db79SHyon Kim 				 * For lu, we don't need to check the hba
7979e86db79SHyon Kim 				 * port address, so let it go here.
7989e86db79SHyon Kim 				 */
7999e86db79SHyon Kim 				hbaPortExist = 1;
8009e86db79SHyon Kim 			}
8019e86db79SHyon Kim 
8029e86db79SHyon Kim 			if (hbaPortExist) {
8039e86db79SHyon Kim 				if (port.PortSpecificAttribute.SASPort->
8049e86db79SHyon Kim 				    NumberofDiscoveredPorts) {
8059e86db79SHyon Kim 					remote_avail++;
8069e86db79SHyon Kim 				}
8079e86db79SHyon Kim 				ret += (*processPort)(handle,
8089e86db79SHyon Kim 				    adpt_array[i].name,
8099e86db79SHyon Kim 				    port_array[portIndex].index, &port,
8109e86db79SHyon Kim 				    &attrs, input);
8119e86db79SHyon Kim 				/*
8129e86db79SHyon Kim 				 * We should reset the hbaPortExist flag
8139e86db79SHyon Kim 				 * here for next round of check and count
8149e86db79SHyon Kim 				 * for the machedHBAPorts.
8159e86db79SHyon Kim 				 */
8169e86db79SHyon Kim 				hbaPortExist = 0;
8179e86db79SHyon Kim 				matchedHBAPorts++;
8189e86db79SHyon Kim 			}
8199e86db79SHyon Kim 		}
8209e86db79SHyon Kim 		if (port_array) {
8219e86db79SHyon Kim 			free(port_array);
8229e86db79SHyon Kim 			port_array = NULL;
8239e86db79SHyon Kim 		}
8249e86db79SHyon Kim 		HBA_CloseAdapter(handle);
8259e86db79SHyon Kim 	}
8269e86db79SHyon Kim 	if (adpt_array) {
8279e86db79SHyon Kim 		free(adpt_array);
8289e86db79SHyon Kim 		adpt_array = NULL;
8299e86db79SHyon Kim 	}
8309e86db79SHyon Kim 
8319e86db79SHyon Kim 	/*
8329e86db79SHyon Kim 	 * When we are here, we have traversed all the hba and hba ports.
8339e86db79SHyon Kim 	 */
8349e86db79SHyon Kim 	if (matchedHBAs == 0) {
835*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
8369e86db79SHyon Kim 		    gettext("Error: Matching HBA not found."));
8379e86db79SHyon Kim 		if (input->wwn_flag) {
8389e86db79SHyon Kim 			free(input->wwn_flag);
8399e86db79SHyon Kim 			input->wwn_flag = NULL;
8409e86db79SHyon Kim 		}
8419e86db79SHyon Kim 		return (++ret);
8429e86db79SHyon Kim 	} else if (processPort == NULL) {
8439e86db79SHyon Kim 		/*
8449e86db79SHyon Kim 		 * processPort == NULL signifies hba subcommand.
8459e86db79SHyon Kim 		 * If enter here, it means we have at least one matching
8469e86db79SHyon Kim 		 * hba, we need to check if there are mismatching ones.
8479e86db79SHyon Kim 		 */
8489e86db79SHyon Kim 		for (i = 0; i < input->wwnCount; i++) {
8499e86db79SHyon Kim 			if (input->wwn_flag[i] == 0) {
850*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s %s %s\n",
8519e86db79SHyon Kim 				    gettext("Error: HBA"),
8529e86db79SHyon Kim 				    input->wwn_argv[i],
8539e86db79SHyon Kim 				    gettext("not found."));
8549e86db79SHyon Kim 				ret++;
8559e86db79SHyon Kim 			}
8569e86db79SHyon Kim 		}
8579e86db79SHyon Kim 	} else {
8589e86db79SHyon Kim 		if (local_avail > 0 && matchedHBAPorts == 0) {
859*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n",
8609e86db79SHyon Kim 			    gettext("Error: Matching HBA Port "
8619e86db79SHyon Kim 			    "not found."));
8629e86db79SHyon Kim 			if (input->wwn_flag) {
8639e86db79SHyon Kim 				free(input->wwn_flag);
8649e86db79SHyon Kim 				input->wwn_flag = NULL;
8659e86db79SHyon Kim 			}
8669e86db79SHyon Kim 			return (++ret);
8679e86db79SHyon Kim 		} else if (local_avail == 0) {
868*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n",
8699e86db79SHyon Kim 			    gettext("Error: No HBA Port Configured."));
8709e86db79SHyon Kim 			if (input->wwn_flag) {
8719e86db79SHyon Kim 				free(input->wwn_flag);
8729e86db79SHyon Kim 				input->wwn_flag = NULL;
8739e86db79SHyon Kim 			}
8749e86db79SHyon Kim 			return (++ret);
8759e86db79SHyon Kim 		} else if (processPort == handleHBAPort) {
8769e86db79SHyon Kim 			/*
8779e86db79SHyon Kim 			 * If enter here, we have at least one HBA port
8789e86db79SHyon Kim 			 * matched. For hba-port subcommand, we shall check
8799e86db79SHyon Kim 			 * whether there are operands mismatching.
8809e86db79SHyon Kim 			 */
8819e86db79SHyon Kim 			for (i = 0; i < input->wwnCount; i++) {
8829e86db79SHyon Kim 				if (input->wwn_flag[i] == 0) {
883*b172429eSMarco van Wieringen 					(void) fprintf(stderr, "%s %s %s\n",
8849e86db79SHyon Kim 					    gettext("Error: HBA Port"),
8859e86db79SHyon Kim 					    input->wwn_argv[i],
8869e86db79SHyon Kim 					    gettext("not found."));
8879e86db79SHyon Kim 					ret++;
8889e86db79SHyon Kim 				}
8899e86db79SHyon Kim 			}
8909e86db79SHyon Kim 		}
8919e86db79SHyon Kim 	}
8929e86db79SHyon Kim 
8939e86db79SHyon Kim 	/*
8949e86db79SHyon Kim 	 * For expander subcommand, we need to check if the
8959e86db79SHyon Kim 	 * specified sas address(ese) exist (none/partial/all).
8969e86db79SHyon Kim 	 */
8979e86db79SHyon Kim 	if (processPort == handleExpander) {
8989e86db79SHyon Kim 		if (input->wwnCount > 0) {
8999e86db79SHyon Kim 			sum = 0;
9009e86db79SHyon Kim 			for (i = 0; i < input->wwnCount; i++) {
9019e86db79SHyon Kim 				sum += input->wwn_flag[i];
9029e86db79SHyon Kim 			}
9039e86db79SHyon Kim 			/*
9049e86db79SHyon Kim 			 * If sum is zero, it means that for all the given
9059e86db79SHyon Kim 			 * operands matching count is zero. So none of the
9069e86db79SHyon Kim 			 * specified SAS address exist actually.
9079e86db79SHyon Kim 			 */
9089e86db79SHyon Kim 			if (sum == 0) {
909*b172429eSMarco van Wieringen 				(void) fprintf(stderr, gettext("Error: "
9109e86db79SHyon Kim 				    "Matching SAS Address not found.\n"));
9119e86db79SHyon Kim 				free(input->wwn_flag);
9129e86db79SHyon Kim 				input->wwn_flag = NULL;
9139e86db79SHyon Kim 				return (++ret);
9149e86db79SHyon Kim 			}
9159e86db79SHyon Kim 
9169e86db79SHyon Kim 			/*
9179e86db79SHyon Kim 			 * If we get here, it means that some of the specified
9189e86db79SHyon Kim 			 * sas address exist, we will know through looping the
9199e86db79SHyon Kim 			 * wwn_flag array.
9209e86db79SHyon Kim 			 */
9219e86db79SHyon Kim 			for (i = 0; i < input->wwnCount; i++) {
9229e86db79SHyon Kim 				if (input->wwn_flag[i] == 0) {
923*b172429eSMarco van Wieringen 					(void) fprintf(stderr, "%s %s %s\n",
9249e86db79SHyon Kim 					    gettext("Error: SAS Address"),
9259e86db79SHyon Kim 					    input->wwn_argv[i],
9269e86db79SHyon Kim 					    gettext("not found."));
9279e86db79SHyon Kim 					ret++;
9289e86db79SHyon Kim 				}
9299e86db79SHyon Kim 			}
9309e86db79SHyon Kim 		}
9319e86db79SHyon Kim 		/* even if no remote port is found it is not an error. */
9329e86db79SHyon Kim 	}
9339e86db79SHyon Kim 	if (input->wwn_flag) {
9349e86db79SHyon Kim 		free(input->wwn_flag);
9359e86db79SHyon Kim 		input->wwn_flag = NULL;
9369e86db79SHyon Kim 	}
9379e86db79SHyon Kim 	return (ret);
9389e86db79SHyon Kim }
9399e86db79SHyon Kim 
9409e86db79SHyon Kim /*
9419e86db79SHyon Kim  * This function will handle the phy stuff for hba-port subcommand.
9429e86db79SHyon Kim  *
9439e86db79SHyon Kim  * Arguments:
9449e86db79SHyon Kim  *      handle - handle to hba port.
9459e86db79SHyon Kim  *      portIndex - the index of hba port currently being processed.
9469e86db79SHyon Kim  *      port - pointer to hba port attributes.
9479e86db79SHyon Kim  *      pflag - options user specified.
9489e86db79SHyon Kim  *
9499e86db79SHyon Kim  *  Return Value:
9509e86db79SHyon Kim  *	    0		sucessfully processed handle
9519e86db79SHyon Kim  *	    >0		error has occured
9529e86db79SHyon Kim  */
9539e86db79SHyon Kim static int
processHBAPortPhyInfo(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,int pflag)9549e86db79SHyon Kim processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
9559e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, int pflag)
9569e86db79SHyon Kim {
9579e86db79SHyon Kim 	int 		phyIndex = 0, err_cnt = 0;
9589e86db79SHyon Kim 	HBA_UINT32	numphys = 0;
9599e86db79SHyon Kim 	HBA_STATUS	status = 0;
9609e86db79SHyon Kim 	SMHBA_SAS_PHY	phyattrs;
9619e86db79SHyon Kim 
9629e86db79SHyon Kim 	if (port == NULL)
9639e86db79SHyon Kim 		return (++err_cnt);
9649e86db79SHyon Kim 
9659e86db79SHyon Kim 	numphys = port->PortSpecificAttribute.SASPort->NumberofPhys;
9669e86db79SHyon Kim 	if (numphys == 0)
9679e86db79SHyon Kim 		return (0);
9689e86db79SHyon Kim 
9699e86db79SHyon Kim 	if ((pflag & PRINT_PHY) || (pflag & PRINT_PHY_LINKSTAT))
970*b172429eSMarco van Wieringen 		(void) fprintf(stdout, "%s\n", "    Phy Information:");
9719e86db79SHyon Kim 	else
9729e86db79SHyon Kim 		return (0);
9739e86db79SHyon Kim 
9749e86db79SHyon Kim 
9759e86db79SHyon Kim 	for (phyIndex = 0; phyIndex < numphys; phyIndex++) {
976*b172429eSMarco van Wieringen 		(void) memset(&phyattrs, 0, sizeof (phyattrs));
9779e86db79SHyon Kim 		status = SMHBA_GetSASPhyAttributes(
9789e86db79SHyon Kim 		    handle, portIndex, phyIndex, &phyattrs);
9799e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
980*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s %d %s %s\n",
9819e86db79SHyon Kim 			    gettext("Failed to get SAS Phy attributes"
9829e86db79SHyon Kim 			    "phyIndex"), phyIndex,
9839e86db79SHyon Kim 			    gettext("Reason:"),
9849e86db79SHyon Kim 			    getHBAStatus(status));
9859e86db79SHyon Kim 			err_cnt++;
9869e86db79SHyon Kim 			continue;
9879e86db79SHyon Kim 		}
9889e86db79SHyon Kim 		if (pflag & PRINT_PHY)
9899e86db79SHyon Kim 			printHBAPortPhyInfo(&phyattrs);
9909e86db79SHyon Kim 		if (pflag & PRINT_PHY_LINKSTAT)
9919e86db79SHyon Kim 			err_cnt += processHBAPortPhyStat(handle,
9929e86db79SHyon Kim 			    portIndex, phyIndex, &phyattrs, pflag);
9939e86db79SHyon Kim 	}
9949e86db79SHyon Kim 	return (err_cnt);
9959e86db79SHyon Kim }
9969e86db79SHyon Kim 
9979e86db79SHyon Kim /*
9989e86db79SHyon Kim  * This function will handle the phy stuff for hba-port subcommand.
9999e86db79SHyon Kim  *
10009e86db79SHyon Kim  * Arguments:
10019e86db79SHyon Kim  *      handle - handle to hba port.
10029e86db79SHyon Kim  *      portIndex - the index of hba port currently being processed.
10039e86db79SHyon Kim  *      port - pointer to hba port attributes.
10049e86db79SHyon Kim  *      pflag - options user specified.
10059e86db79SHyon Kim  *
10069e86db79SHyon Kim  *  Return Value:
10079e86db79SHyon Kim  *	    0		sucessfully processed handle
10089e86db79SHyon Kim  *	    >0		error has occured
10099e86db79SHyon Kim  */
10109e86db79SHyon Kim static int
processHBAPortPhyStat(HBA_HANDLE handle,HBA_UINT32 portIndex,int phyIndex,PSMHBA_SAS_PHY phyattrs,int pflag)10119e86db79SHyon Kim processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex, int phyIndex,
10129e86db79SHyon Kim     PSMHBA_SAS_PHY phyattrs, int pflag)
10139e86db79SHyon Kim {
10149e86db79SHyon Kim 	HBA_STATUS		status = 0;
10159e86db79SHyon Kim 	SMHBA_PHYSTATISTICS	phystat;
10169e86db79SHyon Kim 	SMHBA_SASPHYSTATISTICS	sasphystat;
10179e86db79SHyon Kim 
10189e86db79SHyon Kim 	if ((pflag & PRINT_PHY) == 0) {
1019*b172429eSMarco van Wieringen 		(void) fprintf(stdout, "%s %d\n",
10209e86db79SHyon Kim 		    "      Identifier:", phyattrs->PhyIdentifier);
10219e86db79SHyon Kim 	}
10229e86db79SHyon Kim 
1023*b172429eSMarco van Wieringen 	(void) memset(&phystat, 0, sizeof (phystat));
1024*b172429eSMarco van Wieringen 	(void) memset(&sasphystat, 0, sizeof (sasphystat));
10259e86db79SHyon Kim 	phystat.SASPhyStatistics = &sasphystat;
10269e86db79SHyon Kim 	status = SMHBA_GetPhyStatistics(handle, portIndex, phyIndex, &phystat);
10279e86db79SHyon Kim 	if (status != HBA_STATUS_OK) {
1028*b172429eSMarco van Wieringen 		(void) fprintf(stdout, "%s\n",
10299e86db79SHyon Kim 		    "        Link Error Statistics:");
1030*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
10319e86db79SHyon Kim 		    gettext("            Failed to retrieve Link "
10329e86db79SHyon Kim 		    "Error Statistics!"));
10339e86db79SHyon Kim 		return (1);
10349e86db79SHyon Kim 	}
10359e86db79SHyon Kim 	printHBAPortPhyStatistics(phystat.SASPhyStatistics);
10369e86db79SHyon Kim 	return (0);
10379e86db79SHyon Kim }
10389e86db79SHyon Kim 
10399e86db79SHyon Kim /*
10409e86db79SHyon Kim  * Check whether the pWWN exist in the WWNs list which specified by user.
10419e86db79SHyon Kim  *
10429e86db79SHyon Kim  * Arguments:
10439e86db79SHyon Kim  *	input - contains all the input parameters.
10449e86db79SHyon Kim  *	pWWN - pointer to the hba port sas address.
10459e86db79SHyon Kim  *
10469e86db79SHyon Kim  *  Return Value:
10479e86db79SHyon Kim  *	    1		true, the pWWN exist in the sas address list specified.
10489e86db79SHyon Kim  *	    0		false.
10499e86db79SHyon Kim  */
10509e86db79SHyon Kim static int
isPortWWNInArgv(inputArg_t * input,PHBA_WWN pWWN)10519e86db79SHyon Kim isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN)
10529e86db79SHyon Kim {
10539e86db79SHyon Kim 	int 		port_wwn_counter = 0;
10549e86db79SHyon Kim 	int		portfound = 0;
10559e86db79SHyon Kim 	uint64_t	hbaWWN;
10569e86db79SHyon Kim 
10579e86db79SHyon Kim 	/* list only ports given in wwn_argv */
10589e86db79SHyon Kim 	for (port_wwn_counter = 0;
10599e86db79SHyon Kim 	    port_wwn_counter < input->wwnCount;
10609e86db79SHyon Kim 	    port_wwn_counter++) {
10619e86db79SHyon Kim 		hbaWWN = strtoull(input->wwn_argv[port_wwn_counter], NULL,
10629e86db79SHyon Kim 		    16);
10639e86db79SHyon Kim 		if (hbaWWN == 0 && errno != 0)
10649e86db79SHyon Kim 			continue;
10659e86db79SHyon Kim 		if (wwnConversion(pWWN->wwn) == hbaWWN) {
10669e86db79SHyon Kim 			if (input->wwn_flag) {
10679e86db79SHyon Kim 				input->wwn_flag[port_wwn_counter]++;
10689e86db79SHyon Kim 			}
10699e86db79SHyon Kim 			portfound = 1;
10709e86db79SHyon Kim 		}
10719e86db79SHyon Kim 	}
10729e86db79SHyon Kim 	return (portfound);
10739e86db79SHyon Kim }
10749e86db79SHyon Kim 
10759e86db79SHyon Kim /*
10769e86db79SHyon Kim  * Check whether the string value exists in the input list,
10779e86db79SHyon Kim  * which specified by user.
10789e86db79SHyon Kim  *
10799e86db79SHyon Kim  * Arguments:
10809e86db79SHyon Kim  *	input - contains all the input parameters.
10819e86db79SHyon Kim  *	stringName - could be hba adapter name
10829e86db79SHyon Kim  *	                      hba-port name.
10839e86db79SHyon Kim  *
10849e86db79SHyon Kim  *  Return Value:
10859e86db79SHyon Kim  *	    1		true, the HBA exists in the list specified.
10869e86db79SHyon Kim  *	    0		false.
10879e86db79SHyon Kim  */
10889e86db79SHyon Kim static int
isStringInArgv(inputArg_t * input,const char * stringName)10899e86db79SHyon Kim isStringInArgv(inputArg_t *input, const char *stringName)
10909e86db79SHyon Kim {
10919e86db79SHyon Kim 	int 		counter = 0;
10929e86db79SHyon Kim 	int		found = 0;
10939e86db79SHyon Kim 
10949e86db79SHyon Kim 	/* list only hba(s) given in wwn_argv */
10959e86db79SHyon Kim 	for (counter = 0;
10969e86db79SHyon Kim 	    counter < input->wwnCount;
10979e86db79SHyon Kim 	    counter++) {
10989e86db79SHyon Kim 		if (strcmp(input->wwn_argv[counter],
10999e86db79SHyon Kim 		    stringName) == 0) {
11009e86db79SHyon Kim 			if (input->wwn_flag)
11019e86db79SHyon Kim 				input->wwn_flag[counter]++;
11029e86db79SHyon Kim 			found = 1;
11039e86db79SHyon Kim 		}
11049e86db79SHyon Kim 	}
11059e86db79SHyon Kim 	return (found);
11069e86db79SHyon Kim }
11079e86db79SHyon Kim 
11089e86db79SHyon Kim /*
11099e86db79SHyon Kim  * Callback function for hba subcommand.
11109e86db79SHyon Kim  *
11119e86db79SHyon Kim  * Arguments:
11129e86db79SHyon Kim  *      attrs - pointer to adapter attributes currently being processed.
11139e86db79SHyon Kim  *	input - contains all the input parameters.
11149e86db79SHyon Kim  *	numberOfPorts - number of ports of this HBA.
11159e86db79SHyon Kim  *
11169e86db79SHyon Kim  *  Return Value:
11179e86db79SHyon Kim  *  	matching number
11189e86db79SHyon Kim  */
handleHBA(SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input,int numberOfPorts,const char * adapterName)11199e86db79SHyon Kim static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
11209e86db79SHyon Kim     int numberOfPorts, const char *adapterName)
11219e86db79SHyon Kim {
11229e86db79SHyon Kim 	int matchingHBA = 1;
11239e86db79SHyon Kim 
11249e86db79SHyon Kim 	if (input->wwnCount == 0) {
11259e86db79SHyon Kim 		printHBAInfo(attrs, input->pflag, numberOfPorts, adapterName);
11269e86db79SHyon Kim 	} else {
11279e86db79SHyon Kim 		if (isStringInArgv(input, adapterName)) {
11289e86db79SHyon Kim 			printHBAInfo(attrs,
11299e86db79SHyon Kim 			    input->pflag, numberOfPorts, adapterName);
11309e86db79SHyon Kim 		} else {
11319e86db79SHyon Kim 			matchingHBA = 0;
11329e86db79SHyon Kim 		}
11339e86db79SHyon Kim 	}
11349e86db79SHyon Kim 
11359e86db79SHyon Kim 	return (matchingHBA);
11369e86db79SHyon Kim }
11379e86db79SHyon Kim 
11389e86db79SHyon Kim /*
11399e86db79SHyon Kim  * Callback function for hba-port subcommand.
11409e86db79SHyon Kim  *
11419e86db79SHyon Kim  * Arguments:
11429e86db79SHyon Kim  *      handle - handle to hba port.
11439e86db79SHyon Kim  *      portIndex - the index of hba port currently being processed.
11449e86db79SHyon Kim  *      port - pointer to hba port attributes.
11459e86db79SHyon Kim  *      attrs - pointer to adapter attributes currently being processed.
11469e86db79SHyon Kim  *	input - contains all the input parameters.
11479e86db79SHyon Kim  *
11489e86db79SHyon Kim  *  Return Value:
11499e86db79SHyon Kim  *	    0		sucessfully processed handle
11509e86db79SHyon Kim  *	    >0		error has occured
11519e86db79SHyon Kim  */
11529e86db79SHyon Kim /*ARGSUSED*/
handleHBAPort(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)11539e86db79SHyon Kim static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
11549e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
11559e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
11569e86db79SHyon Kim {
11579e86db79SHyon Kim 	int ret = 0;
11589e86db79SHyon Kim 	printHBAPortInfo(port, attrs, input->pflag);
11599e86db79SHyon Kim 	ret = processHBAPortPhyInfo(handle, portIndex, port, input->pflag);
11609e86db79SHyon Kim 	return (ret);
11619e86db79SHyon Kim }
11629e86db79SHyon Kim 
11639e86db79SHyon Kim /*
11649e86db79SHyon Kim  * Callback function for expander subcommand.
11659e86db79SHyon Kim  *
11669e86db79SHyon Kim  * Arguments:
11679e86db79SHyon Kim  *      handle - handle to hba port.
11689e86db79SHyon Kim  *      portIndex - the index of hba port currently being processed.
11699e86db79SHyon Kim  *      port - pointer to hba port attributes.
11709e86db79SHyon Kim  *      attrs - pointer to adapter attributes currently being processed.
11719e86db79SHyon Kim  *	input - contains all the input parameters.
11729e86db79SHyon Kim  *
11739e86db79SHyon Kim  *  Return Value:
11749e86db79SHyon Kim  *	    0		sucessfully processed handle
11759e86db79SHyon Kim  *	    >0		error has occured
11769e86db79SHyon Kim  */
11779e86db79SHyon Kim /*ARGSUSED*/
handleExpander(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)11789e86db79SHyon Kim static int handleExpander(HBA_HANDLE handle, char *adapterName,
11799e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
11809e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
11819e86db79SHyon Kim {
11829e86db79SHyon Kim 	SMHBA_PORTATTRIBUTES	attr;
11839e86db79SHyon Kim 	SMHBA_SAS_PORT		sasport;
11849e86db79SHyon Kim 	HBA_STATUS		status;
11859e86db79SHyon Kim 	int			ret = 0;
11869e86db79SHyon Kim 	int			i, numberOfRP;
11879e86db79SHyon Kim 	rp_tree_t		*rpnode;
11889e86db79SHyon Kim 	rp_tree_t		*rproot = NULL;
11899e86db79SHyon Kim 	rp_tree_t		*unsolved_head = NULL;
11909e86db79SHyon Kim 	rp_tree_t		*unsolved_tail = NULL;
11919e86db79SHyon Kim 	rp_tree_t		*unsolved_sentinel = NULL;
11929e86db79SHyon Kim 	int			printPort = 0;
11939e86db79SHyon Kim 	int			numberOfEXP = 0;
11949e86db79SHyon Kim 	int			unsolved_inserted = 0;
11959e86db79SHyon Kim 	int			unsolved_left = 0;
11969e86db79SHyon Kim 	int			disco_port_fail = 0;
11979e86db79SHyon Kim 	boolean_t		firstPrinted = B_FALSE;
11989e86db79SHyon Kim 
1199*b172429eSMarco van Wieringen 	(void) memset(&attr, 0, sizeof (attr));
1200*b172429eSMarco van Wieringen 	(void) memset(&sasport, 0, sizeof (sasport));
12019e86db79SHyon Kim 	attr.PortSpecificAttribute.SASPort = &sasport;
12029e86db79SHyon Kim 
12039e86db79SHyon Kim 	/*
12049e86db79SHyon Kim 	 * Retrive all expander device from this hba port first.
12059e86db79SHyon Kim 	 */
12069e86db79SHyon Kim 	if ((numberOfRP = port->PortSpecificAttribute.SASPort->
12079e86db79SHyon Kim 	    NumberofDiscoveredPorts) == 0) {
12089e86db79SHyon Kim 		/* no remote port. just return 0. */
12099e86db79SHyon Kim 		return (ret);
12109e86db79SHyon Kim 	}
12119e86db79SHyon Kim 
12129e86db79SHyon Kim 	for (i = 0; i < numberOfRP; i++) {
12139e86db79SHyon Kim 		rpnode = calloc(1, sizeof (rp_tree_t));
12149e86db79SHyon Kim 		rpnode->portattr.PortSpecificAttribute.SASPort =
12159e86db79SHyon Kim 		    &rpnode->sasattr;
12169e86db79SHyon Kim 		status = SMHBA_GetDiscoveredPortAttributes(handle,
12179e86db79SHyon Kim 		    portIndex, i, &rpnode->portattr);
12189e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
12199e86db79SHyon Kim 			disco_port_fail++;
12209e86db79SHyon Kim 			free(rpnode);
12219e86db79SHyon Kim 			ret++;
12229e86db79SHyon Kim 			continue;
12239e86db79SHyon Kim 		}
12249e86db79SHyon Kim 
12259e86db79SHyon Kim 		if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
12269e86db79SHyon Kim 			numberOfEXP++;
12279e86db79SHyon Kim 		}
12289e86db79SHyon Kim 		/*
12299e86db79SHyon Kim 		 * We will try to insert this expander device and target
12309e86db79SHyon Kim 		 * ports into the topology tree. If we failed, we can chain
12319e86db79SHyon Kim 		 * them together and try again when we have all the
12329e86db79SHyon Kim 		 * discovered port information in hands.
12339e86db79SHyon Kim 		 */
12349e86db79SHyon Kim 		if (rproot == NULL && memcmp(port->
12359e86db79SHyon Kim 		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
12369e86db79SHyon Kim 		    rpnode->sasattr.AttachedSASAddress.wwn,
12379e86db79SHyon Kim 		    sizeof (HBA_WWN)) == 0) {
12389e86db79SHyon Kim 			/*
12399e86db79SHyon Kim 			 * The root node of tree should
12409e86db79SHyon Kim 			 * be set up first.
12419e86db79SHyon Kim 			 */
12429e86db79SHyon Kim 			rproot = rpnode;
12439e86db79SHyon Kim 		} else {
12449e86db79SHyon Kim 			/*
12459e86db79SHyon Kim 			 * If we can not set up the root node of
12469e86db79SHyon Kim 			 * the tree or we failed to insert
12479e86db79SHyon Kim 			 * the disocvered port node, queue it up then.
12489e86db79SHyon Kim 			 */
12499e86db79SHyon Kim 			if (rproot == NULL ||
12509e86db79SHyon Kim 			    sas_rp_tree_insert(&rproot, rpnode) != 0) {
12519e86db79SHyon Kim 				if (unsolved_head == NULL) {
12529e86db79SHyon Kim 					unsolved_head = rpnode;
12539e86db79SHyon Kim 					unsolved_tail = rpnode;
12549e86db79SHyon Kim 				} else {
12559e86db79SHyon Kim 					rpnode->sibling = unsolved_head;
12569e86db79SHyon Kim 					unsolved_head = rpnode;
12579e86db79SHyon Kim 				}
12589e86db79SHyon Kim 			}
12599e86db79SHyon Kim 		}
12609e86db79SHyon Kim 	}
12619e86db79SHyon Kim 
12629e86db79SHyon Kim 	if (disco_port_fail) {
1263*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %d %s %s\n",
12649e86db79SHyon Kim 		    gettext("Error: Failed to get attributes for"),
12659e86db79SHyon Kim 		    disco_port_fail,
12669e86db79SHyon Kim 		    gettext("connected ports of HBA port"),
12679e86db79SHyon Kim 		    port->OSDeviceName);
12689e86db79SHyon Kim 	}
12699e86db79SHyon Kim 
12709e86db79SHyon Kim 	/* no expander found.  No need further processing. */
12719e86db79SHyon Kim 	if (numberOfEXP == 0) {
12729e86db79SHyon Kim 		while (unsolved_head) {
12739e86db79SHyon Kim 			unsolved_tail =
12749e86db79SHyon Kim 			    unsolved_head->sibling;
12759e86db79SHyon Kim 			free(unsolved_head);
12769e86db79SHyon Kim 			unsolved_head = unsolved_tail;
12779e86db79SHyon Kim 		}
12789e86db79SHyon Kim 		if (rproot) sas_rp_tree_free(rproot);
12799e86db79SHyon Kim 		return (ret);
12809e86db79SHyon Kim 	}
12819e86db79SHyon Kim 
12829e86db79SHyon Kim 	/*
12839e86db79SHyon Kim 	 * When we're here, we should already have all information,
12849e86db79SHyon Kim 	 * now we try again to insert them into the topology tree.
12859e86db79SHyon Kim 	 * unsolved_head is the pointer which point to the head of
12869e86db79SHyon Kim 	 * unsolved rpnode linked list.
12879e86db79SHyon Kim 	 * unsolved_tail is the pointer which point to the tail of
12889e86db79SHyon Kim 	 * unsolved rpnode linked list.
12899e86db79SHyon Kim 	 * unsolved_sentinel is for insertion failure detection.
12909e86db79SHyon Kim 	 * When we're trying to insert the rpnodes from unsolved
12919e86db79SHyon Kim 	 * linked list, it may happen that some of the rpnodes can
12929e86db79SHyon Kim 	 * not be inserted no matter how many times we loop through
12939e86db79SHyon Kim 	 * this linked list. So we use unsolved_sentinel to identify
12949e86db79SHyon Kim 	 * the tail of last round of scanning, and unsolved_inserted
12959e86db79SHyon Kim 	 * which is a counter will be used to count how many rpnodes
12969e86db79SHyon Kim 	 * have been inserted from last round, if it is zero, which
12979e86db79SHyon Kim 	 * means that we can not insert rpnodes into rptree any more,
12989e86db79SHyon Kim 	 * and we should stop and deallocate the memory they occupied.
12999e86db79SHyon Kim 	 */
13009e86db79SHyon Kim 	unsolved_sentinel = unsolved_tail;
13019e86db79SHyon Kim 	while (unsolved_head) {
13029e86db79SHyon Kim 		rpnode = unsolved_head;
13039e86db79SHyon Kim 		unsolved_head = unsolved_head->sibling;
13049e86db79SHyon Kim 		if (unsolved_head == NULL)
13059e86db79SHyon Kim 			unsolved_tail = NULL;
13069e86db79SHyon Kim 		rpnode->sibling = NULL;
13079e86db79SHyon Kim 		if (sas_rp_tree_insert(&rproot, rpnode) != 0) {
13089e86db79SHyon Kim 			unsolved_tail->sibling = rpnode;
13099e86db79SHyon Kim 			unsolved_tail = rpnode;
13109e86db79SHyon Kim 			if (rpnode == unsolved_sentinel) {
13119e86db79SHyon Kim 				/*
13129e86db79SHyon Kim 				 * We just scanned one round for the
13139e86db79SHyon Kim 				 * unsolved list. Check to see whether we
13149e86db79SHyon Kim 				 * have nodes inserted, if none, we should
13159e86db79SHyon Kim 				 * break in case of an indefinite loop.
13169e86db79SHyon Kim 				 */
13179e86db79SHyon Kim 				if (unsolved_inserted == 0) {
13189e86db79SHyon Kim 					/*
13199e86db79SHyon Kim 					 * Indicate there is unhandled node.
13209e86db79SHyon Kim 					 * Chain free the whole unsolved
13219e86db79SHyon Kim 					 * list here.
13229e86db79SHyon Kim 					 */
13239e86db79SHyon Kim 					unsolved_left++;
13249e86db79SHyon Kim 					break;
13259e86db79SHyon Kim 				} else {
13269e86db79SHyon Kim 					unsolved_inserted = 0;
13279e86db79SHyon Kim 					unsolved_sentinel = unsolved_tail;
13289e86db79SHyon Kim 				}
13299e86db79SHyon Kim 			}
13309e86db79SHyon Kim 		} else {
13319e86db79SHyon Kim 			/*
13329e86db79SHyon Kim 			 * We just inserted one rpnode, increment the
13339e86db79SHyon Kim 			 * unsolved_inserted counter. We will utilize this
13349e86db79SHyon Kim 			 * counter to detect an indefinite insertion loop.
13359e86db79SHyon Kim 			 */
13369e86db79SHyon Kim 			unsolved_inserted++;
13379e86db79SHyon Kim 		}
13389e86db79SHyon Kim 	}
13399e86db79SHyon Kim 
13409e86db79SHyon Kim 	/* check if there is left out discovered ports. */
13419e86db79SHyon Kim 	if (unsolved_left) {
13429e86db79SHyon Kim 		ret++;
1343*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %s\n",
13449e86db79SHyon Kim 		    gettext("Error: Failed to establish expander topology on"),
13459e86db79SHyon Kim 		    port->OSDeviceName);
1346*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
13479e86db79SHyon Kim 		    gettext("       Folowing port(s) are unresolved."));
13489e86db79SHyon Kim 		while (unsolved_head) {
13499e86db79SHyon Kim 			unsolved_tail =
13509e86db79SHyon Kim 			    unsolved_head->sibling;
1351*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s%016llx ",
13529e86db79SHyon Kim 			    firstPrinted ? "" : "\t",
13539e86db79SHyon Kim 			    wwnConversion(unsolved_head->sasattr.
13549e86db79SHyon Kim 			    LocalSASAddress.wwn));
13559e86db79SHyon Kim 			if (firstPrinted == B_FALSE) firstPrinted = B_TRUE;
13569e86db79SHyon Kim 			free(unsolved_head);
13579e86db79SHyon Kim 			unsolved_head = unsolved_tail;
13589e86db79SHyon Kim 		}
1359*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "\n");
13609e86db79SHyon Kim 		/* still print what we have */
13619e86db79SHyon Kim 		ret += sas_rp_tree_print(handle, adapterName, portIndex,
13629e86db79SHyon Kim 		    port, rproot, input, 2 * TABLEN, &printPort);
13639e86db79SHyon Kim 	} else {
13649e86db79SHyon Kim 		ret += sas_rp_tree_print(handle, adapterName, portIndex,
13659e86db79SHyon Kim 		    port, rproot, input, 2 * TABLEN, &printPort);
13669e86db79SHyon Kim 	}
13679e86db79SHyon Kim 
13689e86db79SHyon Kim 	if (rproot) sas_rp_tree_free(rproot);
13699e86db79SHyon Kim 
13709e86db79SHyon Kim 	return (ret);
13719e86db79SHyon Kim }
13729e86db79SHyon Kim 
13739e86db79SHyon Kim /*
13749e86db79SHyon Kim  * Callback function for target-port subcommand.
13759e86db79SHyon Kim  *
13769e86db79SHyon Kim  * Arguments:
13779e86db79SHyon Kim  *      handle - handle to hba port.
13789e86db79SHyon Kim  *      portIndex - the index of hba port currently being processed.
13799e86db79SHyon Kim  *      port - pointer to hba port attributes.
13809e86db79SHyon Kim  *      attrs - pointer to adapter attributes currently being processed.
13819e86db79SHyon Kim  *	input - contains all the input parameters.
13829e86db79SHyon Kim  *
13839e86db79SHyon Kim  *  Return Value:
13849e86db79SHyon Kim  *	    0		sucessfully processed handle
13859e86db79SHyon Kim  *	    >0		error has occured
13869e86db79SHyon Kim  */
13879e86db79SHyon Kim /*ARGSUSED*/
handleTargetPort(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)13889e86db79SHyon Kim static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
13899e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
13909e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
13919e86db79SHyon Kim {
13929e86db79SHyon Kim 	HBA_STATUS		status;
13939e86db79SHyon Kim 	SMHBA_PORTATTRIBUTES	targetattr;
13949e86db79SHyon Kim 	SMHBA_SAS_PORT		sasattr;
13959e86db79SHyon Kim 	int			i;
13969e86db79SHyon Kim 	int			ret = 0;
13979e86db79SHyon Kim 	int			disco_port_fail = 0;
13989e86db79SHyon Kim 
13999e86db79SHyon Kim 	targetattr.PortSpecificAttribute.SASPort = &sasattr;
14009e86db79SHyon Kim 
14019e86db79SHyon Kim 	for (i = 0; i < port->PortSpecificAttribute.SASPort->
14029e86db79SHyon Kim 	    NumberofDiscoveredPorts; i++) {
14039e86db79SHyon Kim 		status = SMHBA_GetDiscoveredPortAttributes(handle,
14049e86db79SHyon Kim 		    portIndex, i, &targetattr);
14059e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
14069e86db79SHyon Kim 			disco_port_fail++;
14079e86db79SHyon Kim 		} else {
14089e86db79SHyon Kim 			/* skip expander device */
14099e86db79SHyon Kim 			if (targetattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
14109e86db79SHyon Kim 				ret += searchTargetPort(handle, portIndex, port,
14119e86db79SHyon Kim 				    &targetattr, &sasattr, input->pflag);
14129e86db79SHyon Kim 			}
14139e86db79SHyon Kim 		}
14149e86db79SHyon Kim 	}
14159e86db79SHyon Kim 
14169e86db79SHyon Kim 	if (disco_port_fail) {
14179e86db79SHyon Kim 		ret++;
1418*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %d %s %s\n",
14199e86db79SHyon Kim 		    gettext("Error: Failed to get attributes for"),
14209e86db79SHyon Kim 		    disco_port_fail,
14219e86db79SHyon Kim 		    gettext("connected ports of HBA port"),
14229e86db79SHyon Kim 		    port->OSDeviceName);
14239e86db79SHyon Kim 	}
14249e86db79SHyon Kim 	return (ret);
14259e86db79SHyon Kim }
14269e86db79SHyon Kim 
14279e86db79SHyon Kim /*
14289e86db79SHyon Kim  * ****************************************************************************
14299e86db79SHyon Kim  *
14309e86db79SHyon Kim  * compareLUName -
14319e86db79SHyon Kim  * 	compare names directly and also check if disk namees match with
14329e86db79SHyon Kim  *	different slice number or /devices path are speicified and matches.
14339e86db79SHyon Kim  *
14349e86db79SHyon Kim  * cmdArg	- first string to compare
14359e86db79SHyon Kim  * osName	- os name from attributes
14369e86db79SHyon Kim  *
14379e86db79SHyon Kim  * returns 	B_TRUE if the strings match either directly or via devid
14389e86db79SHyon Kim  *		B_FALSE otherwise
14399e86db79SHyon Kim  *
14409e86db79SHyon Kim  * ****************************************************************************
14419e86db79SHyon Kim  */
14429e86db79SHyon Kim static boolean_t
compareLUName(char * cmdArg,char * osName)14439e86db79SHyon Kim compareLUName(char *cmdArg, char *osName)
14449e86db79SHyon Kim {
14459e86db79SHyon Kim 
14469e86db79SHyon Kim 	boolean_t	isSame = B_FALSE;
14479e86db79SHyon Kim 	char		dev1[MAXPATHLEN], dev2[MAXPATHLEN];
14489e86db79SHyon Kim 	char		*ch1, *ch2;
14499e86db79SHyon Kim 
14509e86db79SHyon Kim 	if (strcmp(cmdArg, osName) == 0) {
14519e86db79SHyon Kim 		isSame = B_TRUE;
14529e86db79SHyon Kim 	} else {
14539e86db79SHyon Kim 		/* user input didn't match, try to  match the core of args. */
14549e86db79SHyon Kim 		(void) strlcpy(dev1, cmdArg, MAXPATHLEN);
14559e86db79SHyon Kim 		(void) strlcpy(dev2, osName, MAXPATHLEN);
14569e86db79SHyon Kim 		/* is this /devices path */
14579e86db79SHyon Kim 		if (((ch1 = strrchr(dev1, ',')) != NULL) &&
14589e86db79SHyon Kim 		    ((ch2 = strrchr(dev2, ',')) != NULL)) {
14599e86db79SHyon Kim 			*ch1 = *ch2 = '\0';
14609e86db79SHyon Kim 			if (strcmp(dev1, dev2) == 0) {
14619e86db79SHyon Kim 				isSame = B_TRUE;
14629e86db79SHyon Kim 			}
14639e86db79SHyon Kim 		/* is this a /dev link */
14649e86db79SHyon Kim 		} else if ((strncmp(dev1, "/dev/", 5) == 0) &&
14659e86db79SHyon Kim 		    (strncmp(dev2, "/dev/", 5) == 0)) {
14669e86db79SHyon Kim 			if ((strstr(dev1, "dsk") != NULL) &&
14679e86db79SHyon Kim 			    ((strstr(dev2, "dsk") != NULL))) {
14689e86db79SHyon Kim 				/* if it is disk link */
14699e86db79SHyon Kim 				if (((ch1 = strrchr(dev1, 's')) != NULL) &&
14709e86db79SHyon Kim 				    ((ch2 = strrchr(dev2, 's')) != NULL)) {
14719e86db79SHyon Kim 					*ch1 = *ch2 = '\0';
14729e86db79SHyon Kim 					if (strcmp(dev1, dev2) == 0) {
14739e86db79SHyon Kim 						isSame = B_TRUE;
14749e86db79SHyon Kim 					}
14759e86db79SHyon Kim 				}
14769e86db79SHyon Kim 			} else {
14779e86db79SHyon Kim 				/* other dev links */
14789e86db79SHyon Kim 				if (strcmp(dev1, dev2) == 0) {
14799e86db79SHyon Kim 					isSame = B_TRUE;
14809e86db79SHyon Kim 				}
14819e86db79SHyon Kim 			}
14829e86db79SHyon Kim 		}
14839e86db79SHyon Kim 	} /* compare */
14849e86db79SHyon Kim 
14859e86db79SHyon Kim 	return (isSame);
14869e86db79SHyon Kim }
14879e86db79SHyon Kim 
14889e86db79SHyon Kim /*
14899e86db79SHyon Kim  * Process logical-unit(lu) subcommand.
14909e86db79SHyon Kim  *
14919e86db79SHyon Kim  * Arguments:
14929e86db79SHyon Kim  *      luCount - number of OS device name(s) specified by user.
14939e86db79SHyon Kim  *      luArgv - array of OS device name(s) specified by user.
14949e86db79SHyon Kim  *      options - all the options specified by user.
14959e86db79SHyon Kim  *
14969e86db79SHyon Kim  *  Return Value:
14979e86db79SHyon Kim  *	    0		sucessfully processed handle
14989e86db79SHyon Kim  *	    >0		error has occured
14999e86db79SHyon Kim  */
15009e86db79SHyon Kim int
sas_util_list_logicalunit(int luCount,char ** luArgv,cmdOptions_t * options)15019e86db79SHyon Kim sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
15029e86db79SHyon Kim {
15039e86db79SHyon Kim 	HBA_STATUS		status;
15049e86db79SHyon Kim 	int			processHBA_flags = 0;
15059e86db79SHyon Kim 	int			lu;
15069e86db79SHyon Kim 	boolean_t		pathFound;
15079e86db79SHyon Kim 	boolean_t		verbose;
15089e86db79SHyon Kim 	inputArg_t		input;
15099e86db79SHyon Kim 	discoveredDevice	*LUListWalk = NULL;
15109e86db79SHyon Kim 	int			err_cnt = 0;
15119e86db79SHyon Kim 
15129e86db79SHyon Kim 	for (; options->optval; options++) {
15139e86db79SHyon Kim 		if (options->optval == 'v') {
15149e86db79SHyon Kim 			processHBA_flags |= PRINT_VERBOSE;
15159e86db79SHyon Kim 		}
15169e86db79SHyon Kim 	}
15179e86db79SHyon Kim 
15189e86db79SHyon Kim 	/* HBA_LoadLibrary() */
15199e86db79SHyon Kim 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
1520*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %s\n",
15219e86db79SHyon Kim 		    gettext("Failed to load SM-HBA libraries."
15229e86db79SHyon Kim 		    "Reason:"), getHBAStatus(status));
15239e86db79SHyon Kim 		err_cnt++;
15249e86db79SHyon Kim 		return (err_cnt);
15259e86db79SHyon Kim 	}
15269e86db79SHyon Kim 
1527*b172429eSMarco van Wieringen 	(void) memset(&input, 0, sizeof (input));
15289e86db79SHyon Kim 	input.pflag = processHBA_flags;
15299e86db79SHyon Kim 	input.wwnCount = luCount;
15309e86db79SHyon Kim 	input.wwn_argv = luArgv;
15319e86db79SHyon Kim 
15329e86db79SHyon Kim 	err_cnt += processHBA(&input, handleLogicalUnit);
15339e86db79SHyon Kim 	verbose = (input.pflag & PRINT_VERBOSE) ? B_TRUE : B_FALSE;
15349e86db79SHyon Kim 
15359e86db79SHyon Kim 	if (luCount == 0) {
15369e86db79SHyon Kim 		/* list all paths */
15379e86db79SHyon Kim 		for (LUListWalk = LUList; LUListWalk != NULL;
15389e86db79SHyon Kim 		    LUListWalk = LUListWalk->next) {
15399e86db79SHyon Kim 			err_cnt += printOSDeviceNameInfo(LUListWalk, verbose);
15409e86db79SHyon Kim 		}
15419e86db79SHyon Kim 	} else {
15429e86db79SHyon Kim 		/*
15439e86db79SHyon Kim 		 * When operands provided, we should set the error code
15449e86db79SHyon Kim 		 * only if there are issues related with the operands.
15459e86db79SHyon Kim 		 */
15469e86db79SHyon Kim 		err_cnt = 0;
15479e86db79SHyon Kim 		/*
15489e86db79SHyon Kim 		 * list any paths not found first
15499e86db79SHyon Kim 		 * this gives the user cleaner output
15509e86db79SHyon Kim 		 */
15519e86db79SHyon Kim 		for (lu = 0; lu < luCount; lu++) {
15529e86db79SHyon Kim 			for (LUListWalk = LUList, pathFound = B_FALSE;
15539e86db79SHyon Kim 			    LUListWalk != NULL;
15549e86db79SHyon Kim 			    LUListWalk = LUListWalk->next) {
15559e86db79SHyon Kim 				if (compareLUName(luArgv[lu],
15569e86db79SHyon Kim 				    LUListWalk->OSDeviceName)) {
15579e86db79SHyon Kim 					pathFound = B_TRUE;
15589e86db79SHyon Kim 					break;
15599e86db79SHyon Kim 				}
15609e86db79SHyon Kim 			}
15619e86db79SHyon Kim 			if (pathFound == B_FALSE) {
1562*b172429eSMarco van Wieringen 				(void) fprintf(stderr,
15639e86db79SHyon Kim 				    "Error: Logical Unit %s Not Found \n",
15649e86db79SHyon Kim 				    luArgv[lu]);
15659e86db79SHyon Kim 				err_cnt++;
15669e86db79SHyon Kim 			}
15679e86db79SHyon Kim 		}
15689e86db79SHyon Kim 		/* list all paths requested in order requested */
15699e86db79SHyon Kim 		for (lu = 0; lu < luCount; lu++) {
15709e86db79SHyon Kim 			for (LUListWalk = LUList; LUListWalk != NULL;
15719e86db79SHyon Kim 			    LUListWalk = LUListWalk->next) {
15729e86db79SHyon Kim 				if (compareLUName(luArgv[lu],
15739e86db79SHyon Kim 				    LUListWalk->OSDeviceName)) {
15749e86db79SHyon Kim 					err_cnt += printOSDeviceNameInfo(
15759e86db79SHyon Kim 					    LUListWalk,
15769e86db79SHyon Kim 					    verbose);
15779e86db79SHyon Kim 				}
15789e86db79SHyon Kim 			}
15799e86db79SHyon Kim 		}
15809e86db79SHyon Kim 	}
15819e86db79SHyon Kim 	(void) HBA_FreeLibrary();
15829e86db79SHyon Kim 	return (err_cnt);
15839e86db79SHyon Kim }
15849e86db79SHyon Kim 
15859e86db79SHyon Kim /*
15869e86db79SHyon Kim  * Callback function for logical-unit(lu) subcommand.
15879e86db79SHyon Kim  *
15889e86db79SHyon Kim  * Arguments:
15899e86db79SHyon Kim  *      handle - handle to hba port.
15909e86db79SHyon Kim  *      portIndex - the index of hba port currently being processed.
15919e86db79SHyon Kim  *      port - pointer to hba port attributes.
15929e86db79SHyon Kim  *      attrs - pointer to adapter attributes currently being processed.
15939e86db79SHyon Kim  *	input - contains all the input parameters.
15949e86db79SHyon Kim  *
15959e86db79SHyon Kim  *  Return Value:
15969e86db79SHyon Kim  *	    0		sucessfully processed handle
15979e86db79SHyon Kim  *	    >0		error has occured
15989e86db79SHyon Kim  */
15999e86db79SHyon Kim /*ARGSUSED*/
handleLogicalUnit(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)16009e86db79SHyon Kim static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
16019e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
16029e86db79SHyon Kim     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
16039e86db79SHyon Kim {
16049e86db79SHyon Kim 	HBA_STATUS		status;
16059e86db79SHyon Kim 	SMHBA_TARGETMAPPING	*map;
16069e86db79SHyon Kim 	HBA_WWN			hbaPortWWN, domainPortWWN;
16079e86db79SHyon Kim 	char			*portName = NULL;
16089e86db79SHyon Kim 	int			numentries;
16099e86db79SHyon Kim 	int			count = 0;
16109e86db79SHyon Kim 	int			ret = 0;
16119e86db79SHyon Kim 
16129e86db79SHyon Kim 	hbaPortWWN = port->PortSpecificAttribute.SASPort->LocalSASAddress;
16139e86db79SHyon Kim 	portName = port->OSDeviceName;
16149e86db79SHyon Kim 
16159e86db79SHyon Kim 	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
16169e86db79SHyon Kim 	switch (status) {
16179e86db79SHyon Kim 		case HBA_STATUS_OK:
16189e86db79SHyon Kim 			break;
16199e86db79SHyon Kim 		case HBA_STATUS_ERROR_NOT_SUPPORTED:
16209e86db79SHyon Kim 			/* don't increase error flag for no phy configuration */
16219e86db79SHyon Kim 			return (ret);
16229e86db79SHyon Kim 		case HBA_STATUS_ERROR:
16239e86db79SHyon Kim 		default:
16249e86db79SHyon Kim 			return (++ret);
16259e86db79SHyon Kim 	}
16269e86db79SHyon Kim 
16279e86db79SHyon Kim 	if ((map = calloc(1, sizeof (*map))) == NULL) {
1628*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
16299e86db79SHyon Kim 		    gettext("No enough memory on heap."));
16309e86db79SHyon Kim 		return (++ret);
16319e86db79SHyon Kim 	}
16329e86db79SHyon Kim 	map->NumberOfEntries = 1;
16339e86db79SHyon Kim 
16349e86db79SHyon Kim 	/*
16359e86db79SHyon Kim 	 * First, we need to get the target mapping data from this hba
16369e86db79SHyon Kim 	 * port.
16379e86db79SHyon Kim 	 */
16389e86db79SHyon Kim 	status = SMHBA_GetTargetMapping(handle,
16399e86db79SHyon Kim 	    hbaPortWWN, domainPortWWN, map);
16409e86db79SHyon Kim 
16419e86db79SHyon Kim 	if (status == HBA_STATUS_ERROR_MORE_DATA) {
16429e86db79SHyon Kim 		numentries = map->NumberOfEntries;
16439e86db79SHyon Kim 		free(map);
16449e86db79SHyon Kim 		map = calloc(1, sizeof (HBA_UINT32) +
16459e86db79SHyon Kim 		    (numentries * sizeof (SMHBA_SCSIENTRY)));
16469e86db79SHyon Kim 		if (map == NULL) {
1647*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n",
16489e86db79SHyon Kim 			    gettext("No enough memory on heap."));
16499e86db79SHyon Kim 			return (++ret);
16509e86db79SHyon Kim 		}
16519e86db79SHyon Kim 		map->NumberOfEntries = numentries;
16529e86db79SHyon Kim 		status = SMHBA_GetTargetMapping(handle,
16539e86db79SHyon Kim 		    hbaPortWWN, domainPortWWN, map);
16549e86db79SHyon Kim 	}
16559e86db79SHyon Kim 
16569e86db79SHyon Kim 	if (status != HBA_STATUS_OK) {
1657*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s %016llx %s %s\n",
16589e86db79SHyon Kim 		    gettext("Error: Failed to get SCSI mapping data for "
16599e86db79SHyon Kim 		    "the HBA port"), wwnConversion(hbaPortWWN.wwn),
16609e86db79SHyon Kim 		    gettext("Reason:"),
16619e86db79SHyon Kim 		    getHBAStatus(status));
16629e86db79SHyon Kim 		free(map);
16639e86db79SHyon Kim 		return (++ret);
16649e86db79SHyon Kim 	}
16659e86db79SHyon Kim 
16669e86db79SHyon Kim 	/*
16679e86db79SHyon Kim 	 * By iterating each entry of the targetmapping data, we will
16689e86db79SHyon Kim 	 * construct a global list of logical unit.
16699e86db79SHyon Kim 	 */
16709e86db79SHyon Kim 	for (count = 0; count < map->NumberOfEntries; count++) {
16719e86db79SHyon Kim 		ret += searchDevice(
16729e86db79SHyon Kim 		    &(map->entry[count]), handle, hbaPortWWN, domainPortWWN,
16739e86db79SHyon Kim 		    portName, input->pflag);
16749e86db79SHyon Kim 	}
16759e86db79SHyon Kim 	free(map);
16769e86db79SHyon Kim 	return (ret);
16779e86db79SHyon Kim }
16789e86db79SHyon Kim 
16799e86db79SHyon Kim /*
16809e86db79SHyon Kim  * Search the matching targetmapping data for given target port and SAM LUN
16819e86db79SHyon Kim  *	and return target mapping data if found.
16829e86db79SHyon Kim  *
16839e86db79SHyon Kim  * Arguments:
16849e86db79SHyon Kim  *      handle - handle to hba port.
16859e86db79SHyon Kim  *      portIndex - hba port index
16869e86db79SHyon Kim  *      port - hba port attributes.
16879e86db79SHyon Kim  *      targetportWWN - target port SAS address.
16889e86db79SHyon Kim  *      domainportWWN - domain port SAS address.
16899e86db79SHyon Kim  *      domainportttr - target port SAS attributes.
16909e86db79SHyon Kim  *      samLUN - samLUN from report LUNs data.
16919e86db79SHyon Kim  *      data - matching target mapping data.
16929e86db79SHyon Kim  *
16939e86db79SHyon Kim  *  Return Value:
16949e86db79SHyon Kim  *	    0		sucessfully processed handle
16959e86db79SHyon Kim  *	    >0		error has occured
16969e86db79SHyon Kim  */
16979e86db79SHyon Kim static int
searchTargetPortMappingData(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_SAS_PORT * sasattr,struct targetPortConfig * configData)16989e86db79SHyon Kim searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
16999e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
17009e86db79SHyon Kim     struct targetPortConfig *configData)
17019e86db79SHyon Kim {
17029e86db79SHyon Kim 	int			ret = 0;
17039e86db79SHyon Kim 	HBA_STATUS		status;
17049e86db79SHyon Kim 	SMHBA_TARGETMAPPING	*map = NULL;
17059e86db79SHyon Kim 	HBA_WWN			hbaPortWWN, domainPortWWN;
17069e86db79SHyon Kim 	int			numentries, count;
17079e86db79SHyon Kim 	targetPortMappingData_t	*TPMapData;
17089e86db79SHyon Kim 	struct scsi_inquiry	inq;
17099e86db79SHyon Kim 	struct scsi_extended_sense  sense;
17109e86db79SHyon Kim 	HBA_UINT32		responseSize, senseSize = 0;
17119e86db79SHyon Kim 	uchar_t			rawLUNs[DEFAULT_LUN_LENGTH], *lun_string;
17129e86db79SHyon Kim 	HBA_UINT8		scsiStatus;
17139e86db79SHyon Kim 	rep_luns_rsp_t		*lun_resp;
17149e86db79SHyon Kim 	int			lunNum, numberOfLun, lunCount;
17159e86db79SHyon Kim 	uint32_t		lunlength, tmp_lunlength;
17169e86db79SHyon Kim 	uint64_t		sasLUN;
17179e86db79SHyon Kim 	SMHBA_SCSILUN		smhbaLUN;
17189e86db79SHyon Kim 
17199e86db79SHyon Kim 	hbaPortWWN = port->PortSpecificAttribute.SASPort->
17209e86db79SHyon Kim 	    LocalSASAddress;
17219e86db79SHyon Kim 
17229e86db79SHyon Kim 	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
17239e86db79SHyon Kim 	if (status == HBA_STATUS_OK) {
17249e86db79SHyon Kim 		if ((map = calloc(1, sizeof (*map))) == NULL) {
1725*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n",
17269e86db79SHyon Kim 			gettext("No enough memory on heap."));
17279e86db79SHyon Kim 			return (++ret);
17289e86db79SHyon Kim 		}
17299e86db79SHyon Kim 		map->NumberOfEntries = 1;
17309e86db79SHyon Kim 
17319e86db79SHyon Kim 		status = SMHBA_GetTargetMapping(handle, hbaPortWWN,
17329e86db79SHyon Kim 		    domainPortWWN, map);
17339e86db79SHyon Kim 
17349e86db79SHyon Kim 		if (status == HBA_STATUS_ERROR_MORE_DATA) {
17359e86db79SHyon Kim 			numentries = map->NumberOfEntries;
17369e86db79SHyon Kim 			free(map);
17379e86db79SHyon Kim 			map = calloc(1, sizeof (HBA_UINT32) +
17389e86db79SHyon Kim 			    (numentries * sizeof (SMHBA_SCSIENTRY)));
17399e86db79SHyon Kim 			if (map == NULL) {
1740*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s\n",
17419e86db79SHyon Kim 				    gettext("No enough memory on heap."));
17429e86db79SHyon Kim 				return (++ret);
17439e86db79SHyon Kim 			}
17449e86db79SHyon Kim 			map->NumberOfEntries = numentries;
17459e86db79SHyon Kim 			status = SMHBA_GetTargetMapping(handle,
17469e86db79SHyon Kim 			    hbaPortWWN, domainPortWWN, map);
17479e86db79SHyon Kim 		}
17489e86db79SHyon Kim 
17499e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
17509e86db79SHyon Kim 			/* continue to build mapping data based SCSI info */
17519e86db79SHyon Kim 			ret++;
17529e86db79SHyon Kim 			free(map);
17539e86db79SHyon Kim 			map = NULL;
17549e86db79SHyon Kim 		}
17559e86db79SHyon Kim 	}
17569e86db79SHyon Kim 
17579e86db79SHyon Kim 	/*
17589e86db79SHyon Kim 	 * Get report lun data.
17599e86db79SHyon Kim 	 */
17609e86db79SHyon Kim 	responseSize = DEFAULT_LUN_LENGTH;
17619e86db79SHyon Kim 	senseSize = sizeof (struct scsi_extended_sense);
17629e86db79SHyon Kim 	(void) memset(&sense, 0, sizeof (sense));
17639e86db79SHyon Kim 	status = SMHBA_ScsiReportLUNs(
17649e86db79SHyon Kim 	    handle,
17659e86db79SHyon Kim 	    hbaPortWWN,
17669e86db79SHyon Kim 	    sasattr->LocalSASAddress,
17679e86db79SHyon Kim 	    domainPortWWN,
17689e86db79SHyon Kim 	    (void *)rawLUNs,
17699e86db79SHyon Kim 	    &responseSize,
17709e86db79SHyon Kim 	    &scsiStatus,
17719e86db79SHyon Kim 	    (void *) &sense, &senseSize);
17729e86db79SHyon Kim 
17739e86db79SHyon Kim 	/*
17749e86db79SHyon Kim 	 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
17759e86db79SHyon Kim 	 * a remote HBA and move on
17769e86db79SHyon Kim 	 */
17779e86db79SHyon Kim 	if (status != HBA_STATUS_OK) {
17789e86db79SHyon Kim 		configData->reportLUNsFailed = B_TRUE;
17799e86db79SHyon Kim 		if (map != NULL) {
17809e86db79SHyon Kim 			/*
17819e86db79SHyon Kim 			 * Let's search mapping data and indicate that Report
17829e86db79SHyon Kim 			 * LUNs failed.
17839e86db79SHyon Kim 			 */
17849e86db79SHyon Kim 			for (count = 0; count < map->NumberOfEntries; count++) {
17859e86db79SHyon Kim 				if (memcmp(map->entry[count].PortLun.
17869e86db79SHyon Kim 				    PortWWN.wwn, sasattr->LocalSASAddress.wwn,
17879e86db79SHyon Kim 				    sizeof (HBA_WWN)) == 0) {
17889e86db79SHyon Kim 					/* allocate mapping data for each LUN */
17899e86db79SHyon Kim 					TPMapData = calloc(1,
17909e86db79SHyon Kim 					    sizeof (targetPortMappingData_t));
17919e86db79SHyon Kim 					if (TPMapData == NULL) {
1792*b172429eSMarco van Wieringen 						(void) fprintf(stderr, "%s\n",
17939e86db79SHyon Kim 						    gettext("No enough "
17949e86db79SHyon Kim 						    "memory."));
17959e86db79SHyon Kim 						free(map);
17969e86db79SHyon Kim 						return (++ret);
17979e86db79SHyon Kim 					}
17989e86db79SHyon Kim 					TPMapData->mappingExist = B_TRUE;
17999e86db79SHyon Kim 					TPMapData->osLUN =
18009e86db79SHyon Kim 					    map->entry[count].ScsiId.ScsiOSLun;
18019e86db79SHyon Kim 					(void) strlcpy(TPMapData->osDeviceName,
18029e86db79SHyon Kim 					    map->entry[count].ScsiId.
18039e86db79SHyon Kim 					    OSDeviceName,
18049e86db79SHyon Kim 					    sizeof (TPMapData->osDeviceName));
18059e86db79SHyon Kim 					TPMapData->inq_vid[0] = '\0';
18069e86db79SHyon Kim 					TPMapData->inq_pid[0] = '\0';
18079e86db79SHyon Kim 					TPMapData->inq_dtype = DTYPE_UNKNOWN;
18089e86db79SHyon Kim 					if (configData->map == NULL) {
18099e86db79SHyon Kim 						configData->map = TPMapData;
18109e86db79SHyon Kim 					} else {
18119e86db79SHyon Kim 						TPMapData->next =
18129e86db79SHyon Kim 						    configData->map->next;
18139e86db79SHyon Kim 						configData->map = TPMapData;
18149e86db79SHyon Kim 					}
18159e86db79SHyon Kim 				}
18169e86db79SHyon Kim 			}
18179e86db79SHyon Kim 		}
18189e86db79SHyon Kim 		(void) free(map);
18199e86db79SHyon Kim 		return (++ret);
18209e86db79SHyon Kim 	}
18219e86db79SHyon Kim 	lun_resp = (rep_luns_rsp_t *)((void *)rawLUNs);
18229e86db79SHyon Kim 	(void) memcpy(&tmp_lunlength, &(lun_resp->length),
18239e86db79SHyon Kim 	    sizeof (tmp_lunlength));
18249e86db79SHyon Kim 	lunlength = ntohl(tmp_lunlength);
18259e86db79SHyon Kim 	(void) memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
18269e86db79SHyon Kim 	for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
18279e86db79SHyon Kim 		/* allocate mapping data for each LUN */
18289e86db79SHyon Kim 		TPMapData = calloc(1,
18299e86db79SHyon Kim 		    sizeof (targetPortMappingData_t));
18309e86db79SHyon Kim 		if (TPMapData == NULL) {
1831*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n",
18329e86db79SHyon Kim 			    gettext("No enough memory."));
18339e86db79SHyon Kim 			free(map);
18349e86db79SHyon Kim 			return (++ret);
18359e86db79SHyon Kim 		}
18369e86db79SHyon Kim 
18379e86db79SHyon Kim 		(void) memcpy(&TPMapData->reportLUN, lun_resp->
18389e86db79SHyon Kim 		    lun[lunCount].val, sizeof (SMHBA_SCSILUN));
18399e86db79SHyon Kim 
18409e86db79SHyon Kim 		/*
18419e86db79SHyon Kim 		 * now issue standard inquiry to get Vendor
18429e86db79SHyon Kim 		 * and product information
18439e86db79SHyon Kim 		 */
18449e86db79SHyon Kim 		responseSize = sizeof (struct scsi_inquiry);
18459e86db79SHyon Kim 		senseSize = sizeof (struct scsi_extended_sense);
18469e86db79SHyon Kim 		(void) memset(&inq, 0, sizeof (struct scsi_inquiry));
18479e86db79SHyon Kim 		(void) memset(&sense, 0, sizeof (sense));
18489e86db79SHyon Kim 		sasLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
18499e86db79SHyon Kim 		(void) memcpy(&smhbaLUN, &sasLUN, sizeof (SMHBA_SCSILUN));
18509e86db79SHyon Kim 		status = SMHBA_ScsiInquiry(
18519e86db79SHyon Kim 		    handle,
18529e86db79SHyon Kim 		    hbaPortWWN,
18539e86db79SHyon Kim 		    sasattr->LocalSASAddress,
18549e86db79SHyon Kim 		    domainPortWWN,
18559e86db79SHyon Kim 		    smhbaLUN,
18569e86db79SHyon Kim 		    0,
18579e86db79SHyon Kim 		    0,
18589e86db79SHyon Kim 		    (void *) &inq, &responseSize,
18599e86db79SHyon Kim 		    &scsiStatus,
18609e86db79SHyon Kim 		    (void *) &sense, &senseSize);
18619e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
18629e86db79SHyon Kim 			TPMapData->inq_vid[0] = '\0';
18639e86db79SHyon Kim 			TPMapData->inq_pid[0] = '\0';
18649e86db79SHyon Kim 			TPMapData->inq_dtype = DTYPE_UNKNOWN;
18659e86db79SHyon Kim 			/* indicate that inquiry for this lun is failed */
18669e86db79SHyon Kim 			TPMapData->inquiryFailed = B_TRUE;
18679e86db79SHyon Kim 		} else {
1868*b172429eSMarco van Wieringen 			(void) memcpy(TPMapData->inq_vid, inq.inq_vid,
18699e86db79SHyon Kim 			    sizeof (TPMapData->inq_vid));
1870*b172429eSMarco van Wieringen 			(void) memcpy(TPMapData->inq_pid, inq.inq_pid,
18719e86db79SHyon Kim 			    sizeof (TPMapData->inq_pid));
18729e86db79SHyon Kim 			TPMapData->inq_dtype = inq.inq_dtype;
18739e86db79SHyon Kim 		}
18749e86db79SHyon Kim 
18759e86db79SHyon Kim 		if (map != NULL) {
18769e86db79SHyon Kim 			for (count = 0; count < map->NumberOfEntries; count++) {
18779e86db79SHyon Kim 				if ((memcmp(map->entry[count].PortLun.
18789e86db79SHyon Kim 				    PortWWN.wwn, sasattr->LocalSASAddress.wwn,
18799e86db79SHyon Kim 				    sizeof (HBA_WWN)) == 0) &&
18809e86db79SHyon Kim 				    (memcmp(&(map->entry[count].PortLun.
18819e86db79SHyon Kim 				    TargetLun), &smhbaLUN,
18829e86db79SHyon Kim 				    sizeof (SMHBA_SCSILUN))
18839e86db79SHyon Kim 				    == 0)) {
18849e86db79SHyon Kim 					TPMapData->mappingExist = B_TRUE;
18859e86db79SHyon Kim 					TPMapData->osLUN =
18869e86db79SHyon Kim 					    map->entry[count].ScsiId.ScsiOSLun;
18879e86db79SHyon Kim 					(void) strlcpy(TPMapData->osDeviceName,
18889e86db79SHyon Kim 					    map->entry[count].ScsiId.
18899e86db79SHyon Kim 					    OSDeviceName,
18909e86db79SHyon Kim 					    sizeof (TPMapData->osDeviceName));
18919e86db79SHyon Kim 					break;
18929e86db79SHyon Kim 				}
18939e86db79SHyon Kim 			}
18949e86db79SHyon Kim 			if (count == map->NumberOfEntries) {
18959e86db79SHyon Kim 				TPMapData->osDeviceName[0] = '\0';
18969e86db79SHyon Kim 				lun_string = lun_resp->lun[lunCount].val;
18979e86db79SHyon Kim 				lunNum = ((lun_string[0] & 0x3F) << 8) |
18989e86db79SHyon Kim 				    lun_string[1];
18999e86db79SHyon Kim 				TPMapData->osLUN = lunNum;
19009e86db79SHyon Kim 			}
19019e86db79SHyon Kim 		} else {
19029e86db79SHyon Kim 		/* Not able to get any target mapping information */
19039e86db79SHyon Kim 			TPMapData->osDeviceName[0] = '\0';
19049e86db79SHyon Kim 			lun_string = lun_resp->lun[lunCount].val;
19059e86db79SHyon Kim 			lunNum = ((lun_string[0] & 0x3F) << 8) |
19069e86db79SHyon Kim 			    lun_string[1];
19079e86db79SHyon Kim 			TPMapData->osLUN = lunNum;
19089e86db79SHyon Kim 		}
19099e86db79SHyon Kim 
19109e86db79SHyon Kim 		if (configData->map == NULL) {
19119e86db79SHyon Kim 			configData->map = TPMapData;
19129e86db79SHyon Kim 		} else {
19139e86db79SHyon Kim 			TPMapData->next = configData->map->next;
19149e86db79SHyon Kim 			configData->map = TPMapData;
19159e86db79SHyon Kim 		}
19169e86db79SHyon Kim 	}
19179e86db79SHyon Kim 	free(map);
19189e86db79SHyon Kim 	return (ret);
19199e86db79SHyon Kim }
19209e86db79SHyon Kim 
19219e86db79SHyon Kim /*
19229e86db79SHyon Kim  * Search the discovered LUs and construct the global LU list.
19239e86db79SHyon Kim  *
19249e86db79SHyon Kim  * Arguments:
19259e86db79SHyon Kim  *      handle - handle to hba port.
19269e86db79SHyon Kim  *      portIndex - hba port index
19279e86db79SHyon Kim  *      port - hba port attributes.
19289e86db79SHyon Kim  *      targetattr - target port attributes.
19299e86db79SHyon Kim  *      sasattr - target port SAS attributes.
19309e86db79SHyon Kim  *      pflag - options the user specified.
19319e86db79SHyon Kim  *
19329e86db79SHyon Kim  *  Return Value:
19339e86db79SHyon Kim  *	    0		sucessfully processed handle
19349e86db79SHyon Kim  *	    >0		error has occured
19359e86db79SHyon Kim  */
19369e86db79SHyon Kim static int
searchTargetPort(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_PORTATTRIBUTES * targetattr,SMHBA_SAS_PORT * sasattr,int pflag)19379e86db79SHyon Kim searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
19389e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
19399e86db79SHyon Kim     SMHBA_SAS_PORT *sasattr, int pflag)
19409e86db79SHyon Kim {
19419e86db79SHyon Kim 	int			ret = 0;
19429e86db79SHyon Kim 	HBA_WWN			expander;
19439e86db79SHyon Kim 	HBA_WWN			domainPortWWN;
19449e86db79SHyon Kim 	targetPortList_t 	*discoveredTP, *newTP;
19459e86db79SHyon Kim 	targetPortConfig_t	*TPConfig, *newConfig, *prevConfig;
19469e86db79SHyon Kim 	boolean_t		foundTP = B_FALSE;
19479e86db79SHyon Kim 	boolean_t		foundConfig = B_FALSE;
19489e86db79SHyon Kim 	int			status;
19499e86db79SHyon Kim 	SMHBA_PORTATTRIBUTES	tgtattr;
19509e86db79SHyon Kim 	SMHBA_SAS_PORT		tgtsasport;
19519e86db79SHyon Kim 	int			expanderValid = 0;
19529e86db79SHyon Kim 
19539e86db79SHyon Kim 	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
19549e86db79SHyon Kim 	switch (status) {
19559e86db79SHyon Kim 		case HBA_STATUS_OK:
19569e86db79SHyon Kim 			break;
19579e86db79SHyon Kim 		case HBA_STATUS_ERROR_NOT_SUPPORTED:
19589e86db79SHyon Kim 			/* don't increase error flag for no phy configuration */
19599e86db79SHyon Kim 			return (ret);
19609e86db79SHyon Kim 		case HBA_STATUS_ERROR:
19619e86db79SHyon Kim 		default:
19629e86db79SHyon Kim 			return (++ret);
19639e86db79SHyon Kim 	}
19649e86db79SHyon Kim 
19659e86db79SHyon Kim 	/*
19669e86db79SHyon Kim 	 * First, we will iterate the already constructed target port
19679e86db79SHyon Kim 	 * list to see whether there is a target port already exist with
19689e86db79SHyon Kim 	 * matching target port SAS address.
19699e86db79SHyon Kim 	 */
19709e86db79SHyon Kim 	for (discoveredTP = gTargetPortList; discoveredTP != NULL;
19719e86db79SHyon Kim 	    discoveredTP = discoveredTP->next) {
19729e86db79SHyon Kim 		if (memcmp((void *)sasattr->LocalSASAddress.wwn,
19739e86db79SHyon Kim 		    (void *)discoveredTP->sasattr.LocalSASAddress.wwn,
19749e86db79SHyon Kim 		    sizeof (HBA_WWN)) == 0) {
19759e86db79SHyon Kim 			/*
19769e86db79SHyon Kim 			 * if the target port exist and
19779e86db79SHyon Kim 			 * verbose is not set, just return
19789e86db79SHyon Kim 			 */
19799e86db79SHyon Kim 			if (((pflag & PRINT_VERBOSE) == 0) &&
19809e86db79SHyon Kim 			    ((pflag & PRINT_TARGET_SCSI) == 0)) {
19819e86db79SHyon Kim 				return (ret);
19829e86db79SHyon Kim 			}
19839e86db79SHyon Kim 			foundTP = B_TRUE;
19849e86db79SHyon Kim 			break;
19859e86db79SHyon Kim 		}
19869e86db79SHyon Kim 	}
19879e86db79SHyon Kim 
19889e86db79SHyon Kim 	if (foundTP == B_TRUE) {
19899e86db79SHyon Kim 		/*
19909e86db79SHyon Kim 		 * If there is a target port already exist, we should
19919e86db79SHyon Kim 		 * add more information on the target port to construct the
19929e86db79SHyon Kim 		 * whole topology.
19939e86db79SHyon Kim 		 * Here we will check whether the current hba port name
19949e86db79SHyon Kim 		 * has already been added.
19959e86db79SHyon Kim 		 */
19969e86db79SHyon Kim 		/* first get the expander SAS address compare */
19979e86db79SHyon Kim 		if (memcmp((void *)port->PortSpecificAttribute.SASPort->
19989e86db79SHyon Kim 		    LocalSASAddress.wwn, (void *)sasattr->
19999e86db79SHyon Kim 		    AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
20009e86db79SHyon Kim 			/* NO expander */
20019e86db79SHyon Kim 			(void) memset((void *)expander.wwn, 0,
20029e86db79SHyon Kim 			    sizeof (HBA_WWN));
20039e86db79SHyon Kim 			expanderValid = 1;
20049e86db79SHyon Kim 		} else {
20059e86db79SHyon Kim 			if (wwnConversion(sasattr->AttachedSASAddress.wwn)
20069e86db79SHyon Kim 			    != 0) {
20079e86db79SHyon Kim 				/* expander exist.  We should verify it.  */
20089e86db79SHyon Kim 				(void) memcpy((void *)expander.wwn,
20099e86db79SHyon Kim 				    (void *)sasattr->AttachedSASAddress.wwn,
20109e86db79SHyon Kim 				    sizeof (HBA_WWN));
20119e86db79SHyon Kim 
2012*b172429eSMarco van Wieringen 				(void) memset(&tgtattr, 0, sizeof (tgtattr));
2013*b172429eSMarco van Wieringen 				(void) memset(&tgtsasport, 0,
20149e86db79SHyon Kim 				    sizeof (tgtsasport));
20159e86db79SHyon Kim 				tgtattr.PortSpecificAttribute.SASPort
20169e86db79SHyon Kim 				    = &tgtsasport;
20179e86db79SHyon Kim 				status = SMHBA_GetPortAttributesByWWN(handle,
20189e86db79SHyon Kim 				    sasattr->AttachedSASAddress, domainPortWWN,
20199e86db79SHyon Kim 				    &tgtattr);
20209e86db79SHyon Kim 				if (status == HBA_STATUS_OK && tgtattr.PortType
20219e86db79SHyon Kim 				    == HBA_PORTTYPE_SASEXPANDER) {
20229e86db79SHyon Kim 					expanderValid = 1;
20239e86db79SHyon Kim 				}
20249e86db79SHyon Kim 			}
20259e86db79SHyon Kim 		}
20269e86db79SHyon Kim 
20279e86db79SHyon Kim 		for (TPConfig = discoveredTP->configEntry,
20289e86db79SHyon Kim 		    foundConfig = B_FALSE; TPConfig != NULL;
20299e86db79SHyon Kim 		    TPConfig = TPConfig->next) {
20309e86db79SHyon Kim 			if ((strcmp(TPConfig->hbaPortName,
20319e86db79SHyon Kim 			    port->OSDeviceName) == 0) &&
20329e86db79SHyon Kim 			    (memcmp((void *)expander.wwn, (void *)TPConfig->
20339e86db79SHyon Kim 			    expanderSASAddr.wwn,
20349e86db79SHyon Kim 			    sizeof (HBA_WWN)) == 0)) {
20359e86db79SHyon Kim 				foundConfig = B_TRUE;
20369e86db79SHyon Kim 				break;
20379e86db79SHyon Kim 			}
20389e86db79SHyon Kim 		}
20399e86db79SHyon Kim 
20409e86db79SHyon Kim 		/*
20419e86db79SHyon Kim 		 * If we get here, it means that it is a new hba port/exapnder
20429e86db79SHyon Kim 		 * sas address for this discovered target port.
20439e86db79SHyon Kim 		 */
20449e86db79SHyon Kim 		if (foundConfig == B_FALSE) {
20459e86db79SHyon Kim 			newConfig = (targetPortConfig_t *)calloc(1,
20469e86db79SHyon Kim 			    sizeof (targetPortConfig_t));
20479e86db79SHyon Kim 			if (newConfig == NULL) {
2048*b172429eSMarco van Wieringen 				(void) fprintf(stderr,
20499e86db79SHyon Kim 				    "%s\n", strerror(errno));
20509e86db79SHyon Kim 				return (++ret);
20519e86db79SHyon Kim 			}
20529e86db79SHyon Kim 
20539e86db79SHyon Kim 			(void) strlcpy(newConfig->hbaPortName, port->
20549e86db79SHyon Kim 			    OSDeviceName, sizeof (newConfig->hbaPortName));
20559e86db79SHyon Kim 			(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
20569e86db79SHyon Kim 			    (void *)expander.wwn, sizeof (HBA_WWN));
20579e86db79SHyon Kim 			newConfig->expanderValid = expanderValid;
20589e86db79SHyon Kim 			if (discoveredTP->configEntry == NULL) {
20599e86db79SHyon Kim 				discoveredTP->configEntry = newConfig;
20609e86db79SHyon Kim 			} else {
20619e86db79SHyon Kim 				TPConfig = discoveredTP->configEntry;
20629e86db79SHyon Kim 				prevConfig = TPConfig;
20639e86db79SHyon Kim 				while (TPConfig != NULL &&
20649e86db79SHyon Kim 				    sas_name_comp(newConfig->hbaPortName,
20659e86db79SHyon Kim 				    TPConfig->hbaPortName) > 0) {
20669e86db79SHyon Kim 					prevConfig = TPConfig;
20679e86db79SHyon Kim 					TPConfig = TPConfig->next;
20689e86db79SHyon Kim 				}
20699e86db79SHyon Kim 				if (TPConfig == prevConfig) {
20709e86db79SHyon Kim 					/* Should be inserted in the head. */
20719e86db79SHyon Kim 					newConfig->next = TPConfig;
20729e86db79SHyon Kim 					discoveredTP->configEntry = newConfig;
20739e86db79SHyon Kim 				} else {
20749e86db79SHyon Kim 					newConfig->next = TPConfig;
20759e86db79SHyon Kim 					prevConfig->next = newConfig;
20769e86db79SHyon Kim 				}
20779e86db79SHyon Kim 			}
20789e86db79SHyon Kim 			/* if scsi option is not set return */
20799e86db79SHyon Kim 			if ((pflag & PRINT_TARGET_SCSI) == 0) {
20809e86db79SHyon Kim 				return (0);
20819e86db79SHyon Kim 			} else {
20829e86db79SHyon Kim 				return (searchTargetPortMappingData(
20839e86db79SHyon Kim 				    handle, portIndex, port,
20849e86db79SHyon Kim 				    sasattr, newConfig));
20859e86db79SHyon Kim 			}
20869e86db79SHyon Kim 		}
20879e86db79SHyon Kim 	} else {
20889e86db79SHyon Kim 		/*
20899e86db79SHyon Kim 		 * Here we got a new target port which has not ever exist
20909e86db79SHyon Kim 		 * in our global target port list. So add it to the list.
20919e86db79SHyon Kim 		 * list.
20929e86db79SHyon Kim 		 */
20939e86db79SHyon Kim 		newTP = (targetPortList_t *)calloc(1,
20949e86db79SHyon Kim 		    sizeof (targetPortList_t));
20959e86db79SHyon Kim 
20969e86db79SHyon Kim 		if (newTP == NULL) {
2097*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n", strerror(errno));
20989e86db79SHyon Kim 			return (++ret);
20999e86db79SHyon Kim 		}
21009e86db79SHyon Kim 
21019e86db79SHyon Kim 		(void) memcpy((void *)&newTP->targetattr, (void *)targetattr,
21029e86db79SHyon Kim 		    sizeof (SMHBA_PORTATTRIBUTES));
21039e86db79SHyon Kim 		(void) memcpy((void *)&newTP->sasattr, (void *)sasattr,
21049e86db79SHyon Kim 		    sizeof (SMHBA_SAS_PORT));
21059e86db79SHyon Kim 
21069e86db79SHyon Kim 		newConfig = (targetPortConfig_t *)calloc(1,
21079e86db79SHyon Kim 		    sizeof (targetPortConfig_t));
21089e86db79SHyon Kim 
21099e86db79SHyon Kim 		if (newConfig == NULL) {
2110*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n", strerror(errno));
21119e86db79SHyon Kim 			free(newTP);
21129e86db79SHyon Kim 			return (++ret);
21139e86db79SHyon Kim 		}
21149e86db79SHyon Kim 
21159e86db79SHyon Kim 		(void) strlcpy(newConfig->hbaPortName, port->OSDeviceName,
21169e86db79SHyon Kim 		    sizeof (newConfig->hbaPortName));
21179e86db79SHyon Kim 		if (memcmp((void *)port->PortSpecificAttribute.SASPort->
21189e86db79SHyon Kim 		    LocalSASAddress.wwn, (void *)sasattr->
21199e86db79SHyon Kim 		    AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
21209e86db79SHyon Kim 			/* NO expander */
21219e86db79SHyon Kim 			(void) memset((void *)newConfig->expanderSASAddr.wwn,
21229e86db79SHyon Kim 			    0, sizeof (HBA_WWN));
21239e86db79SHyon Kim 		} else {
21249e86db79SHyon Kim 			/* expander exist.  We should verify it. */
21259e86db79SHyon Kim 			(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
21269e86db79SHyon Kim 			    (void *)sasattr->AttachedSASAddress.wwn,
21279e86db79SHyon Kim 			    sizeof (HBA_WWN));
21289e86db79SHyon Kim 
2129*b172429eSMarco van Wieringen 			(void) memset(&tgtattr, 0, sizeof (tgtattr));
2130*b172429eSMarco van Wieringen 			(void) memset(&tgtsasport, 0, sizeof (tgtsasport));
21319e86db79SHyon Kim 			tgtattr.PortSpecificAttribute.SASPort = &tgtsasport;
21329e86db79SHyon Kim 			status = SMHBA_GetPortAttributesByWWN(handle,
21339e86db79SHyon Kim 			    sasattr->AttachedSASAddress, domainPortWWN,
21349e86db79SHyon Kim 			    &tgtattr);
21359e86db79SHyon Kim 			if (status == HBA_STATUS_OK && tgtattr.PortType ==
21369e86db79SHyon Kim 			    HBA_PORTTYPE_SASEXPANDER) {
21379e86db79SHyon Kim 				expanderValid = 1;
21389e86db79SHyon Kim 			}
21399e86db79SHyon Kim 			newConfig->expanderValid = expanderValid;
21409e86db79SHyon Kim 		}
21419e86db79SHyon Kim 
21429e86db79SHyon Kim 		newTP->configEntry = newConfig;
21439e86db79SHyon Kim 
21449e86db79SHyon Kim 		newTP->next = gTargetPortList; /* insert at head */
21459e86db79SHyon Kim 		gTargetPortList = newTP; /* set new head */
21469e86db79SHyon Kim 
21479e86db79SHyon Kim 		/* if scsi option is not set return */
21489e86db79SHyon Kim 		if ((pflag & PRINT_TARGET_SCSI) == 0) {
21499e86db79SHyon Kim 			return (0);
21509e86db79SHyon Kim 		} else {
21519e86db79SHyon Kim 			return (searchTargetPortMappingData(
21529e86db79SHyon Kim 			    handle, portIndex, port, sasattr, newConfig));
21539e86db79SHyon Kim 		}
21549e86db79SHyon Kim 	}
21559e86db79SHyon Kim 	return (ret);
21569e86db79SHyon Kim }
21579e86db79SHyon Kim 
21589e86db79SHyon Kim /*
21599e86db79SHyon Kim  * Search the discovered LUs and construct the global LU list.
21609e86db79SHyon Kim  *
21619e86db79SHyon Kim  * Arguments:
21629e86db79SHyon Kim  *      entryP - one of the target mapping data.
21639e86db79SHyon Kim  *      handle - handle to hba port.
21649e86db79SHyon Kim  *      hbaPortWWN - hba port sas address.
21659e86db79SHyon Kim  *      domainPortWWN - domain port WWN for this sas domain.
21669e86db79SHyon Kim  *      portName - HBA port OS Device Name.
21679e86db79SHyon Kim  *      pflag - options the user specified.
21689e86db79SHyon Kim  *
21699e86db79SHyon Kim  *  Return Value:
21709e86db79SHyon Kim  *	    0		sucessfully processed handle
21719e86db79SHyon Kim  *	    >0		error has occured
21729e86db79SHyon Kim  */
21739e86db79SHyon Kim static int
searchDevice(PSMHBA_SCSIENTRY entryP,HBA_HANDLE handle,HBA_WWN hbaPortWWN,HBA_WWN domainPortWWN,char * portName,int pflag)21749e86db79SHyon Kim searchDevice(PSMHBA_SCSIENTRY entryP,
21759e86db79SHyon Kim     HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN domainPortWWN,
21769e86db79SHyon Kim     char *portName, int pflag)
21779e86db79SHyon Kim {
21789e86db79SHyon Kim 	HBA_STATUS		status;
21799e86db79SHyon Kim 	int			ret = 0;
21809e86db79SHyon Kim 	discoveredDevice 	*discoveredLU, *newDevice;
21819e86db79SHyon Kim 	portList		*portElem, *newPort, *prevElem;
21829e86db79SHyon Kim 	tgtPortWWNList 		*newTgtWWN, *TgtWWNList;
21839e86db79SHyon Kim 	boolean_t		foundDevice = B_FALSE;
21849e86db79SHyon Kim 	boolean_t		foundPort = B_FALSE;
21859e86db79SHyon Kim 	struct scsi_inquiry	inq;
21869e86db79SHyon Kim 	HBA_UINT32		responseSize, senseSize = 0;
21879e86db79SHyon Kim 	HBA_UINT8		inq_status;
21889e86db79SHyon Kim 	SMHBA_SCSILUN		smhbaLUN;
21899e86db79SHyon Kim 	struct scsi_extended_sense sense;
21909e86db79SHyon Kim 
21919e86db79SHyon Kim 	/* if OSDeviceName is not set, we don't need to search */
21929e86db79SHyon Kim 	if (entryP->ScsiId.OSDeviceName[0] == '\0') {
21939e86db79SHyon Kim 		return (ret);
21949e86db79SHyon Kim 	}
21959e86db79SHyon Kim 
21969e86db79SHyon Kim 	/*
21979e86db79SHyon Kim 	 * First, we will iterate the already constructed discovered LU
21989e86db79SHyon Kim 	 * list to see whether there is a LU already exist with the same OS
21999e86db79SHyon Kim 	 * device name as current target mapping data entry.
22009e86db79SHyon Kim 	 */
22019e86db79SHyon Kim 	for (discoveredLU = LUList; discoveredLU != NULL;
22029e86db79SHyon Kim 	    discoveredLU = discoveredLU->next) {
22039e86db79SHyon Kim 		if (strcmp(entryP->ScsiId.OSDeviceName,
22049e86db79SHyon Kim 		    discoveredLU->OSDeviceName) == 0) {
22059e86db79SHyon Kim 			/*
22069e86db79SHyon Kim 			 * if there is existing OS Device Name and
22079e86db79SHyon Kim 			 * verbose is not set, just return
22089e86db79SHyon Kim 			 */
22099e86db79SHyon Kim 			if ((pflag & PRINT_VERBOSE) == 0) {
22109e86db79SHyon Kim 				return (ret);
22119e86db79SHyon Kim 			}
22129e86db79SHyon Kim 			foundDevice = B_TRUE;
22139e86db79SHyon Kim 			break;
22149e86db79SHyon Kim 		}
22159e86db79SHyon Kim 	}
22169e86db79SHyon Kim 
22179e86db79SHyon Kim 	if (foundDevice == B_TRUE) {
22189e86db79SHyon Kim 		/*
22199e86db79SHyon Kim 		 * If there is a discovered LU already exist, we should
22209e86db79SHyon Kim 		 * add more information on this LU to construct the whole
22219e86db79SHyon Kim 		 * topology.
22229e86db79SHyon Kim 		 * Here we will check whether the current hba port has
22239e86db79SHyon Kim 		 * already been added.
22249e86db79SHyon Kim 		 */
22259e86db79SHyon Kim 		for (portElem = discoveredLU->HBAPortList,
22269e86db79SHyon Kim 		    foundPort = B_FALSE;  portElem != NULL;
22279e86db79SHyon Kim 		    portElem = portElem->next) {
22289e86db79SHyon Kim 			if (strcmp(portElem->portName,
22299e86db79SHyon Kim 			    portName) == 0) {
22309e86db79SHyon Kim 				foundPort = B_TRUE;
22319e86db79SHyon Kim 				break;
22329e86db79SHyon Kim 			}
22339e86db79SHyon Kim 		}
22349e86db79SHyon Kim 
22359e86db79SHyon Kim 		/*
22369e86db79SHyon Kim 		 * If we get here, it means that it is a new hba port name
22379e86db79SHyon Kim 		 * for this discovered LU.
22389e86db79SHyon Kim 		 */
22399e86db79SHyon Kim 		if (foundPort == B_FALSE) {
22409e86db79SHyon Kim 			newPort = (portList *)calloc(1, sizeof (portList));
22419e86db79SHyon Kim 			if (newPort == NULL) {
2242*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s\n", strerror(errno));
22439e86db79SHyon Kim 				return (++ret);
22449e86db79SHyon Kim 			}
22459e86db79SHyon Kim 			(void) strlcpy(newPort->portName, portName,
22469e86db79SHyon Kim 			    sizeof (newPort->portName));
22479e86db79SHyon Kim 
22489e86db79SHyon Kim 			portElem = discoveredLU->HBAPortList;
22499e86db79SHyon Kim 			prevElem = portElem;
22509e86db79SHyon Kim 			while (portElem != NULL &&
22519e86db79SHyon Kim 			    sas_name_comp(newPort->portName, portElem->portName)
22529e86db79SHyon Kim 			    > 0) {
22539e86db79SHyon Kim 				prevElem = portElem;
22549e86db79SHyon Kim 				portElem = portElem->next;
22559e86db79SHyon Kim 			}
22569e86db79SHyon Kim 			if (portElem == prevElem) {
22579e86db79SHyon Kim 				/* Insert in the head of list. */
22589e86db79SHyon Kim 				newPort->next = portElem;
22599e86db79SHyon Kim 				discoveredLU->HBAPortList = newPort;
22609e86db79SHyon Kim 			} else {
22619e86db79SHyon Kim 				newPort->next = portElem;
22629e86db79SHyon Kim 				prevElem->next = newPort;
22639e86db79SHyon Kim 			}
22649e86db79SHyon Kim 			/* add Target Port */
22659e86db79SHyon Kim 			newPort->tgtPortWWN = (tgtPortWWNList *)calloc(1,
22669e86db79SHyon Kim 			    sizeof (tgtPortWWNList));
22679e86db79SHyon Kim 			if (newPort->tgtPortWWN == NULL) {
2268*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s\n", strerror(errno));
22699e86db79SHyon Kim 				return (++ret);
22709e86db79SHyon Kim 			}
2271*b172429eSMarco van Wieringen 			(void) memcpy((void *)&(newPort->tgtPortWWN->portWWN),
22729e86db79SHyon Kim 			    (void *)&(entryP->PortLun.PortWWN),
22739e86db79SHyon Kim 			    sizeof (HBA_WWN));
22749e86db79SHyon Kim 			/* Set LUN data */
22759e86db79SHyon Kim 			newPort->tgtPortWWN->scsiOSLun =
22769e86db79SHyon Kim 			    entryP->ScsiId.ScsiOSLun;
22779e86db79SHyon Kim 		} else {
22789e86db79SHyon Kim 			/*
22799e86db79SHyon Kim 			 * Otherwise, we just need to add the target port
22809e86db79SHyon Kim 			 * sas address information.
22819e86db79SHyon Kim 			 */
22829e86db79SHyon Kim 			for (TgtWWNList = portElem->tgtPortWWN;
22839e86db79SHyon Kim 			    TgtWWNList != NULL;
22849e86db79SHyon Kim 			    TgtWWNList = TgtWWNList->next) {
22859e86db79SHyon Kim 				if (memcmp(&TgtWWNList->portWWN,
22869e86db79SHyon Kim 				    &entryP->PortLun.PortWWN,
22879e86db79SHyon Kim 				    sizeof (HBA_WWN)) == 0)
22889e86db79SHyon Kim 					return (0);
22899e86db79SHyon Kim 			}
22909e86db79SHyon Kim 			/* add it to existing */
22919e86db79SHyon Kim 			newTgtWWN = (tgtPortWWNList *)calloc(1,
22929e86db79SHyon Kim 			    sizeof (tgtPortWWNList));
22939e86db79SHyon Kim 			if (newTgtWWN == NULL) {
2294*b172429eSMarco van Wieringen 				(void) fprintf(stderr, "%s\n", strerror(errno));
22959e86db79SHyon Kim 				return (++ret);
22969e86db79SHyon Kim 			}
22979e86db79SHyon Kim 			/* insert at head */
22989e86db79SHyon Kim 			newTgtWWN->next = portElem->tgtPortWWN;
22999e86db79SHyon Kim 			portElem->tgtPortWWN = newTgtWWN;
2300*b172429eSMarco van Wieringen 			(void) memcpy((void *)&(newTgtWWN->portWWN),
23019e86db79SHyon Kim 			    (void *)&(entryP->PortLun.PortWWN),
23029e86db79SHyon Kim 			    sizeof (HBA_WWN));
23039e86db79SHyon Kim 			/* Set LUN data */
23049e86db79SHyon Kim 			newTgtWWN->scsiOSLun =
23059e86db79SHyon Kim 			    entryP->ScsiId.ScsiOSLun;
23069e86db79SHyon Kim 		}
23079e86db79SHyon Kim 	} else {
23089e86db79SHyon Kim 		/*
23099e86db79SHyon Kim 		 * Here we got a new discovered LU which has not ever exist
23109e86db79SHyon Kim 		 * in our global LU list. So add it into our global LU
23119e86db79SHyon Kim 		 * list.
23129e86db79SHyon Kim 		 */
23139e86db79SHyon Kim 		newDevice = (discoveredDevice *)calloc(1,
23149e86db79SHyon Kim 		    sizeof (discoveredDevice));
23159e86db79SHyon Kim 
23169e86db79SHyon Kim 		if (newDevice == NULL) {
2317*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n", strerror(errno));
23189e86db79SHyon Kim 			return (++ret);
23199e86db79SHyon Kim 		}
23209e86db79SHyon Kim 		newDevice->next = LUList; /* insert at head */
23219e86db79SHyon Kim 		LUList = newDevice; /* set new head */
23229e86db79SHyon Kim 
23239e86db79SHyon Kim 		/* copy device name */
2324*b172429eSMarco van Wieringen 		(void) strlcpy(newDevice->OSDeviceName,
23259e86db79SHyon Kim 		    entryP->ScsiId.OSDeviceName,
23269e86db79SHyon Kim 		    sizeof (newDevice->OSDeviceName));
23279e86db79SHyon Kim 
23289e86db79SHyon Kim 		/* if verbose is not set return */
23299e86db79SHyon Kim 		if ((pflag & PRINT_VERBOSE) == 0) {
23309e86db79SHyon Kim 			return (0);
23319e86db79SHyon Kim 		}
23329e86db79SHyon Kim 
23339e86db79SHyon Kim 		/* copy WWN data */
23349e86db79SHyon Kim 		newDevice->HBAPortList = (portList *)calloc(1,
23359e86db79SHyon Kim 		    sizeof (portList));
23369e86db79SHyon Kim 		if (newDevice->HBAPortList == NULL) {
2337*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n", strerror(errno));
23389e86db79SHyon Kim 			return (++ret);
23399e86db79SHyon Kim 		}
23409e86db79SHyon Kim 		(void) strlcpy(newDevice->HBAPortList->portName,
23419e86db79SHyon Kim 		    portName, sizeof (newDevice->HBAPortList->portName));
23429e86db79SHyon Kim 
23439e86db79SHyon Kim 		newDevice->HBAPortList->tgtPortWWN =
23449e86db79SHyon Kim 		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
23459e86db79SHyon Kim 		if (newDevice->HBAPortList->tgtPortWWN == NULL) {
2346*b172429eSMarco van Wieringen 			(void) fprintf(stderr, "%s\n", strerror(errno));
23479e86db79SHyon Kim 			return (++ret);
23489e86db79SHyon Kim 		}
23499e86db79SHyon Kim 
2350*b172429eSMarco van Wieringen 		(void) memcpy((void *)&(newDevice->HBAPortList->\
23519e86db79SHyon Kim 		    tgtPortWWN->portWWN),
23529e86db79SHyon Kim 		    (void *)&(entryP->PortLun.PortWWN),
23539e86db79SHyon Kim 		    sizeof (HBA_WWN));
23549e86db79SHyon Kim 		newDevice->HBAPortList->tgtPortWWN->scsiOSLun =
23559e86db79SHyon Kim 		    entryP->ScsiId.ScsiOSLun;
23569e86db79SHyon Kim 
23579e86db79SHyon Kim 		responseSize = sizeof (struct scsi_inquiry);
23589e86db79SHyon Kim 		senseSize = sizeof (struct scsi_extended_sense);
2359*b172429eSMarco van Wieringen 		(void) memset(&inq, 0, sizeof (struct scsi_inquiry));
2360*b172429eSMarco van Wieringen 		(void) memset(&sense, 0, sizeof (sense));
2361*b172429eSMarco van Wieringen 		(void) memcpy(&smhbaLUN, &entryP->PortLun.TargetLun,
23629e86db79SHyon Kim 		    sizeof (smhbaLUN));
23639e86db79SHyon Kim 
23649e86db79SHyon Kim 		/*
23659e86db79SHyon Kim 		 * Retrieve the VPD data for the newly found discovered LU.
23669e86db79SHyon Kim 		 */
23679e86db79SHyon Kim 		status = SMHBA_ScsiInquiry(
23689e86db79SHyon Kim 		    handle,
23699e86db79SHyon Kim 		    hbaPortWWN,
23709e86db79SHyon Kim 		    entryP->PortLun.PortWWN,
23719e86db79SHyon Kim 		    domainPortWWN,
23729e86db79SHyon Kim 		    smhbaLUN,
23739e86db79SHyon Kim 		    0,
23749e86db79SHyon Kim 		    0,
23759e86db79SHyon Kim 		    (void *) &inq, &responseSize,
23769e86db79SHyon Kim 		    &inq_status,
23779e86db79SHyon Kim 		    (void *) &sense, &senseSize);
23789e86db79SHyon Kim 
23799e86db79SHyon Kim 		if (status != HBA_STATUS_OK) {
23809e86db79SHyon Kim 			/* init VID/PID/dType as '\0' */
23819e86db79SHyon Kim 			newDevice->VID[0] = '\0';
23829e86db79SHyon Kim 			newDevice->PID[0] = '\0';
23839e86db79SHyon Kim 			newDevice->dType = DTYPE_UNKNOWN;
23849e86db79SHyon Kim 			/* initialize inq status */
23859e86db79SHyon Kim 			newDevice->inquiryFailed = B_TRUE;
23869e86db79SHyon Kim 			ret++;
23879e86db79SHyon Kim 		} else {
2388*b172429eSMarco van Wieringen 			(void) memcpy(newDevice->VID, inq.inq_vid,
23899e86db79SHyon Kim 			    sizeof (newDevice->VID));
2390*b172429eSMarco van Wieringen 			(void) memcpy(newDevice->PID, inq.inq_pid,
23919e86db79SHyon Kim 			    sizeof (newDevice->PID));
23929e86db79SHyon Kim 			newDevice->dType = inq.inq_dtype;
23939e86db79SHyon Kim 			/* initialize inq status */
23949e86db79SHyon Kim 			newDevice->inquiryFailed = B_FALSE;
23959e86db79SHyon Kim 		}
23969e86db79SHyon Kim 	}
23979e86db79SHyon Kim 	return (ret);
23989e86db79SHyon Kim }
23999e86db79SHyon Kim 
24009e86db79SHyon Kim /*
24019e86db79SHyon Kim  * Function we use to insert a newly discovered port.
24029e86db79SHyon Kim  * Return:
24039e86db79SHyon Kim  * 	0 - success
24049e86db79SHyon Kim  * 	>0 - failed
24059e86db79SHyon Kim  */
24069e86db79SHyon Kim static int
sas_rp_tree_insert(rp_tree_t ** rproot,rp_tree_t * rpnode)24079e86db79SHyon Kim sas_rp_tree_insert(rp_tree_t **rproot,
24089e86db79SHyon Kim     rp_tree_t *rpnode)
24099e86db79SHyon Kim {
24109e86db79SHyon Kim 	HBA_UINT8 *wwn1, *wwn2, *wwn3;
24119e86db79SHyon Kim 	rp_tree_t *node_ptr;
24129e86db79SHyon Kim 	int ret = 0;
24139e86db79SHyon Kim 
24149e86db79SHyon Kim 	if (rproot == NULL) {
2415*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
24169e86db79SHyon Kim 		    gettext("Error: NULL rproot"));
24179e86db79SHyon Kim 		return (1);
24189e86db79SHyon Kim 	}
24199e86db79SHyon Kim 
24209e86db79SHyon Kim 	if (rpnode == NULL) {
2421*b172429eSMarco van Wieringen 		(void) fprintf(stderr, "%s\n",
24229e86db79SHyon Kim 		    gettext("Error: NULL rpnode"));
24239e86db79SHyon Kim 		return (1);
24249e86db79SHyon Kim 	}
24259e86db79SHyon Kim 
24269e86db79SHyon Kim 	if (*rproot == NULL) {
24279e86db79SHyon Kim 		*rproot = rpnode;
24289e86db79SHyon Kim 		return (0);
24299e86db79SHyon Kim 	}
24309e86db79SHyon Kim 
24319e86db79SHyon Kim 	wwn1 = (*rproot)->sasattr.LocalSASAddress.wwn;
24329e86db79SHyon Kim 	wwn2 = (*rproot)->sasattr.AttachedSASAddress.wwn;
24339e86db79SHyon Kim 	wwn3 = rpnode->sasattr.AttachedSASAddress.wwn;
24349e86db79SHyon Kim 
24359e86db79SHyon Kim 	/*
24369e86db79SHyon Kim 	 * If the attched sas address is equal to the local sas address,
24379e86db79SHyon Kim 	 * then this should be a child node of current root node.
24389e86db79SHyon Kim 	 */
24399e86db79SHyon Kim 	if (memcmp(wwn1, wwn3, sizeof (HBA_WWN)) == 0) {
24409e86db79SHyon Kim 		(void) sas_rp_tree_insert(&(*rproot)->child, rpnode);
24419e86db79SHyon Kim 		rpnode->parent = *rproot;
24429e86db79SHyon Kim 	} else if (memcmp(wwn2, wwn3, sizeof (HBA_WWN)) == 0) {
24439e86db79SHyon Kim 		/*
24449e86db79SHyon Kim 		 * If the attached sas address is equal to the attached sas
24459e86db79SHyon Kim 		 * address of current root node, then this should be a
24469e86db79SHyon Kim 		 * sibling node.
24479e86db79SHyon Kim 		 * Insert the SAS/SATA Device at the head of sibling list.
24489e86db79SHyon Kim 		 */
24499e86db79SHyon Kim 		if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
24509e86db79SHyon Kim 			rpnode->sibling = *rproot;
24519e86db79SHyon Kim 			*rproot = rpnode;
24529e86db79SHyon Kim 		} else {
24539e86db79SHyon Kim 			/*
24549e86db79SHyon Kim 			 * Insert the SAS Expander at the tail of sibling
24559e86db79SHyon Kim 			 * list.
24569e86db79SHyon Kim 			 */
24579e86db79SHyon Kim 			node_ptr = *rproot;
24589e86db79SHyon Kim 			while (node_ptr->sibling != NULL)
24599e86db79SHyon Kim 				node_ptr = node_ptr->sibling;
24609e86db79SHyon Kim 			node_ptr->sibling = rpnode;
24619e86db79SHyon Kim 		}
24629e86db79SHyon Kim 		rpnode->parent = (*rproot)->parent;
24639e86db79SHyon Kim 	} else {
24649e86db79SHyon Kim 		/*
24659e86db79SHyon Kim 		 * If enter here, we should first try to insert the discovered
24669e86db79SHyon Kim 		 * port node into the child sub-tree, then try to insert to the
24679e86db79SHyon Kim 		 * sibling sub-trees. If we failed to insert the discovered
24689e86db79SHyon Kim 		 * port node, return 1. The caller will queue this node
24699e86db79SHyon Kim 		 * up and retry insertion later.
24709e86db79SHyon Kim 		 */
24719e86db79SHyon Kim 		if ((*rproot)->child) {
24729e86db79SHyon Kim 			ret = sas_rp_tree_insert(&(*rproot)->child, rpnode);
24739e86db79SHyon Kim 		}
24749e86db79SHyon Kim 		if ((*rproot)->child == NULL || ret != 0) {
24759e86db79SHyon Kim 			if ((*rproot)->sibling) {
24769e86db79SHyon Kim 				ret = sas_rp_tree_insert(&(*rproot)->sibling,
24779e86db79SHyon Kim 				    rpnode);
24789e86db79SHyon Kim 			} else
24799e86db79SHyon Kim 				ret = 1;
24809e86db79SHyon Kim 		}
24819e86db79SHyon Kim 		return (ret);
24829e86db79SHyon Kim 	}
24839e86db79SHyon Kim 	return (0);
24849e86db79SHyon Kim }
24859e86db79SHyon Kim 
24869e86db79SHyon Kim /*
24879e86db79SHyon Kim  * Function which will print out the whole disocvered port topology.
24889e86db79SHyon Kim  * Here we use the Preorder Traversal algorithm.
24899e86db79SHyon Kim  * The indentation rules are:
24909e86db79SHyon Kim  * 	1 * TABLEN - for attributes
24919e86db79SHyon Kim  * 	2 * TABLEN - for next tier target port/expander
24929e86db79SHyon Kim  */
24939e86db79SHyon Kim static int
sas_rp_tree_print(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,rp_tree_t * rpnode,inputArg_t * input,int gident,int * printPort)24949e86db79SHyon Kim sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
24959e86db79SHyon Kim     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
24969e86db79SHyon Kim     rp_tree_t *rpnode, inputArg_t *input,
24979e86db79SHyon Kim     int gident, int *printPort)
24989e86db79SHyon Kim {
24999e86db79SHyon Kim 	int ret = 0, lident;
25009e86db79SHyon Kim 
25019e86db79SHyon Kim 	if (rpnode == NULL)
25029e86db79SHyon Kim 		return (ret);
25039e86db79SHyon Kim 	lident = gident;
25049e86db79SHyon Kim 
25059e86db79SHyon Kim 	/*
25069e86db79SHyon Kim 	 * We assume that all the nodes are disocvered ports(sas device or
25079e86db79SHyon Kim 	 * expander).
25089e86db79SHyon Kim 	 */
25099e86db79SHyon Kim 	if (input->wwnCount > 0) {
25109e86db79SHyon Kim 		/* Adjust local indentation if a discovered port specified. */
25119e86db79SHyon Kim 		lident = 2 * TABLEN;
25129e86db79SHyon Kim 		/*
25139e86db79SHyon Kim 		 * Check whether current node match one of the specified
25149e86db79SHyon Kim 		 * SAS addresses.
25159e86db79SHyon Kim 		 */
25169e86db79SHyon Kim 		if ((rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) ||
25179e86db79SHyon Kim 		    !isPortWWNInArgv(input,
25189e86db79SHyon Kim 		    &rpnode->sasattr.LocalSASAddress)) {
25199e86db79SHyon Kim 			/*
25209e86db79SHyon Kim 			 * Step down to child tree first.
25219e86db79SHyon Kim 			 */
25229e86db79SHyon Kim 			ret += sas_rp_tree_print(handle, adapterName,
25239e86db79SHyon Kim 			    portIndex, port, rpnode->child, input,
25249e86db79SHyon Kim 			    gident + 2 * TABLEN, printPort);
25259e86db79SHyon Kim 			/*
25269e86db79SHyon Kim 			 * Then check the sibling tree.
25279e86db79SHyon Kim 			 */
25289e86db79SHyon Kim 			ret += sas_rp_tree_print(handle, adapterName,
25299e86db79SHyon Kim 			    portIndex, port, rpnode->sibling, input,
25309e86db79SHyon Kim 			    gident, printPort);
25319e86db79SHyon Kim 			return (ret);
25329e86db79SHyon Kim 		}
25339e86db79SHyon Kim 	}
25349e86db79SHyon Kim 
25359e86db79SHyon Kim 	if ((rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) ||
25369e86db79SHyon Kim 	    (input->pflag & PRINT_TARGET_PORT)) {
25379e86db79SHyon Kim 		/*
25389e86db79SHyon Kim 		 * We should print the header(HBA Name + HBA Port Name)
25399e86db79SHyon Kim 		 * on-demand. It means that, if we have expander device
25409e86db79SHyon Kim 		 * address specified on the command line, we should print
25419e86db79SHyon Kim 		 * the header once we find a matching one. Or we will
25429e86db79SHyon Kim 		 * print the header from the beginning of the output.
25439e86db79SHyon Kim 		 */
25449e86db79SHyon Kim 		if (g_printHBA == 0) {
2545*b172429eSMarco van Wieringen 			(void) fprintf(stdout, "%s %s\n",
25469e86db79SHyon Kim 			    "HBA Name:", adapterName);
25479e86db79SHyon Kim 			g_printHBA = 1;
25489e86db79SHyon Kim 		}
25499e86db79SHyon Kim 
25509e86db79SHyon Kim 		if (*printPort == 0) {
2551*b172429eSMarco van Wieringen 			(void) fprintf(stdout, "%s%s %s\n",
25529e86db79SHyon Kim 			    getIndentSpaces(TABLEN),
25539e86db79SHyon Kim 			    "HBA Port Name:", port->OSDeviceName);
25549e86db79SHyon Kim 			*printPort = 1;
25559e86db79SHyon Kim 		}
25569e86db79SHyon Kim 		ret += sas_print_rpnode(input, rpnode, lident, gident);
25579e86db79SHyon Kim 	}
25589e86db79SHyon Kim 
25599e86db79SHyon Kim 	/*
25609e86db79SHyon Kim 	 * If operands provided with "-t" option specified, we will print
25619e86db79SHyon Kim 	 * the immediate child nodes information under the expander.
25629e86db79SHyon Kim 	 */
25639e86db79SHyon Kim 	if (input->pflag & PRINT_TARGET_PORT) {
25649e86db79SHyon Kim 		/* no operand. ignore the option. */
25659e86db79SHyon Kim 		if (input->wwnCount > 0) {
25669e86db79SHyon Kim 			if (rpnode->portattr.PortType ==
25679e86db79SHyon Kim 			    HBA_PORTTYPE_SASEXPANDER) {
25689e86db79SHyon Kim 				ret += sas_rp_tree_print_desc(handle,
25699e86db79SHyon Kim 				    portIndex, port, rpnode->child,
25709e86db79SHyon Kim 				    input,
25719e86db79SHyon Kim 				    lident + 2 * TABLEN,
25729e86db79SHyon Kim 				    gident + 2 * TABLEN);
25739e86db79SHyon Kim 			}
25749e86db79SHyon Kim 		}
25759e86db79SHyon Kim 	}
25769e86db79SHyon Kim 
25779e86db79SHyon Kim 	/*
25789e86db79SHyon Kim 	 * Here we use DFS(Depth First Search) algorithm to traverse the
25799e86db79SHyon Kim 	 * whole tree.
25809e86db79SHyon Kim 	 */
25819e86db79SHyon Kim 	ret += sas_rp_tree_print(handle, adapterName,
25829e86db79SHyon Kim 	    portIndex, port, rpnode->child, input,
25839e86db79SHyon Kim 	    gident + 2 * TABLEN, printPort);
25849e86db79SHyon Kim 	ret += sas_rp_tree_print(handle, adapterName,
25859e86db79SHyon Kim 	    portIndex, port, rpnode->sibling, input,
25869e86db79SHyon Kim 	    gident, printPort);
25879e86db79SHyon Kim 	return (ret);
25889e86db79SHyon Kim }
25899e86db79SHyon Kim 
25909e86db79SHyon Kim /*
25919e86db79SHyon Kim  * Function which will destroy the whole discovered port tree.
25929e86db79SHyon Kim  * Here we use the Postorder Traversal algorithm.
25939e86db79SHyon Kim  */
sas_rp_tree_free(rp_tree_t * rproot)25949e86db79SHyon Kim static void sas_rp_tree_free(rp_tree_t *rproot)
25959e86db79SHyon Kim {
25969e86db79SHyon Kim 	tgt_mapping *cur, *next;
25979e86db79SHyon Kim 
25989e86db79SHyon Kim 	if (rproot == NULL)
25999e86db79SHyon Kim 		return;
26009e86db79SHyon Kim 
26019e86db79SHyon Kim 	/*
26029e86db79SHyon Kim 	 * Free child tree first.
26039e86db79SHyon Kim 	 */
26049e86db79SHyon Kim 	if (rproot->child) {
26059e86db79SHyon Kim 		sas_rp_tree_free(rproot->child);
26069e86db79SHyon Kim 	}
26079e86db79SHyon Kim 
26089e86db79SHyon Kim 	/*
26099e86db79SHyon Kim 	 * Free sibling trees then.
26109e86db79SHyon Kim 	 */
26119e86db79SHyon Kim 	if (rproot->sibling) {
26129e86db79SHyon Kim 		sas_rp_tree_free(rproot->sibling);
26139e86db79SHyon Kim 	}
26149e86db79SHyon Kim 
26159e86db79SHyon Kim 	/*
26169e86db79SHyon Kim 	 * Free root node at last.
26179e86db79SHyon Kim 	 */
26189e86db79SHyon Kim 	cur = rproot->first_entry;
26199e86db79SHyon Kim 	while (cur != NULL) {
26209e86db79SHyon Kim 		next = cur->next;
26219e86db79SHyon Kim 		free(cur);
26229e86db79SHyon Kim 		cur = next;
26239e86db79SHyon Kim 	}
26249e86db79SHyon Kim 	free(rproot);
26259e86db79SHyon Kim }
26269e86db79SHyon Kim 
26279e86db79SHyon Kim /*
26289e86db79SHyon Kim  * Function used to print out all the descendant nodes.
26299e86db79SHyon Kim  * handle - handle to HBA.
26309e86db79SHyon Kim  * port - port attributes of current HBA port.
26319e86db79SHyon Kim  * desc - the root node of a subtree which will be processed.
26329e86db79SHyon Kim  * input - input argument.
26339e86db79SHyon Kim  * lident - local indentation for shifting indentation.
26349e86db79SHyon Kim  * gident - global indentation, can also be used to obtain Tier number.
26359e86db79SHyon Kim  */
26369e86db79SHyon Kim /*ARGSUSED*/
26379e86db79SHyon Kim static int
sas_rp_tree_print_desc(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,rp_tree_t * desc,inputArg_t * input,int lident,int gident)26389e86db79SHyon Kim sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
26399e86db79SHyon Kim     SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
26409e86db79SHyon Kim     inputArg_t *input, int lident, int gident)
26419e86db79SHyon Kim {
26429e86db79SHyon Kim 	int ret = 0;
26439e86db79SHyon Kim 	rp_tree_t   *rp_node;
26449e86db79SHyon Kim 
26459e86db79SHyon Kim 	if (desc == NULL)
26469e86db79SHyon Kim 		return (ret);
26479e86db79SHyon Kim 	/*
26489e86db79SHyon Kim 	 * Walk through the subtree of desc by Pre-Order Traversal Algo.
26499e86db79SHyon Kim 	 */
26509e86db79SHyon Kim 	for (rp_node = desc; rp_node !=	NULL; rp_node = rp_node->sibling) {
26519e86db79SHyon Kim 		ret += sas_print_rpnode(input, rp_node, lident, gident);
26529e86db79SHyon Kim 	}
26539e86db79SHyon Kim 
26549e86db79SHyon Kim 	return (ret);
26559e86db79SHyon Kim }
26569e86db79SHyon Kim 
26579e86db79SHyon Kim /*
26589e86db79SHyon Kim  * Function used to print the information of specified SAS address.
26599e86db79SHyon Kim  * handle - handle to a HBA.
26609e86db79SHyon Kim  * port - port attributes of a HBA port.
26619e86db79SHyon Kim  * rpnode - discovered port which will be processed.
26629e86db79SHyon Kim  * lident - local indentation used for shifting indentation.
26639e86db79SHyon Kim  * gident - global indentation used for calculating "Tier" number.
26649e86db79SHyon Kim  */
26659e86db79SHyon Kim static int
sas_print_rpnode(inputArg_t * input,rp_tree_t * rpnode,int lident,int gident)26669e86db79SHyon Kim sas_print_rpnode(inputArg_t *input,
26679e86db79SHyon Kim     rp_tree_t *rpnode, int lident, int gident)
26689e86db79SHyon Kim {
26699e86db79SHyon Kim 	int ret = 0;
26709e86db79SHyon Kim 
26719e86db79SHyon Kim 	if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
2672*b172429eSMarco van Wieringen 		(void) fprintf(stdout, "%s%s(Tier %d): %016llx\n",
26739e86db79SHyon Kim 		    getIndentSpaces(lident),
26749e86db79SHyon Kim 		    "Expander SAS Address",
26759e86db79SHyon Kim 		    gident / (2 * TABLEN),
26769e86db79SHyon Kim 		    wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
26779e86db79SHyon Kim 	} else {
2678*b172429eSMarco van Wieringen 		(void) fprintf(stdout, "%s%s %016llx\n",
26799e86db79SHyon Kim 		    getIndentSpaces(lident),
26809e86db79SHyon Kim 		    "Target Port SAS Address:",
26819e86db79SHyon Kim 		    wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
26829e86db79SHyon Kim 	}
26839e86db79SHyon Kim 	if (input->pflag & PRINT_VERBOSE) {
26849e86db79SHyon Kim 		if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2685*b172429eSMarco van Wieringen 			(void) fprintf(stdout, "%s%s %s\n",
26869e86db79SHyon Kim 			    getIndentSpaces(TABLEN + lident),
26879e86db79SHyon Kim 			    "Type:",
26889e86db79SHyon Kim 			    getStateString(rpnode->portattr.PortType,
26899e86db79SHyon Kim 			    porttype_string));
26909e86db79SHyon Kim 		} else {
2691*b172429eSMarco van Wieringen 			(void) fprintf(stdout, "%s%s %s\n",
26929e86db79SHyon Kim 			    getIndentSpaces(TABLEN + lident),
26939e86db79SHyon Kim 			    "OS Device Name:",
26949e86db79SHyon Kim 			    rpnode->portattr.OSDeviceName);
2695*b172429eSMarco van Wieringen 			(void) fprintf(stdout, "%s%s %s\n",
26969e86db79SHyon Kim 			    getIndentSpaces(TABLEN + lident),
26979e86db79SHyon Kim 			    "State: ",
26989e86db79SHyon Kim 			    getStateString(rpnode->portattr.PortState,
26999e86db79SHyon Kim 			    portstate_string));
27009e86db79SHyon Kim 		}
27019e86db79SHyon Kim 	}
27029e86db79SHyon Kim 	rpnode->printed = 1;
27039e86db79SHyon Kim 	return (ret);
27049e86db79SHyon Kim }
27059e86db79SHyon Kim 
27069e86db79SHyon Kim /*
27079e86db79SHyon Kim  * Function used to get the correct domainPortWWN as needed by some of the
27089e86db79SHyon Kim  * SMHBA APIs.
27099e86db79SHyon Kim  * handle - handle to a HBA.
27109e86db79SHyon Kim  * portIndex - index to locate the port.
27119e86db79SHyon Kim  * port - pointer to the structure holding port attributes.
27129e86db79SHyon Kim  * pdomainPort - pointer to the buffer holding domainPortWWN.
27139e86db79SHyon Kim  */
27149e86db79SHyon Kim HBA_STATUS
get_domainPort(HBA_HANDLE handle,int portIndex,PSMHBA_PORTATTRIBUTES port,HBA_WWN * pdomainPort)27159e86db79SHyon Kim get_domainPort(HBA_HANDLE handle,
27169e86db79SHyon Kim     int portIndex, PSMHBA_PORTATTRIBUTES port,
27179e86db79SHyon Kim     HBA_WWN *pdomainPort)
27189e86db79SHyon Kim {
27199e86db79SHyon Kim 	HBA_STATUS status;
27209e86db79SHyon Kim 	PSMHBA_SAS_PORT sasport;
27219e86db79SHyon Kim 	SMHBA_SAS_PHY phyattr;
27229e86db79SHyon Kim 
27239e86db79SHyon Kim 	sasport = port->PortSpecificAttribute.SASPort;
2724*b172429eSMarco van Wieringen 	(void) memset(pdomainPort, 0, sizeof (HBA_WWN));
27259e86db79SHyon Kim 	/*
27269e86db79SHyon Kim 	 * Since iport can exist without any phys,
27279e86db79SHyon Kim 	 * sasinfo hba-port -v has indicated numberOfPhys;
27289e86db79SHyon Kim 	 * if there is no phys within the hba, just return OK.
27299e86db79SHyon Kim 	 */
27309e86db79SHyon Kim 	if (sasport->NumberofPhys > 0) {
27319e86db79SHyon Kim 		status = SMHBA_GetSASPhyAttributes(handle, portIndex,
27329e86db79SHyon Kim 		    0, &phyattr);
27339e86db79SHyon Kim 		if (status != HBA_STATUS_OK)
27349e86db79SHyon Kim 			return (status);
2735*b172429eSMarco van Wieringen 		(void) memcpy(pdomainPort, &phyattr.domainPortWWN,
27369e86db79SHyon Kim 		    sizeof (HBA_WWN));
27379e86db79SHyon Kim 	} else {
27389e86db79SHyon Kim 		/* return not supported for no phy configured */
27399e86db79SHyon Kim 		return (HBA_STATUS_ERROR_NOT_SUPPORTED);
27409e86db79SHyon Kim 	}
27419e86db79SHyon Kim 	return (HBA_STATUS_OK);
27429e86db79SHyon Kim }
27439e86db79SHyon Kim 
27449e86db79SHyon Kim /*
27459e86db79SHyon Kim  * Comparison function for comparing names possibly ending with digits.
27469e86db79SHyon Kim  * Return:
27479e86db79SHyon Kim  * 	<0 - name1 is less than name2.
27489e86db79SHyon Kim  * 	0 - name1 is equal with name2.
27499e86db79SHyon Kim  * 	>0 - name1 is more than name2.
27509e86db79SHyon Kim  */
27519e86db79SHyon Kim static int
sas_name_comp(const char * name1,const char * name2)27529e86db79SHyon Kim sas_name_comp(const char *name1, const char *name2)
27539e86db79SHyon Kim {
27549e86db79SHyon Kim 	int i = 0;
27559e86db79SHyon Kim 
27569e86db79SHyon Kim 	if (name1 == name2)
27579e86db79SHyon Kim 		return (0);
27589e86db79SHyon Kim 
27599e86db79SHyon Kim 	while ((name1[i] == name2[i]) && (name1[i] != '\0'))
27609e86db79SHyon Kim 		i++;
27619e86db79SHyon Kim 
27629e86db79SHyon Kim 	/* If neither of name1[i] and name2[i] is '\0'. */
27639e86db79SHyon Kim 	if (isdigit(name1[i]) && isdigit(name2[i]))
27649e86db79SHyon Kim 		return (atoi(&name1[i]) - atoi(&name2[i]));
27659e86db79SHyon Kim 
27669e86db79SHyon Kim 	/* One of name1[i] and name2[i] is not digit. */
27679e86db79SHyon Kim 	return (name1[i] - name2[i]);
27689e86db79SHyon Kim }
27699e86db79SHyon Kim /*
27709e86db79SHyon Kim  * Comparison function for sorting HBA/HBA Port.
27719e86db79SHyon Kim  * arg1 - first argument of type sas_elem_t.
27729e86db79SHyon Kim  * arg2 - second argument of type sas_elem_t.
27739e86db79SHyon Kim  * Return:
27749e86db79SHyon Kim  * 	<0 - arg1 is less than arg2.
27759e86db79SHyon Kim  * 	0 - arg1 is equal with arg2.
27769e86db79SHyon Kim  * 	>0 - arg1 is more than arg2.
27779e86db79SHyon Kim  */
27789e86db79SHyon Kim static int
sas_elem_compare(const void * arg1,const void * arg2)27799e86db79SHyon Kim sas_elem_compare(const void *arg1, const void *arg2)
27809e86db79SHyon Kim {
27819e86db79SHyon Kim 	sas_elem_t *p1, *p2;
27829e86db79SHyon Kim 	p1 = (sas_elem_t *)arg1;
27839e86db79SHyon Kim 	p2 = (sas_elem_t *)arg2;
27849e86db79SHyon Kim 	return (sas_name_comp(p1->name, p2->name));
27859e86db79SHyon Kim }
27869e86db79SHyon Kim 
27879e86db79SHyon Kim /*
27889e86db79SHyon Kim  * Sorting function for HBA/HBA Port output.
27899e86db79SHyon Kim  * array - elements array of type sas_elem_t.
27909e86db79SHyon Kim  * nelem - number of elements in array of type sas_elem_t.
27919e86db79SHyon Kim  */
27929e86db79SHyon Kim static void
sas_elem_sort(sas_elem_t * array,int nelem)27939e86db79SHyon Kim sas_elem_sort(sas_elem_t *array, int nelem)
27949e86db79SHyon Kim {
27959e86db79SHyon Kim 	qsort((void *)array, nelem, sizeof (sas_elem_t), sas_elem_compare);
27969e86db79SHyon Kim }
2797