xref: /onnv-gate/usr/src/cmd/sasinfo/sasinfo-list.c (revision 10652:9d0aff74d6fd)
1*10652SHyon.Kim@Sun.COM /*
2*10652SHyon.Kim@Sun.COM  * CDDL HEADER START
3*10652SHyon.Kim@Sun.COM  *
4*10652SHyon.Kim@Sun.COM  * The contents of this file are subject to the terms of the
5*10652SHyon.Kim@Sun.COM  * Common Development and Distribution License (the "License").
6*10652SHyon.Kim@Sun.COM  * You may not use this file except in compliance with the License.
7*10652SHyon.Kim@Sun.COM  *
8*10652SHyon.Kim@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10652SHyon.Kim@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10652SHyon.Kim@Sun.COM  * See the License for the specific language governing permissions
11*10652SHyon.Kim@Sun.COM  * and limitations under the License.
12*10652SHyon.Kim@Sun.COM  *
13*10652SHyon.Kim@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10652SHyon.Kim@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10652SHyon.Kim@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10652SHyon.Kim@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10652SHyon.Kim@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10652SHyon.Kim@Sun.COM  *
19*10652SHyon.Kim@Sun.COM  * CDDL HEADER END
20*10652SHyon.Kim@Sun.COM  */
21*10652SHyon.Kim@Sun.COM /*
22*10652SHyon.Kim@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*10652SHyon.Kim@Sun.COM  * Use is subject to license terms.
24*10652SHyon.Kim@Sun.COM  */
25*10652SHyon.Kim@Sun.COM 
26*10652SHyon.Kim@Sun.COM #include <unistd.h>
27*10652SHyon.Kim@Sun.COM #include <stdlib.h>
28*10652SHyon.Kim@Sun.COM #include <ctype.h>
29*10652SHyon.Kim@Sun.COM #include <errno.h>
30*10652SHyon.Kim@Sun.COM #include <printAttrs.h>
31*10652SHyon.Kim@Sun.COM #include <smhbaapi.h>
32*10652SHyon.Kim@Sun.COM 
33*10652SHyon.Kim@Sun.COM #define	TABLEN	2
34*10652SHyon.Kim@Sun.COM typedef struct inputArgs {
35*10652SHyon.Kim@Sun.COM 	int 		wwnCount;
36*10652SHyon.Kim@Sun.COM 	char 		**wwn_argv;
37*10652SHyon.Kim@Sun.COM 	uint64_t 	portWWN;
38*10652SHyon.Kim@Sun.COM 	char		*hbaName;
39*10652SHyon.Kim@Sun.COM 	int		pflag;
40*10652SHyon.Kim@Sun.COM 	int		*wwn_flag;
41*10652SHyon.Kim@Sun.COM } inputArg_t;
42*10652SHyon.Kim@Sun.COM 
43*10652SHyon.Kim@Sun.COM typedef struct tgt_mapping {
44*10652SHyon.Kim@Sun.COM 	SMHBA_SCSIENTRY	tgtentry;
45*10652SHyon.Kim@Sun.COM 	uchar_t		inq_vid[8];
46*10652SHyon.Kim@Sun.COM 	uchar_t		inq_pid[16];
47*10652SHyon.Kim@Sun.COM 	uchar_t		inq_dtype;
48*10652SHyon.Kim@Sun.COM 	struct tgt_mapping *next;
49*10652SHyon.Kim@Sun.COM }tgt_mapping;
50*10652SHyon.Kim@Sun.COM 
51*10652SHyon.Kim@Sun.COM /*
52*10652SHyon.Kim@Sun.COM  * Remote port tree node structure.
53*10652SHyon.Kim@Sun.COM  */
54*10652SHyon.Kim@Sun.COM typedef struct smhba_rp_tree {
55*10652SHyon.Kim@Sun.COM 	SMHBA_PORTATTRIBUTES	portattr;
56*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PORT		sasattr;
57*10652SHyon.Kim@Sun.COM 	tgt_mapping		*first_entry;
58*10652SHyon.Kim@Sun.COM 	int			printed;
59*10652SHyon.Kim@Sun.COM 	struct smhba_rp_tree	*parent;
60*10652SHyon.Kim@Sun.COM 	struct smhba_rp_tree	*child;
61*10652SHyon.Kim@Sun.COM 	struct smhba_rp_tree	*sibling;
62*10652SHyon.Kim@Sun.COM }rp_tree_t;
63*10652SHyon.Kim@Sun.COM 
64*10652SHyon.Kim@Sun.COM /*
65*10652SHyon.Kim@Sun.COM  * Report LUN data structure.
66*10652SHyon.Kim@Sun.COM  */
67*10652SHyon.Kim@Sun.COM struct lun {
68*10652SHyon.Kim@Sun.COM 	uchar_t	val[8];
69*10652SHyon.Kim@Sun.COM };
70*10652SHyon.Kim@Sun.COM 
71*10652SHyon.Kim@Sun.COM typedef struct rep_luns_rsp {
72*10652SHyon.Kim@Sun.COM 	uint32_t    length;
73*10652SHyon.Kim@Sun.COM 	uint32_t    rsrvd;
74*10652SHyon.Kim@Sun.COM 	struct lun  lun[1];
75*10652SHyon.Kim@Sun.COM } rep_luns_rsp_t;
76*10652SHyon.Kim@Sun.COM 
77*10652SHyon.Kim@Sun.COM /*
78*10652SHyon.Kim@Sun.COM  * The following flag is used for printing HBA header on-demand.
79*10652SHyon.Kim@Sun.COM  */
80*10652SHyon.Kim@Sun.COM static int g_printHBA = 0;
81*10652SHyon.Kim@Sun.COM 
82*10652SHyon.Kim@Sun.COM /*
83*10652SHyon.Kim@Sun.COM  * The following structure is for sorted output of HBA and HBA Port.
84*10652SHyon.Kim@Sun.COM  */
85*10652SHyon.Kim@Sun.COM typedef struct _sas_elem {
86*10652SHyon.Kim@Sun.COM 	char	name[256];
87*10652SHyon.Kim@Sun.COM 	int	index;
88*10652SHyon.Kim@Sun.COM }sas_elem_t;
89*10652SHyon.Kim@Sun.COM 
90*10652SHyon.Kim@Sun.COM /*
91*10652SHyon.Kim@Sun.COM  * The following two functions are for generating hierachy of expander
92*10652SHyon.Kim@Sun.COM  * subcommand.
93*10652SHyon.Kim@Sun.COM  */
94*10652SHyon.Kim@Sun.COM static int
95*10652SHyon.Kim@Sun.COM sas_rp_tree_insert(rp_tree_t **rproot, rp_tree_t *rpnode);
96*10652SHyon.Kim@Sun.COM static int
97*10652SHyon.Kim@Sun.COM sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
98*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
99*10652SHyon.Kim@Sun.COM     rp_tree_t *rpnode, inputArg_t *input, int gident,
100*10652SHyon.Kim@Sun.COM     int *printPort);
101*10652SHyon.Kim@Sun.COM static int
102*10652SHyon.Kim@Sun.COM sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
103*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
104*10652SHyon.Kim@Sun.COM     inputArg_t *input, int lident, int gident);
105*10652SHyon.Kim@Sun.COM static int
106*10652SHyon.Kim@Sun.COM sas_print_rpnode(inputArg_t *input,
107*10652SHyon.Kim@Sun.COM     rp_tree_t *rpnode, int lident, int gident);
108*10652SHyon.Kim@Sun.COM static void sas_rp_tree_free(rp_tree_t *rproot);
109*10652SHyon.Kim@Sun.COM 
110*10652SHyon.Kim@Sun.COM typedef int (*processPortFunc)(HBA_HANDLE handle, char *adapterName,
111*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
112*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
113*10652SHyon.Kim@Sun.COM 
114*10652SHyon.Kim@Sun.COM static int processHBA(inputArg_t *input,
115*10652SHyon.Kim@Sun.COM     processPortFunc processPort);
116*10652SHyon.Kim@Sun.COM 
117*10652SHyon.Kim@Sun.COM static int isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN);
118*10652SHyon.Kim@Sun.COM static int isStringInArgv(inputArg_t *input, const char *adapterName);
119*10652SHyon.Kim@Sun.COM static boolean_t compareLUName(char *cmdArg, char *osName);
120*10652SHyon.Kim@Sun.COM static discoveredDevice *LUList = NULL;
121*10652SHyon.Kim@Sun.COM static targetPortList_t *gTargetPortList = NULL;
122*10652SHyon.Kim@Sun.COM 
123*10652SHyon.Kim@Sun.COM /* processes for hanlding local HBA info */
124*10652SHyon.Kim@Sun.COM static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
125*10652SHyon.Kim@Sun.COM     int numberOfPorts, const char *adapterName);
126*10652SHyon.Kim@Sun.COM static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
127*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
128*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
129*10652SHyon.Kim@Sun.COM static int processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
130*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, int pflag);
131*10652SHyon.Kim@Sun.COM static int processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex,
132*10652SHyon.Kim@Sun.COM     int phyIndex, PSMHBA_SAS_PHY phyattrs, int pflag);
133*10652SHyon.Kim@Sun.COM 
134*10652SHyon.Kim@Sun.COM /* process for handling expander info */
135*10652SHyon.Kim@Sun.COM static int handleExpander(HBA_HANDLE handle, char *adapterName,
136*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
137*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
138*10652SHyon.Kim@Sun.COM 
139*10652SHyon.Kim@Sun.COM /* process for handling target port info */
140*10652SHyon.Kim@Sun.COM static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
141*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
142*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
143*10652SHyon.Kim@Sun.COM 
144*10652SHyon.Kim@Sun.COM /* process for handling logical unit info */
145*10652SHyon.Kim@Sun.COM static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
146*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
147*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input);
148*10652SHyon.Kim@Sun.COM 
149*10652SHyon.Kim@Sun.COM /* process for target port SCSI processing */
150*10652SHyon.Kim@Sun.COM static int
151*10652SHyon.Kim@Sun.COM searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
152*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
153*10652SHyon.Kim@Sun.COM     struct targetPortConfig *configData);
154*10652SHyon.Kim@Sun.COM 
155*10652SHyon.Kim@Sun.COM /* process for target port config processing */
156*10652SHyon.Kim@Sun.COM static int searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
157*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
158*10652SHyon.Kim@Sun.COM     SMHBA_SAS_PORT *sasattr, int pflag);
159*10652SHyon.Kim@Sun.COM 
160*10652SHyon.Kim@Sun.COM /* process for logical-unit config processing */
161*10652SHyon.Kim@Sun.COM static int
162*10652SHyon.Kim@Sun.COM searchDevice(PSMHBA_SCSIENTRY entryP, HBA_HANDLE handle, HBA_WWN hbaPortWWN,
163*10652SHyon.Kim@Sun.COM     HBA_WWN domainPortWWN, char *portName, int pflag);
164*10652SHyon.Kim@Sun.COM 
165*10652SHyon.Kim@Sun.COM /* get domain port out of hba-port phy attr. */
166*10652SHyon.Kim@Sun.COM HBA_STATUS get_domainPort(HBA_HANDLE handle,
167*10652SHyon.Kim@Sun.COM     int portindex, PSMHBA_PORTATTRIBUTES port,
168*10652SHyon.Kim@Sun.COM     HBA_WWN *pdomainPort);
169*10652SHyon.Kim@Sun.COM 
170*10652SHyon.Kim@Sun.COM static int
171*10652SHyon.Kim@Sun.COM sas_name_comp(const char *name1, const char *name2);
172*10652SHyon.Kim@Sun.COM static void
173*10652SHyon.Kim@Sun.COM sas_elem_sort(sas_elem_t *array, int nelem);
174*10652SHyon.Kim@Sun.COM 
175*10652SHyon.Kim@Sun.COM /*
176*10652SHyon.Kim@Sun.COM  * function for hba subcommand
177*10652SHyon.Kim@Sun.COM  *
178*10652SHyon.Kim@Sun.COM  * Arguments:
179*10652SHyon.Kim@Sun.COM  *	wwnCount - count of the number of WWNs in wwn_argv
180*10652SHyon.Kim@Sun.COM  *	    if wwnCount > 0, then we will only print information for
181*10652SHyon.Kim@Sun.COM  *		the hba ports listed in wwn_argv
182*10652SHyon.Kim@Sun.COM  *	    if wwnCount == 0, then we will print information on all hba ports
183*10652SHyon.Kim@Sun.COM  *	wwn_argv - argument array of hba port WWNs
184*10652SHyon.Kim@Sun.COM  *	options - any options specified by the caller
185*10652SHyon.Kim@Sun.COM  *
186*10652SHyon.Kim@Sun.COM  * returns:
187*10652SHyon.Kim@Sun.COM  *	0	if successful
188*10652SHyon.Kim@Sun.COM  *	>0	otherwise
189*10652SHyon.Kim@Sun.COM  */
190*10652SHyon.Kim@Sun.COM int
sas_util_list_hba(int hbaCount,char ** hba_argv,cmdOptions_t * options)191*10652SHyon.Kim@Sun.COM sas_util_list_hba(int hbaCount, char **hba_argv, cmdOptions_t *options)
192*10652SHyon.Kim@Sun.COM {
193*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
194*10652SHyon.Kim@Sun.COM 	int			processHBA_flags = 0;
195*10652SHyon.Kim@Sun.COM 	inputArg_t		input;
196*10652SHyon.Kim@Sun.COM 	int 			err_cnt = 0;
197*10652SHyon.Kim@Sun.COM 
198*10652SHyon.Kim@Sun.COM 	/* process each of the options */
199*10652SHyon.Kim@Sun.COM 	for (; options->optval; options++) {
200*10652SHyon.Kim@Sun.COM 		switch (options->optval) {
201*10652SHyon.Kim@Sun.COM 		case 'v':
202*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_VERBOSE;
203*10652SHyon.Kim@Sun.COM 			break;
204*10652SHyon.Kim@Sun.COM 		default:
205*10652SHyon.Kim@Sun.COM 			break;
206*10652SHyon.Kim@Sun.COM 		}
207*10652SHyon.Kim@Sun.COM 	}
208*10652SHyon.Kim@Sun.COM 
209*10652SHyon.Kim@Sun.COM 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
210*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %s\n",
211*10652SHyon.Kim@Sun.COM 		    gettext("Failed to load SM-HBA libraries."
212*10652SHyon.Kim@Sun.COM 		    "Reason:"), getHBAStatus(status));
213*10652SHyon.Kim@Sun.COM 		err_cnt++;
214*10652SHyon.Kim@Sun.COM 		return (err_cnt);
215*10652SHyon.Kim@Sun.COM 	}
216*10652SHyon.Kim@Sun.COM 
217*10652SHyon.Kim@Sun.COM 	(void *) memset(&input, 0, sizeof (input));
218*10652SHyon.Kim@Sun.COM 	/* utilize wwnCount and wwn_argv for hbaCount and hba_argv */
219*10652SHyon.Kim@Sun.COM 	input.wwnCount = hbaCount;
220*10652SHyon.Kim@Sun.COM 	input.wwn_argv = hba_argv;
221*10652SHyon.Kim@Sun.COM 	input.pflag = processHBA_flags;
222*10652SHyon.Kim@Sun.COM 
223*10652SHyon.Kim@Sun.COM 	/*
224*10652SHyon.Kim@Sun.COM 	 * Process and filter for every local hba,
225*10652SHyon.Kim@Sun.COM 	 * when the hba is not specificed, print all hba(s).
226*10652SHyon.Kim@Sun.COM 	 */
227*10652SHyon.Kim@Sun.COM 	err_cnt += processHBA(&input, NULL);
228*10652SHyon.Kim@Sun.COM 
229*10652SHyon.Kim@Sun.COM 	(void) HBA_FreeLibrary();
230*10652SHyon.Kim@Sun.COM 
231*10652SHyon.Kim@Sun.COM 	return (err_cnt);
232*10652SHyon.Kim@Sun.COM }
233*10652SHyon.Kim@Sun.COM 
234*10652SHyon.Kim@Sun.COM /*
235*10652SHyon.Kim@Sun.COM  * function for hba-port subcommand
236*10652SHyon.Kim@Sun.COM  *
237*10652SHyon.Kim@Sun.COM  * Arguments:
238*10652SHyon.Kim@Sun.COM  *	wwnCount - count of the number of WWNs in wwn_argv
239*10652SHyon.Kim@Sun.COM  *	    if wwnCount > 0, then we will only print information for
240*10652SHyon.Kim@Sun.COM  *		the hba ports listed in wwn_argv
241*10652SHyon.Kim@Sun.COM  *	    if wwnCount == 0, then we will print information on all hba ports
242*10652SHyon.Kim@Sun.COM  *	wwn_argv - argument array of hba port WWNs
243*10652SHyon.Kim@Sun.COM  *	options - any options specified by the caller
244*10652SHyon.Kim@Sun.COM  *
245*10652SHyon.Kim@Sun.COM  * returns:
246*10652SHyon.Kim@Sun.COM  *	0	if successful
247*10652SHyon.Kim@Sun.COM  *	>0	otherwise
248*10652SHyon.Kim@Sun.COM  */
249*10652SHyon.Kim@Sun.COM int
sas_util_list_hbaport(int wwnCount,char ** wwn_argv,cmdOptions_t * options)250*10652SHyon.Kim@Sun.COM sas_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
251*10652SHyon.Kim@Sun.COM {
252*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
253*10652SHyon.Kim@Sun.COM 	int			processHBA_flags = 0;
254*10652SHyon.Kim@Sun.COM 	inputArg_t		input;
255*10652SHyon.Kim@Sun.COM 	int 			err_cnt = 0;
256*10652SHyon.Kim@Sun.COM 	char			hbaName[256] = {'\0'};
257*10652SHyon.Kim@Sun.COM 
258*10652SHyon.Kim@Sun.COM 	/* process each of the options */
259*10652SHyon.Kim@Sun.COM 	for (; options->optval; options++) {
260*10652SHyon.Kim@Sun.COM 		switch (options->optval) {
261*10652SHyon.Kim@Sun.COM 		case 'a':
262*10652SHyon.Kim@Sun.COM 			(void *) strlcpy(hbaName,
263*10652SHyon.Kim@Sun.COM 			    options->optarg, sizeof (hbaName));
264*10652SHyon.Kim@Sun.COM 			break;
265*10652SHyon.Kim@Sun.COM 		case 'y':
266*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_PHY;
267*10652SHyon.Kim@Sun.COM 			break;
268*10652SHyon.Kim@Sun.COM 		case 'l':
269*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_PHY_LINKSTAT;
270*10652SHyon.Kim@Sun.COM 			break;
271*10652SHyon.Kim@Sun.COM 		case 'v':
272*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_VERBOSE;
273*10652SHyon.Kim@Sun.COM 			break;
274*10652SHyon.Kim@Sun.COM 		default:
275*10652SHyon.Kim@Sun.COM 			break;
276*10652SHyon.Kim@Sun.COM 		}
277*10652SHyon.Kim@Sun.COM 	}
278*10652SHyon.Kim@Sun.COM 
279*10652SHyon.Kim@Sun.COM 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
280*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %s\n",
281*10652SHyon.Kim@Sun.COM 		    gettext("Failed to load SM-HBA libraries."
282*10652SHyon.Kim@Sun.COM 		    "Reason:"), getHBAStatus(status));
283*10652SHyon.Kim@Sun.COM 		err_cnt++;
284*10652SHyon.Kim@Sun.COM 		return (err_cnt);
285*10652SHyon.Kim@Sun.COM 	}
286*10652SHyon.Kim@Sun.COM 
287*10652SHyon.Kim@Sun.COM 	(void *) memset(&input, 0, sizeof (input));
288*10652SHyon.Kim@Sun.COM 	input.wwnCount = wwnCount;
289*10652SHyon.Kim@Sun.COM 	input.wwn_argv = wwn_argv;
290*10652SHyon.Kim@Sun.COM 	input.hbaName = hbaName;
291*10652SHyon.Kim@Sun.COM 	input.pflag = processHBA_flags;
292*10652SHyon.Kim@Sun.COM 
293*10652SHyon.Kim@Sun.COM 	/*
294*10652SHyon.Kim@Sun.COM 	 * Process and filter for every local hba-port,
295*10652SHyon.Kim@Sun.COM 	 * when the hba-port is not specificed, print all hba-port(s).
296*10652SHyon.Kim@Sun.COM 	 */
297*10652SHyon.Kim@Sun.COM 	err_cnt += processHBA(&input, handleHBAPort);
298*10652SHyon.Kim@Sun.COM 
299*10652SHyon.Kim@Sun.COM 	(void) HBA_FreeLibrary();
300*10652SHyon.Kim@Sun.COM 
301*10652SHyon.Kim@Sun.COM 	return (err_cnt);
302*10652SHyon.Kim@Sun.COM }
303*10652SHyon.Kim@Sun.COM 
304*10652SHyon.Kim@Sun.COM /*
305*10652SHyon.Kim@Sun.COM  * function for expander subcommand
306*10652SHyon.Kim@Sun.COM  *
307*10652SHyon.Kim@Sun.COM  * Arguments:
308*10652SHyon.Kim@Sun.COM  *	wwnCount - the number of Remote Port SAS Address in wwn_argv
309*10652SHyon.Kim@Sun.COM  *	    if wwnCount == 0, then print information on all
310*10652SHyon.Kim@Sun.COM  *		expander devices.
311*10652SHyon.Kim@Sun.COM  *	    if wwnCount > 0, then print information for the exapnders
312*10652SHyon.Kim@Sun.COM  *		given in wwn_argv.
313*10652SHyon.Kim@Sun.COM  *	wwn_argv - array of WWNs
314*10652SHyon.Kim@Sun.COM  *	options - options specified by the caller
315*10652SHyon.Kim@Sun.COM  *
316*10652SHyon.Kim@Sun.COM  * returns:
317*10652SHyon.Kim@Sun.COM  *	0	if successful
318*10652SHyon.Kim@Sun.COM  *	>0	otherwise
319*10652SHyon.Kim@Sun.COM  */
320*10652SHyon.Kim@Sun.COM int
sas_util_list_expander(int wwnCount,char ** wwn_argv,cmdOptions_t * options)321*10652SHyon.Kim@Sun.COM sas_util_list_expander(int wwnCount, char **wwn_argv, cmdOptions_t *options)
322*10652SHyon.Kim@Sun.COM {
323*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
324*10652SHyon.Kim@Sun.COM 	int			processHBA_flags = 0;
325*10652SHyon.Kim@Sun.COM 	char			hbaPort[MAXPATHLEN + 1] = {0};
326*10652SHyon.Kim@Sun.COM 	inputArg_t		input;
327*10652SHyon.Kim@Sun.COM 	int			err_cnt = 0;
328*10652SHyon.Kim@Sun.COM 
329*10652SHyon.Kim@Sun.COM 	/* process each of the options */
330*10652SHyon.Kim@Sun.COM 	for (; options->optval; options++) {
331*10652SHyon.Kim@Sun.COM 		switch (options->optval) {
332*10652SHyon.Kim@Sun.COM 		case 'p':
333*10652SHyon.Kim@Sun.COM 			(void) strlcpy(hbaPort, options->optarg,
334*10652SHyon.Kim@Sun.COM 			    sizeof (hbaPort));
335*10652SHyon.Kim@Sun.COM 			break;
336*10652SHyon.Kim@Sun.COM 		case 't':
337*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_TARGET_PORT;
338*10652SHyon.Kim@Sun.COM 			break;
339*10652SHyon.Kim@Sun.COM 		case 'v':
340*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_VERBOSE;
341*10652SHyon.Kim@Sun.COM 			break;
342*10652SHyon.Kim@Sun.COM 		default:
343*10652SHyon.Kim@Sun.COM 			break;
344*10652SHyon.Kim@Sun.COM 		}
345*10652SHyon.Kim@Sun.COM 	}
346*10652SHyon.Kim@Sun.COM 
347*10652SHyon.Kim@Sun.COM 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
348*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %s\n",
349*10652SHyon.Kim@Sun.COM 		    gettext("Failed to load SM-HBA libraries."
350*10652SHyon.Kim@Sun.COM 		    "Reason:"), getHBAStatus(status));
351*10652SHyon.Kim@Sun.COM 		err_cnt++;
352*10652SHyon.Kim@Sun.COM 		return (err_cnt);
353*10652SHyon.Kim@Sun.COM 	}
354*10652SHyon.Kim@Sun.COM 
355*10652SHyon.Kim@Sun.COM 	(void *) memset(&input, 0, sizeof (input));
356*10652SHyon.Kim@Sun.COM 	input.wwnCount = wwnCount;
357*10652SHyon.Kim@Sun.COM 	input.wwn_argv = wwn_argv;
358*10652SHyon.Kim@Sun.COM 	input.pflag = processHBA_flags;
359*10652SHyon.Kim@Sun.COM 	input.hbaName = hbaPort;
360*10652SHyon.Kim@Sun.COM 
361*10652SHyon.Kim@Sun.COM 	/*
362*10652SHyon.Kim@Sun.COM 	 * Process and filter for every hba-port,
363*10652SHyon.Kim@Sun.COM 	 * when the hba-port is not specificed, print all hba-port(s).
364*10652SHyon.Kim@Sun.COM 	 */
365*10652SHyon.Kim@Sun.COM 	err_cnt += processHBA(&input, handleExpander);
366*10652SHyon.Kim@Sun.COM 
367*10652SHyon.Kim@Sun.COM 	(void) HBA_FreeLibrary();
368*10652SHyon.Kim@Sun.COM 
369*10652SHyon.Kim@Sun.COM 	return (err_cnt);
370*10652SHyon.Kim@Sun.COM }
371*10652SHyon.Kim@Sun.COM 
372*10652SHyon.Kim@Sun.COM /*
373*10652SHyon.Kim@Sun.COM  * function for target-port subcommand
374*10652SHyon.Kim@Sun.COM  *
375*10652SHyon.Kim@Sun.COM  * Arguments:
376*10652SHyon.Kim@Sun.COM  *	wwnCount - the number of Remote Port SAS Address in wwn_argv
377*10652SHyon.Kim@Sun.COM  *	    if wwnCount == 0, then print information on all
378*10652SHyon.Kim@Sun.COM  *		target ports.
379*10652SHyon.Kim@Sun.COM  *	    if wwnCount > 0, then print information for the target ports
380*10652SHyon.Kim@Sun.COM  *		given in wwn_argv.
381*10652SHyon.Kim@Sun.COM  *	wwn_argv - array of WWNs
382*10652SHyon.Kim@Sun.COM  *	options - options specified by the caller
383*10652SHyon.Kim@Sun.COM  *
384*10652SHyon.Kim@Sun.COM  * returns:
385*10652SHyon.Kim@Sun.COM  *	0	if successful
386*10652SHyon.Kim@Sun.COM  *	>0	otherwise
387*10652SHyon.Kim@Sun.COM  */
388*10652SHyon.Kim@Sun.COM int
sas_util_list_targetport(int tpCount,char ** tpArgv,cmdOptions_t * options)389*10652SHyon.Kim@Sun.COM sas_util_list_targetport(int tpCount, char **tpArgv, cmdOptions_t *options)
390*10652SHyon.Kim@Sun.COM {
391*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
392*10652SHyon.Kim@Sun.COM 	int			processHBA_flags = 0;
393*10652SHyon.Kim@Sun.COM 	int			tp, tpFound;
394*10652SHyon.Kim@Sun.COM 	inputArg_t		input;
395*10652SHyon.Kim@Sun.COM 	targetPortList_t	*tpListWalk;
396*10652SHyon.Kim@Sun.COM 	int			err_cnt = 0;
397*10652SHyon.Kim@Sun.COM 	uint64_t		tmpAddr;
398*10652SHyon.Kim@Sun.COM 
399*10652SHyon.Kim@Sun.COM 	/* process each of the options */
400*10652SHyon.Kim@Sun.COM 	for (; options->optval; options++) {
401*10652SHyon.Kim@Sun.COM 		switch (options->optval) {
402*10652SHyon.Kim@Sun.COM 		case 's':
403*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_TARGET_SCSI;
404*10652SHyon.Kim@Sun.COM 			break;
405*10652SHyon.Kim@Sun.COM 		case 'v':
406*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_VERBOSE;
407*10652SHyon.Kim@Sun.COM 			break;
408*10652SHyon.Kim@Sun.COM 		default:
409*10652SHyon.Kim@Sun.COM 			break;
410*10652SHyon.Kim@Sun.COM 		}
411*10652SHyon.Kim@Sun.COM 	}
412*10652SHyon.Kim@Sun.COM 
413*10652SHyon.Kim@Sun.COM 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
414*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %s\n",
415*10652SHyon.Kim@Sun.COM 		    gettext("Failed to load SM-HBA libraries."
416*10652SHyon.Kim@Sun.COM 		    "Reason:"), getHBAStatus(status));
417*10652SHyon.Kim@Sun.COM 		err_cnt++;
418*10652SHyon.Kim@Sun.COM 		return (err_cnt);
419*10652SHyon.Kim@Sun.COM 	}
420*10652SHyon.Kim@Sun.COM 
421*10652SHyon.Kim@Sun.COM 	(void *) memset(&input, 0, sizeof (input));
422*10652SHyon.Kim@Sun.COM 	input.wwnCount = tpCount;
423*10652SHyon.Kim@Sun.COM 	input.wwn_argv = tpArgv;
424*10652SHyon.Kim@Sun.COM 	input.pflag = processHBA_flags;
425*10652SHyon.Kim@Sun.COM 
426*10652SHyon.Kim@Sun.COM 	/*
427*10652SHyon.Kim@Sun.COM 	 * Process and filter for every hba-port,
428*10652SHyon.Kim@Sun.COM 	 * when the hba-port is not specificed, print all hba-port(s).
429*10652SHyon.Kim@Sun.COM 	 */
430*10652SHyon.Kim@Sun.COM 	err_cnt += processHBA(&input, handleTargetPort);
431*10652SHyon.Kim@Sun.COM 
432*10652SHyon.Kim@Sun.COM 	if (tpCount == 0) {
433*10652SHyon.Kim@Sun.COM 		/* list all target port */
434*10652SHyon.Kim@Sun.COM 		for (tpListWalk = gTargetPortList; tpListWalk != NULL;
435*10652SHyon.Kim@Sun.COM 		    tpListWalk = tpListWalk->next) {
436*10652SHyon.Kim@Sun.COM 			err_cnt += printTargetPortInfo(tpListWalk, input.pflag);
437*10652SHyon.Kim@Sun.COM 		}
438*10652SHyon.Kim@Sun.COM 	} else {
439*10652SHyon.Kim@Sun.COM 		/*
440*10652SHyon.Kim@Sun.COM 		 * When operands provided, we should set the error code
441*10652SHyon.Kim@Sun.COM 		 * only if there are issues related with the operands.
442*10652SHyon.Kim@Sun.COM 		 */
443*10652SHyon.Kim@Sun.COM 		err_cnt = 0;
444*10652SHyon.Kim@Sun.COM 		/*
445*10652SHyon.Kim@Sun.COM 		 * list any paths not found first
446*10652SHyon.Kim@Sun.COM 		 * this gives the user cleaner output
447*10652SHyon.Kim@Sun.COM 		 */
448*10652SHyon.Kim@Sun.COM 		for (tp = 0; tp < tpCount; tp++) {
449*10652SHyon.Kim@Sun.COM 			errno = 0;
450*10652SHyon.Kim@Sun.COM 			tmpAddr = strtoull(tpArgv[tp], NULL, 16);
451*10652SHyon.Kim@Sun.COM 			if ((tmpAddr == 0) && (errno != 0)) {
452*10652SHyon.Kim@Sun.COM 				err_cnt++;
453*10652SHyon.Kim@Sun.COM 				continue;
454*10652SHyon.Kim@Sun.COM 			}
455*10652SHyon.Kim@Sun.COM 			for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
456*10652SHyon.Kim@Sun.COM 			    tpListWalk != NULL;
457*10652SHyon.Kim@Sun.COM 			    tpListWalk = tpListWalk->next) {
458*10652SHyon.Kim@Sun.COM 				if (wwnConversion(tpListWalk->sasattr.
459*10652SHyon.Kim@Sun.COM 				    LocalSASAddress.wwn) == tmpAddr) {
460*10652SHyon.Kim@Sun.COM 					tpFound = B_TRUE;
461*10652SHyon.Kim@Sun.COM 					break;
462*10652SHyon.Kim@Sun.COM 				}
463*10652SHyon.Kim@Sun.COM 			}
464*10652SHyon.Kim@Sun.COM 			if (tpFound == B_FALSE) {
465*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr,
466*10652SHyon.Kim@Sun.COM 				    "Error: Target Port %s Not Found \n",
467*10652SHyon.Kim@Sun.COM 				    tpArgv[tp]);
468*10652SHyon.Kim@Sun.COM 				err_cnt++;
469*10652SHyon.Kim@Sun.COM 			}
470*10652SHyon.Kim@Sun.COM 		}
471*10652SHyon.Kim@Sun.COM 		/* list all paths requested in order requested */
472*10652SHyon.Kim@Sun.COM 		for (tp = 0; tp < tpCount; tp++) {
473*10652SHyon.Kim@Sun.COM 			errno = 0;
474*10652SHyon.Kim@Sun.COM 			tmpAddr = strtoull(tpArgv[tp], NULL, 16);
475*10652SHyon.Kim@Sun.COM 			if ((tmpAddr == 0) && (errno != 0)) {
476*10652SHyon.Kim@Sun.COM 				continue;
477*10652SHyon.Kim@Sun.COM 			}
478*10652SHyon.Kim@Sun.COM 			for (tpListWalk = gTargetPortList, tpFound = B_FALSE;
479*10652SHyon.Kim@Sun.COM 			    tpListWalk != NULL;
480*10652SHyon.Kim@Sun.COM 			    tpListWalk = tpListWalk->next) {
481*10652SHyon.Kim@Sun.COM 				if (wwnConversion(tpListWalk->sasattr.
482*10652SHyon.Kim@Sun.COM 				    LocalSASAddress.wwn) == tmpAddr) {
483*10652SHyon.Kim@Sun.COM 					err_cnt += printTargetPortInfo(
484*10652SHyon.Kim@Sun.COM 					    tpListWalk,
485*10652SHyon.Kim@Sun.COM 					    processHBA_flags);
486*10652SHyon.Kim@Sun.COM 				}
487*10652SHyon.Kim@Sun.COM 			}
488*10652SHyon.Kim@Sun.COM 		}
489*10652SHyon.Kim@Sun.COM 	}
490*10652SHyon.Kim@Sun.COM 	(void) HBA_FreeLibrary();
491*10652SHyon.Kim@Sun.COM 	return (err_cnt);
492*10652SHyon.Kim@Sun.COM }
493*10652SHyon.Kim@Sun.COM /*
494*10652SHyon.Kim@Sun.COM  * This function will enumerate all the hba and hba ports,
495*10652SHyon.Kim@Sun.COM  * call the callback function to proceed with futher process.
496*10652SHyon.Kim@Sun.COM  *
497*10652SHyon.Kim@Sun.COM  * Arguments:
498*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
499*10652SHyon.Kim@Sun.COM  *	processPort - a callback function when handling each port.
500*10652SHyon.Kim@Sun.COM  *
501*10652SHyon.Kim@Sun.COM  *  Return Value:
502*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
503*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
504*10652SHyon.Kim@Sun.COM  */
505*10652SHyon.Kim@Sun.COM static int
processHBA(inputArg_t * input,processPortFunc processPort)506*10652SHyon.Kim@Sun.COM processHBA(inputArg_t *input, processPortFunc processPort)
507*10652SHyon.Kim@Sun.COM {
508*10652SHyon.Kim@Sun.COM 	int			numAdapters = 0;
509*10652SHyon.Kim@Sun.COM 	int			matchedHBAs = 0;
510*10652SHyon.Kim@Sun.COM 	int			matchedHBAPorts = 0;
511*10652SHyon.Kim@Sun.COM 	int			hbaPortExist = 0;
512*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
513*10652SHyon.Kim@Sun.COM 	HBA_HANDLE		handle;
514*10652SHyon.Kim@Sun.COM 	HBA_UINT32		numberOfPorts = 0;
515*10652SHyon.Kim@Sun.COM 	int			portIndex = 0;
516*10652SHyon.Kim@Sun.COM 	HBA_PORTTYPE		porttype;
517*10652SHyon.Kim@Sun.COM 	SMHBA_LIBRARYATTRIBUTES libattrs;
518*10652SHyon.Kim@Sun.COM 	SMHBA_ADAPTERATTRIBUTES	attrs;
519*10652SHyon.Kim@Sun.COM 	SMHBA_PORTATTRIBUTES	port;
520*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PORT		sasattrs;
521*10652SHyon.Kim@Sun.COM 	int			i, sum, ret = 0;
522*10652SHyon.Kim@Sun.COM 	int			remote_avail = 0;
523*10652SHyon.Kim@Sun.COM 	int			local_avail = 0;
524*10652SHyon.Kim@Sun.COM 	sas_elem_t		*adpt_array = NULL;
525*10652SHyon.Kim@Sun.COM 	sas_elem_t		*port_array = NULL;
526*10652SHyon.Kim@Sun.COM 
527*10652SHyon.Kim@Sun.COM 	numAdapters = HBA_GetNumberOfAdapters();
528*10652SHyon.Kim@Sun.COM 	if (numAdapters == 0) {
529*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
530*10652SHyon.Kim@Sun.COM 		    gettext("Error: No Adapters Found."));
531*10652SHyon.Kim@Sun.COM 		return (++ret);
532*10652SHyon.Kim@Sun.COM 	}
533*10652SHyon.Kim@Sun.COM 
534*10652SHyon.Kim@Sun.COM 	/*
535*10652SHyon.Kim@Sun.COM 	 * To deal with mismatching HBA/HBA Port/Expander Port, we need an
536*10652SHyon.Kim@Sun.COM 	 * array of flags for each operands.
537*10652SHyon.Kim@Sun.COM 	 */
538*10652SHyon.Kim@Sun.COM 	if (input->wwnCount && (processPort != handleTargetPort) &&
539*10652SHyon.Kim@Sun.COM 	    (processPort != handleLogicalUnit)) {
540*10652SHyon.Kim@Sun.COM 		input->wwn_flag = calloc(input->wwnCount, sizeof (int));
541*10652SHyon.Kim@Sun.COM 		if (input->wwn_flag == NULL) {
542*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n",
543*10652SHyon.Kim@Sun.COM 			    gettext("No enough memory on heap"));
544*10652SHyon.Kim@Sun.COM 			return (++ret);
545*10652SHyon.Kim@Sun.COM 		}
546*10652SHyon.Kim@Sun.COM 	}
547*10652SHyon.Kim@Sun.COM 
548*10652SHyon.Kim@Sun.COM 	adpt_array = calloc(numAdapters, sizeof (sas_elem_t));
549*10652SHyon.Kim@Sun.COM 	if (adpt_array == NULL) {
550*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
551*10652SHyon.Kim@Sun.COM 		    gettext("No enough memory on heap"));
552*10652SHyon.Kim@Sun.COM 		if (input->wwn_flag) {
553*10652SHyon.Kim@Sun.COM 			free(input->wwn_flag);
554*10652SHyon.Kim@Sun.COM 			input->wwn_flag = NULL;
555*10652SHyon.Kim@Sun.COM 		}
556*10652SHyon.Kim@Sun.COM 		return (++ret);
557*10652SHyon.Kim@Sun.COM 	}
558*10652SHyon.Kim@Sun.COM 	for (i = 0; i < numAdapters; i++) {
559*10652SHyon.Kim@Sun.COM 		status =
560*10652SHyon.Kim@Sun.COM 		    SMHBA_GetVendorLibraryAttributes(i, &libattrs);
561*10652SHyon.Kim@Sun.COM 		/*
562*10652SHyon.Kim@Sun.COM 		 * If we get SAS incompatible library warning here,
563*10652SHyon.Kim@Sun.COM 		 * just skip the following steps.
564*10652SHyon.Kim@Sun.COM 		 */
565*10652SHyon.Kim@Sun.COM 		if (status != 1) {
566*10652SHyon.Kim@Sun.COM 			continue;
567*10652SHyon.Kim@Sun.COM 		}
568*10652SHyon.Kim@Sun.COM 		status = HBA_GetAdapterName(i, adpt_array[i].name);
569*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
570*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s %d %s %s\n",
571*10652SHyon.Kim@Sun.COM 			    gettext("Error: Failed to get the name for"
572*10652SHyon.Kim@Sun.COM 			    " HBA index"),
573*10652SHyon.Kim@Sun.COM 			    i, gettext("Reason:"),
574*10652SHyon.Kim@Sun.COM 			    getHBAStatus(status));
575*10652SHyon.Kim@Sun.COM 			ret++;
576*10652SHyon.Kim@Sun.COM 			continue;
577*10652SHyon.Kim@Sun.COM 		}
578*10652SHyon.Kim@Sun.COM 		adpt_array[i].index = i;
579*10652SHyon.Kim@Sun.COM 	}
580*10652SHyon.Kim@Sun.COM 	/* Sort the HBA Name in place. */
581*10652SHyon.Kim@Sun.COM 	sas_elem_sort(adpt_array, numAdapters);
582*10652SHyon.Kim@Sun.COM 
583*10652SHyon.Kim@Sun.COM 	for (i = 0; i < numAdapters; i++) {
584*10652SHyon.Kim@Sun.COM 		int times = 0;
585*10652SHyon.Kim@Sun.COM 		if (adpt_array[i].name[0] != '\0') {
586*10652SHyon.Kim@Sun.COM 			if ((handle = HBA_OpenAdapter(adpt_array[i].name))
587*10652SHyon.Kim@Sun.COM 			    == 0) {
588*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr, "%s %s.\n",
589*10652SHyon.Kim@Sun.COM 				    gettext("Error: Failed to open adapter"),
590*10652SHyon.Kim@Sun.COM 				    adpt_array[i].name);
591*10652SHyon.Kim@Sun.COM 				ret++;
592*10652SHyon.Kim@Sun.COM 				continue;
593*10652SHyon.Kim@Sun.COM 			}
594*10652SHyon.Kim@Sun.COM 		} else {
595*10652SHyon.Kim@Sun.COM 			continue;
596*10652SHyon.Kim@Sun.COM 		}
597*10652SHyon.Kim@Sun.COM 
598*10652SHyon.Kim@Sun.COM 		/*
599*10652SHyon.Kim@Sun.COM 		 * We need to support an adapter without hba port.
600*10652SHyon.Kim@Sun.COM 		 * So get attributes anyway.
601*10652SHyon.Kim@Sun.COM 		 */
602*10652SHyon.Kim@Sun.COM 		(void *) memset(&attrs, 0, sizeof (attrs));
603*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetAdapterAttributes(handle, &attrs);
604*10652SHyon.Kim@Sun.COM 		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
605*10652SHyon.Kim@Sun.COM 		    status == HBA_STATUS_ERROR_BUSY) &&
606*10652SHyon.Kim@Sun.COM 		    times++ < HBA_MAX_RETRIES) {
607*10652SHyon.Kim@Sun.COM 			(void) sleep(1);
608*10652SHyon.Kim@Sun.COM 			status = SMHBA_GetAdapterAttributes(handle,
609*10652SHyon.Kim@Sun.COM 			    &attrs);
610*10652SHyon.Kim@Sun.COM 		}
611*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
612*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s %s %s %s\n",
613*10652SHyon.Kim@Sun.COM 			    gettext("Error: Failed to get attributes"
614*10652SHyon.Kim@Sun.COM 			    " for HBA "), adpt_array[i].name,
615*10652SHyon.Kim@Sun.COM 			    gettext("Reason:"),
616*10652SHyon.Kim@Sun.COM 			    getHBAStatus(status));
617*10652SHyon.Kim@Sun.COM 
618*10652SHyon.Kim@Sun.COM 			HBA_CloseAdapter(handle);
619*10652SHyon.Kim@Sun.COM 			ret++;
620*10652SHyon.Kim@Sun.COM 			continue;
621*10652SHyon.Kim@Sun.COM 		}
622*10652SHyon.Kim@Sun.COM 
623*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetNumberOfPorts(handle, &numberOfPorts);
624*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
625*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s %s %s %s\n",
626*10652SHyon.Kim@Sun.COM 			    gettext("Error: Failed to get number of ports "
627*10652SHyon.Kim@Sun.COM 			    "for HBA"), adpt_array[i].name,
628*10652SHyon.Kim@Sun.COM 			    gettext("Reason:"),
629*10652SHyon.Kim@Sun.COM 			    getHBAStatus(status));
630*10652SHyon.Kim@Sun.COM 			HBA_CloseAdapter(handle);
631*10652SHyon.Kim@Sun.COM 			ret++;
632*10652SHyon.Kim@Sun.COM 			continue;
633*10652SHyon.Kim@Sun.COM 		}
634*10652SHyon.Kim@Sun.COM 
635*10652SHyon.Kim@Sun.COM 		/*
636*10652SHyon.Kim@Sun.COM 		 * Deal with each subcommand for hba filter here,
637*10652SHyon.Kim@Sun.COM 		 * processPort is NULL for hba subcommand.
638*10652SHyon.Kim@Sun.COM 		 */
639*10652SHyon.Kim@Sun.COM 		if (processPort == NULL) {
640*10652SHyon.Kim@Sun.COM 			matchedHBAs += handleHBA(&attrs, input,
641*10652SHyon.Kim@Sun.COM 			    numberOfPorts, adpt_array[i].name);
642*10652SHyon.Kim@Sun.COM 			HBA_CloseAdapter(handle);
643*10652SHyon.Kim@Sun.COM 			continue;
644*10652SHyon.Kim@Sun.COM 		} else if (processPort == handleHBAPort) {
645*10652SHyon.Kim@Sun.COM 			if (input->hbaName[0] != '\0') {
646*10652SHyon.Kim@Sun.COM 				if (strcmp(input->hbaName,
647*10652SHyon.Kim@Sun.COM 				    adpt_array[i].name) == 0) {
648*10652SHyon.Kim@Sun.COM 					matchedHBAs++;
649*10652SHyon.Kim@Sun.COM 				} else {
650*10652SHyon.Kim@Sun.COM 					continue;
651*10652SHyon.Kim@Sun.COM 				}
652*10652SHyon.Kim@Sun.COM 			} else {
653*10652SHyon.Kim@Sun.COM 				matchedHBAs++;
654*10652SHyon.Kim@Sun.COM 			}
655*10652SHyon.Kim@Sun.COM 		} else {
656*10652SHyon.Kim@Sun.COM 			matchedHBAs++;
657*10652SHyon.Kim@Sun.COM 		}
658*10652SHyon.Kim@Sun.COM 
659*10652SHyon.Kim@Sun.COM 		/*
660*10652SHyon.Kim@Sun.COM 		 * In order to have a sorted output for HBA Port, we should
661*10652SHyon.Kim@Sun.COM 		 * do the sorting before moving on.
662*10652SHyon.Kim@Sun.COM 		 */
663*10652SHyon.Kim@Sun.COM 		if (numberOfPorts) {
664*10652SHyon.Kim@Sun.COM 			port_array = calloc(numberOfPorts, sizeof (sas_elem_t));
665*10652SHyon.Kim@Sun.COM 		}
666*10652SHyon.Kim@Sun.COM 		for (portIndex = 0; portIndex < numberOfPorts; portIndex++) {
667*10652SHyon.Kim@Sun.COM 			if ((status = SMHBA_GetPortType(handle,
668*10652SHyon.Kim@Sun.COM 			    portIndex, &porttype)) != HBA_STATUS_OK) {
669*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr, "%s %s %s %s\n",
670*10652SHyon.Kim@Sun.COM 				    gettext("Failed to get adapter port type "
671*10652SHyon.Kim@Sun.COM 				    "for HBA"), adpt_array[i].name,
672*10652SHyon.Kim@Sun.COM 				    gettext("Reason:"),
673*10652SHyon.Kim@Sun.COM 				    getHBAStatus(status));
674*10652SHyon.Kim@Sun.COM 				ret++;
675*10652SHyon.Kim@Sun.COM 				continue;
676*10652SHyon.Kim@Sun.COM 			}
677*10652SHyon.Kim@Sun.COM 			if (porttype != HBA_PORTTYPE_SASDEVICE) {
678*10652SHyon.Kim@Sun.COM 				/* skip any non-sas hba port */
679*10652SHyon.Kim@Sun.COM 				continue;
680*10652SHyon.Kim@Sun.COM 			}
681*10652SHyon.Kim@Sun.COM 			(void *) memset(&port, 0, sizeof (port));
682*10652SHyon.Kim@Sun.COM 			(void *) memset(&sasattrs, 0, sizeof (sasattrs));
683*10652SHyon.Kim@Sun.COM 			port.PortSpecificAttribute.SASPort = &sasattrs;
684*10652SHyon.Kim@Sun.COM 			if ((status = SMHBA_GetAdapterPortAttributes(
685*10652SHyon.Kim@Sun.COM 			    handle, portIndex, &port)) != HBA_STATUS_OK) {
686*10652SHyon.Kim@Sun.COM 				/*
687*10652SHyon.Kim@Sun.COM 				 * Not able to get port attributes.
688*10652SHyon.Kim@Sun.COM 				 * print out error message and
689*10652SHyon.Kim@Sun.COM 				 * move on to the next port
690*10652SHyon.Kim@Sun.COM 				 */
691*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr, "%s %s %s %d %s %s\n",
692*10652SHyon.Kim@Sun.COM 				    gettext("Error: Failed to get port "
693*10652SHyon.Kim@Sun.COM 				    "attributes for HBA"), adpt_array[i].name,
694*10652SHyon.Kim@Sun.COM 				    gettext("port index"), portIndex,
695*10652SHyon.Kim@Sun.COM 				    gettext("Reason:"),
696*10652SHyon.Kim@Sun.COM 				    getHBAStatus(status));
697*10652SHyon.Kim@Sun.COM 				ret++;
698*10652SHyon.Kim@Sun.COM 				continue;
699*10652SHyon.Kim@Sun.COM 			}
700*10652SHyon.Kim@Sun.COM 			(void) strlcpy(port_array[portIndex].name,
701*10652SHyon.Kim@Sun.COM 			    port.OSDeviceName,
702*10652SHyon.Kim@Sun.COM 			    sizeof (port_array[portIndex].name));
703*10652SHyon.Kim@Sun.COM 			port_array[portIndex].index = portIndex;
704*10652SHyon.Kim@Sun.COM 		}
705*10652SHyon.Kim@Sun.COM 		/* Sort the HBA Port Name here. */
706*10652SHyon.Kim@Sun.COM 		if (port_array) {
707*10652SHyon.Kim@Sun.COM 			sas_elem_sort(port_array, numberOfPorts);
708*10652SHyon.Kim@Sun.COM 		}
709*10652SHyon.Kim@Sun.COM 		/*
710*10652SHyon.Kim@Sun.COM 		 * Sum up the local hba ports available.
711*10652SHyon.Kim@Sun.COM 		 */
712*10652SHyon.Kim@Sun.COM 		local_avail += numberOfPorts;
713*10652SHyon.Kim@Sun.COM 
714*10652SHyon.Kim@Sun.COM 		/*
715*10652SHyon.Kim@Sun.COM 		 * Clear g_printHBA flag for expander subcommand.
716*10652SHyon.Kim@Sun.COM 		 */
717*10652SHyon.Kim@Sun.COM 		g_printHBA = 0;
718*10652SHyon.Kim@Sun.COM 
719*10652SHyon.Kim@Sun.COM 		/* process each port on the given adapter */
720*10652SHyon.Kim@Sun.COM 		for (portIndex = 0;
721*10652SHyon.Kim@Sun.COM 		    portIndex < numberOfPorts;
722*10652SHyon.Kim@Sun.COM 		    portIndex++) {
723*10652SHyon.Kim@Sun.COM 			/*
724*10652SHyon.Kim@Sun.COM 			 * We only handle the port which is valid.
725*10652SHyon.Kim@Sun.COM 			 */
726*10652SHyon.Kim@Sun.COM 			if (port_array[portIndex].name[0] == '\0') {
727*10652SHyon.Kim@Sun.COM 				continue;
728*10652SHyon.Kim@Sun.COM 			}
729*10652SHyon.Kim@Sun.COM 			(void *) memset(&port, 0, sizeof (port));
730*10652SHyon.Kim@Sun.COM 			(void *) memset(&sasattrs, 0, sizeof (sasattrs));
731*10652SHyon.Kim@Sun.COM 			port.PortSpecificAttribute.SASPort = &sasattrs;
732*10652SHyon.Kim@Sun.COM 
733*10652SHyon.Kim@Sun.COM 			(void) SMHBA_GetAdapterPortAttributes(handle,
734*10652SHyon.Kim@Sun.COM 			    port_array[portIndex].index, &port);
735*10652SHyon.Kim@Sun.COM 
736*10652SHyon.Kim@Sun.COM 			/*
737*10652SHyon.Kim@Sun.COM 			 * We have different things to do for the three
738*10652SHyon.Kim@Sun.COM 			 * sub-commands here.
739*10652SHyon.Kim@Sun.COM 			 */
740*10652SHyon.Kim@Sun.COM 			if (processPort == handleHBAPort) {
741*10652SHyon.Kim@Sun.COM 				/*
742*10652SHyon.Kim@Sun.COM 				 * For hba-port, we will check whether the
743*10652SHyon.Kim@Sun.COM 				 * specified hba port exist first.
744*10652SHyon.Kim@Sun.COM 				 * But if no hba port specified, we should
745*10652SHyon.Kim@Sun.COM 				 * by pass this check(just let hbaPortExist
746*10652SHyon.Kim@Sun.COM 				 * be 1).
747*10652SHyon.Kim@Sun.COM 				 */
748*10652SHyon.Kim@Sun.COM 				if (input->wwnCount > 0) {
749*10652SHyon.Kim@Sun.COM 					if (isStringInArgv(input,
750*10652SHyon.Kim@Sun.COM 					    port.OSDeviceName)) {
751*10652SHyon.Kim@Sun.COM 						hbaPortExist = 1;
752*10652SHyon.Kim@Sun.COM 						if (g_printHBA == 0) {
753*10652SHyon.Kim@Sun.COM 							(void *) fprintf(stdout,
754*10652SHyon.Kim@Sun.COM 							    "%s %s\n",
755*10652SHyon.Kim@Sun.COM 							    "HBA Name:",
756*10652SHyon.Kim@Sun.COM 							    adpt_array[i].name);
757*10652SHyon.Kim@Sun.COM 							g_printHBA = 1;
758*10652SHyon.Kim@Sun.COM 						}
759*10652SHyon.Kim@Sun.COM 					}
760*10652SHyon.Kim@Sun.COM 				} else {
761*10652SHyon.Kim@Sun.COM 					hbaPortExist = 1;
762*10652SHyon.Kim@Sun.COM 					if (g_printHBA == 0) {
763*10652SHyon.Kim@Sun.COM 						(void *) fprintf(stdout,
764*10652SHyon.Kim@Sun.COM 						    "%s %s\n",
765*10652SHyon.Kim@Sun.COM 						    "HBA Name:",
766*10652SHyon.Kim@Sun.COM 						    adpt_array[i].name);
767*10652SHyon.Kim@Sun.COM 						g_printHBA = 1;
768*10652SHyon.Kim@Sun.COM 					}
769*10652SHyon.Kim@Sun.COM 				}
770*10652SHyon.Kim@Sun.COM 			}
771*10652SHyon.Kim@Sun.COM 
772*10652SHyon.Kim@Sun.COM 			if (processPort == handleExpander) {
773*10652SHyon.Kim@Sun.COM 				/*
774*10652SHyon.Kim@Sun.COM 				 * For expander device, input->hbaName is
775*10652SHyon.Kim@Sun.COM 				 * the hba port name specified on the
776*10652SHyon.Kim@Sun.COM 				 * command line(with -p option).
777*10652SHyon.Kim@Sun.COM 				 */
778*10652SHyon.Kim@Sun.COM 				if (input->hbaName[0] != '\0') {
779*10652SHyon.Kim@Sun.COM 					if (strcmp(input->hbaName,
780*10652SHyon.Kim@Sun.COM 					    port.OSDeviceName) == 0)
781*10652SHyon.Kim@Sun.COM 						hbaPortExist = 1;
782*10652SHyon.Kim@Sun.COM 				} else
783*10652SHyon.Kim@Sun.COM 					hbaPortExist = 1;
784*10652SHyon.Kim@Sun.COM 			}
785*10652SHyon.Kim@Sun.COM 
786*10652SHyon.Kim@Sun.COM 			if (processPort == handleTargetPort) {
787*10652SHyon.Kim@Sun.COM 				/*
788*10652SHyon.Kim@Sun.COM 				 * For target port, we don't need to check the
789*10652SHyon.Kim@Sun.COM 				 * hba port address, so let it go here.
790*10652SHyon.Kim@Sun.COM 				 */
791*10652SHyon.Kim@Sun.COM 				hbaPortExist = 1;
792*10652SHyon.Kim@Sun.COM 			}
793*10652SHyon.Kim@Sun.COM 
794*10652SHyon.Kim@Sun.COM 			if (processPort == handleLogicalUnit) {
795*10652SHyon.Kim@Sun.COM 				/*
796*10652SHyon.Kim@Sun.COM 				 * For lu, we don't need to check the hba
797*10652SHyon.Kim@Sun.COM 				 * port address, so let it go here.
798*10652SHyon.Kim@Sun.COM 				 */
799*10652SHyon.Kim@Sun.COM 				hbaPortExist = 1;
800*10652SHyon.Kim@Sun.COM 			}
801*10652SHyon.Kim@Sun.COM 
802*10652SHyon.Kim@Sun.COM 			if (hbaPortExist) {
803*10652SHyon.Kim@Sun.COM 				if (port.PortSpecificAttribute.SASPort->
804*10652SHyon.Kim@Sun.COM 				    NumberofDiscoveredPorts) {
805*10652SHyon.Kim@Sun.COM 					remote_avail++;
806*10652SHyon.Kim@Sun.COM 				}
807*10652SHyon.Kim@Sun.COM 				ret += (*processPort)(handle,
808*10652SHyon.Kim@Sun.COM 				    adpt_array[i].name,
809*10652SHyon.Kim@Sun.COM 				    port_array[portIndex].index, &port,
810*10652SHyon.Kim@Sun.COM 				    &attrs, input);
811*10652SHyon.Kim@Sun.COM 				/*
812*10652SHyon.Kim@Sun.COM 				 * We should reset the hbaPortExist flag
813*10652SHyon.Kim@Sun.COM 				 * here for next round of check and count
814*10652SHyon.Kim@Sun.COM 				 * for the machedHBAPorts.
815*10652SHyon.Kim@Sun.COM 				 */
816*10652SHyon.Kim@Sun.COM 				hbaPortExist = 0;
817*10652SHyon.Kim@Sun.COM 				matchedHBAPorts++;
818*10652SHyon.Kim@Sun.COM 			}
819*10652SHyon.Kim@Sun.COM 		}
820*10652SHyon.Kim@Sun.COM 		if (port_array) {
821*10652SHyon.Kim@Sun.COM 			free(port_array);
822*10652SHyon.Kim@Sun.COM 			port_array = NULL;
823*10652SHyon.Kim@Sun.COM 		}
824*10652SHyon.Kim@Sun.COM 		HBA_CloseAdapter(handle);
825*10652SHyon.Kim@Sun.COM 	}
826*10652SHyon.Kim@Sun.COM 	if (adpt_array) {
827*10652SHyon.Kim@Sun.COM 		free(adpt_array);
828*10652SHyon.Kim@Sun.COM 		adpt_array = NULL;
829*10652SHyon.Kim@Sun.COM 	}
830*10652SHyon.Kim@Sun.COM 
831*10652SHyon.Kim@Sun.COM 	/*
832*10652SHyon.Kim@Sun.COM 	 * When we are here, we have traversed all the hba and hba ports.
833*10652SHyon.Kim@Sun.COM 	 */
834*10652SHyon.Kim@Sun.COM 	if (matchedHBAs == 0) {
835*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
836*10652SHyon.Kim@Sun.COM 		    gettext("Error: Matching HBA not found."));
837*10652SHyon.Kim@Sun.COM 		if (input->wwn_flag) {
838*10652SHyon.Kim@Sun.COM 			free(input->wwn_flag);
839*10652SHyon.Kim@Sun.COM 			input->wwn_flag = NULL;
840*10652SHyon.Kim@Sun.COM 		}
841*10652SHyon.Kim@Sun.COM 		return (++ret);
842*10652SHyon.Kim@Sun.COM 	} else if (processPort == NULL) {
843*10652SHyon.Kim@Sun.COM 		/*
844*10652SHyon.Kim@Sun.COM 		 * processPort == NULL signifies hba subcommand.
845*10652SHyon.Kim@Sun.COM 		 * If enter here, it means we have at least one matching
846*10652SHyon.Kim@Sun.COM 		 * hba, we need to check if there are mismatching ones.
847*10652SHyon.Kim@Sun.COM 		 */
848*10652SHyon.Kim@Sun.COM 		for (i = 0; i < input->wwnCount; i++) {
849*10652SHyon.Kim@Sun.COM 			if (input->wwn_flag[i] == 0) {
850*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr, "%s %s %s\n",
851*10652SHyon.Kim@Sun.COM 				    gettext("Error: HBA"),
852*10652SHyon.Kim@Sun.COM 				    input->wwn_argv[i],
853*10652SHyon.Kim@Sun.COM 				    gettext("not found."));
854*10652SHyon.Kim@Sun.COM 				ret++;
855*10652SHyon.Kim@Sun.COM 			}
856*10652SHyon.Kim@Sun.COM 		}
857*10652SHyon.Kim@Sun.COM 	} else {
858*10652SHyon.Kim@Sun.COM 		if (local_avail > 0 && matchedHBAPorts == 0) {
859*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n",
860*10652SHyon.Kim@Sun.COM 			    gettext("Error: Matching HBA Port "
861*10652SHyon.Kim@Sun.COM 			    "not found."));
862*10652SHyon.Kim@Sun.COM 			if (input->wwn_flag) {
863*10652SHyon.Kim@Sun.COM 				free(input->wwn_flag);
864*10652SHyon.Kim@Sun.COM 				input->wwn_flag = NULL;
865*10652SHyon.Kim@Sun.COM 			}
866*10652SHyon.Kim@Sun.COM 			return (++ret);
867*10652SHyon.Kim@Sun.COM 		} else if (local_avail == 0) {
868*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n",
869*10652SHyon.Kim@Sun.COM 			    gettext("Error: No HBA Port Configured."));
870*10652SHyon.Kim@Sun.COM 			if (input->wwn_flag) {
871*10652SHyon.Kim@Sun.COM 				free(input->wwn_flag);
872*10652SHyon.Kim@Sun.COM 				input->wwn_flag = NULL;
873*10652SHyon.Kim@Sun.COM 			}
874*10652SHyon.Kim@Sun.COM 			return (++ret);
875*10652SHyon.Kim@Sun.COM 		} else if (processPort == handleHBAPort) {
876*10652SHyon.Kim@Sun.COM 			/*
877*10652SHyon.Kim@Sun.COM 			 * If enter here, we have at least one HBA port
878*10652SHyon.Kim@Sun.COM 			 * matched. For hba-port subcommand, we shall check
879*10652SHyon.Kim@Sun.COM 			 * whether there are operands mismatching.
880*10652SHyon.Kim@Sun.COM 			 */
881*10652SHyon.Kim@Sun.COM 			for (i = 0; i < input->wwnCount; i++) {
882*10652SHyon.Kim@Sun.COM 				if (input->wwn_flag[i] == 0) {
883*10652SHyon.Kim@Sun.COM 					(void *) fprintf(stderr, "%s %s %s\n",
884*10652SHyon.Kim@Sun.COM 					    gettext("Error: HBA Port"),
885*10652SHyon.Kim@Sun.COM 					    input->wwn_argv[i],
886*10652SHyon.Kim@Sun.COM 					    gettext("not found."));
887*10652SHyon.Kim@Sun.COM 					ret++;
888*10652SHyon.Kim@Sun.COM 				}
889*10652SHyon.Kim@Sun.COM 			}
890*10652SHyon.Kim@Sun.COM 		}
891*10652SHyon.Kim@Sun.COM 	}
892*10652SHyon.Kim@Sun.COM 
893*10652SHyon.Kim@Sun.COM 	/*
894*10652SHyon.Kim@Sun.COM 	 * For expander subcommand, we need to check if the
895*10652SHyon.Kim@Sun.COM 	 * specified sas address(ese) exist (none/partial/all).
896*10652SHyon.Kim@Sun.COM 	 */
897*10652SHyon.Kim@Sun.COM 	if (processPort == handleExpander) {
898*10652SHyon.Kim@Sun.COM 		if (input->wwnCount > 0) {
899*10652SHyon.Kim@Sun.COM 			sum = 0;
900*10652SHyon.Kim@Sun.COM 			for (i = 0; i < input->wwnCount; i++) {
901*10652SHyon.Kim@Sun.COM 				sum += input->wwn_flag[i];
902*10652SHyon.Kim@Sun.COM 			}
903*10652SHyon.Kim@Sun.COM 			/*
904*10652SHyon.Kim@Sun.COM 			 * If sum is zero, it means that for all the given
905*10652SHyon.Kim@Sun.COM 			 * operands matching count is zero. So none of the
906*10652SHyon.Kim@Sun.COM 			 * specified SAS address exist actually.
907*10652SHyon.Kim@Sun.COM 			 */
908*10652SHyon.Kim@Sun.COM 			if (sum == 0) {
909*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr, gettext("Error: "
910*10652SHyon.Kim@Sun.COM 				    "Matching SAS Address not found.\n"));
911*10652SHyon.Kim@Sun.COM 				free(input->wwn_flag);
912*10652SHyon.Kim@Sun.COM 				input->wwn_flag = NULL;
913*10652SHyon.Kim@Sun.COM 				return (++ret);
914*10652SHyon.Kim@Sun.COM 			}
915*10652SHyon.Kim@Sun.COM 
916*10652SHyon.Kim@Sun.COM 			/*
917*10652SHyon.Kim@Sun.COM 			 * If we get here, it means that some of the specified
918*10652SHyon.Kim@Sun.COM 			 * sas address exist, we will know through looping the
919*10652SHyon.Kim@Sun.COM 			 * wwn_flag array.
920*10652SHyon.Kim@Sun.COM 			 */
921*10652SHyon.Kim@Sun.COM 			for (i = 0; i < input->wwnCount; i++) {
922*10652SHyon.Kim@Sun.COM 				if (input->wwn_flag[i] == 0) {
923*10652SHyon.Kim@Sun.COM 					(void *) fprintf(stderr, "%s %s %s\n",
924*10652SHyon.Kim@Sun.COM 					    gettext("Error: SAS Address"),
925*10652SHyon.Kim@Sun.COM 					    input->wwn_argv[i],
926*10652SHyon.Kim@Sun.COM 					    gettext("not found."));
927*10652SHyon.Kim@Sun.COM 					ret++;
928*10652SHyon.Kim@Sun.COM 				}
929*10652SHyon.Kim@Sun.COM 			}
930*10652SHyon.Kim@Sun.COM 		}
931*10652SHyon.Kim@Sun.COM 		/* even if no remote port is found it is not an error. */
932*10652SHyon.Kim@Sun.COM 	}
933*10652SHyon.Kim@Sun.COM 	if (input->wwn_flag) {
934*10652SHyon.Kim@Sun.COM 		free(input->wwn_flag);
935*10652SHyon.Kim@Sun.COM 		input->wwn_flag = NULL;
936*10652SHyon.Kim@Sun.COM 	}
937*10652SHyon.Kim@Sun.COM 	return (ret);
938*10652SHyon.Kim@Sun.COM }
939*10652SHyon.Kim@Sun.COM 
940*10652SHyon.Kim@Sun.COM /*
941*10652SHyon.Kim@Sun.COM  * This function will handle the phy stuff for hba-port subcommand.
942*10652SHyon.Kim@Sun.COM  *
943*10652SHyon.Kim@Sun.COM  * Arguments:
944*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
945*10652SHyon.Kim@Sun.COM  *      portIndex - the index of hba port currently being processed.
946*10652SHyon.Kim@Sun.COM  *      port - pointer to hba port attributes.
947*10652SHyon.Kim@Sun.COM  *      pflag - options user specified.
948*10652SHyon.Kim@Sun.COM  *
949*10652SHyon.Kim@Sun.COM  *  Return Value:
950*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
951*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
952*10652SHyon.Kim@Sun.COM  */
953*10652SHyon.Kim@Sun.COM static int
processHBAPortPhyInfo(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,int pflag)954*10652SHyon.Kim@Sun.COM processHBAPortPhyInfo(HBA_HANDLE handle, HBA_UINT32 portIndex,
955*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, int pflag)
956*10652SHyon.Kim@Sun.COM {
957*10652SHyon.Kim@Sun.COM 	int 		phyIndex = 0, err_cnt = 0;
958*10652SHyon.Kim@Sun.COM 	HBA_UINT32	numphys = 0;
959*10652SHyon.Kim@Sun.COM 	HBA_STATUS	status = 0;
960*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PHY	phyattrs;
961*10652SHyon.Kim@Sun.COM 
962*10652SHyon.Kim@Sun.COM 	if (port == NULL)
963*10652SHyon.Kim@Sun.COM 		return (++err_cnt);
964*10652SHyon.Kim@Sun.COM 
965*10652SHyon.Kim@Sun.COM 	numphys = port->PortSpecificAttribute.SASPort->NumberofPhys;
966*10652SHyon.Kim@Sun.COM 	if (numphys == 0)
967*10652SHyon.Kim@Sun.COM 		return (0);
968*10652SHyon.Kim@Sun.COM 
969*10652SHyon.Kim@Sun.COM 	if ((pflag & PRINT_PHY) || (pflag & PRINT_PHY_LINKSTAT))
970*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stdout, "%s\n", "    Phy Information:");
971*10652SHyon.Kim@Sun.COM 	else
972*10652SHyon.Kim@Sun.COM 		return (0);
973*10652SHyon.Kim@Sun.COM 
974*10652SHyon.Kim@Sun.COM 
975*10652SHyon.Kim@Sun.COM 	for (phyIndex = 0; phyIndex < numphys; phyIndex++) {
976*10652SHyon.Kim@Sun.COM 		(void *) memset(&phyattrs, 0, sizeof (phyattrs));
977*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetSASPhyAttributes(
978*10652SHyon.Kim@Sun.COM 		    handle, portIndex, phyIndex, &phyattrs);
979*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
980*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s %d %s %s\n",
981*10652SHyon.Kim@Sun.COM 			    gettext("Failed to get SAS Phy attributes"
982*10652SHyon.Kim@Sun.COM 			    "phyIndex"), phyIndex,
983*10652SHyon.Kim@Sun.COM 			    gettext("Reason:"),
984*10652SHyon.Kim@Sun.COM 			    getHBAStatus(status));
985*10652SHyon.Kim@Sun.COM 			err_cnt++;
986*10652SHyon.Kim@Sun.COM 			continue;
987*10652SHyon.Kim@Sun.COM 		}
988*10652SHyon.Kim@Sun.COM 		if (pflag & PRINT_PHY)
989*10652SHyon.Kim@Sun.COM 			printHBAPortPhyInfo(&phyattrs);
990*10652SHyon.Kim@Sun.COM 		if (pflag & PRINT_PHY_LINKSTAT)
991*10652SHyon.Kim@Sun.COM 			err_cnt += processHBAPortPhyStat(handle,
992*10652SHyon.Kim@Sun.COM 			    portIndex, phyIndex, &phyattrs, pflag);
993*10652SHyon.Kim@Sun.COM 	}
994*10652SHyon.Kim@Sun.COM 	return (err_cnt);
995*10652SHyon.Kim@Sun.COM }
996*10652SHyon.Kim@Sun.COM 
997*10652SHyon.Kim@Sun.COM /*
998*10652SHyon.Kim@Sun.COM  * This function will handle the phy stuff for hba-port subcommand.
999*10652SHyon.Kim@Sun.COM  *
1000*10652SHyon.Kim@Sun.COM  * Arguments:
1001*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1002*10652SHyon.Kim@Sun.COM  *      portIndex - the index of hba port currently being processed.
1003*10652SHyon.Kim@Sun.COM  *      port - pointer to hba port attributes.
1004*10652SHyon.Kim@Sun.COM  *      pflag - options user specified.
1005*10652SHyon.Kim@Sun.COM  *
1006*10652SHyon.Kim@Sun.COM  *  Return Value:
1007*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1008*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1009*10652SHyon.Kim@Sun.COM  */
1010*10652SHyon.Kim@Sun.COM static int
processHBAPortPhyStat(HBA_HANDLE handle,HBA_UINT32 portIndex,int phyIndex,PSMHBA_SAS_PHY phyattrs,int pflag)1011*10652SHyon.Kim@Sun.COM processHBAPortPhyStat(HBA_HANDLE handle, HBA_UINT32 portIndex, int phyIndex,
1012*10652SHyon.Kim@Sun.COM     PSMHBA_SAS_PHY phyattrs, int pflag)
1013*10652SHyon.Kim@Sun.COM {
1014*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status = 0;
1015*10652SHyon.Kim@Sun.COM 	SMHBA_PHYSTATISTICS	phystat;
1016*10652SHyon.Kim@Sun.COM 	SMHBA_SASPHYSTATISTICS	sasphystat;
1017*10652SHyon.Kim@Sun.COM 
1018*10652SHyon.Kim@Sun.COM 	if ((pflag & PRINT_PHY) == 0) {
1019*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stdout, "%s %d\n",
1020*10652SHyon.Kim@Sun.COM 		    "      Identifier:", phyattrs->PhyIdentifier);
1021*10652SHyon.Kim@Sun.COM 	}
1022*10652SHyon.Kim@Sun.COM 
1023*10652SHyon.Kim@Sun.COM 	(void *) memset(&phystat, 0, sizeof (phystat));
1024*10652SHyon.Kim@Sun.COM 	(void *) memset(&sasphystat, 0, sizeof (sasphystat));
1025*10652SHyon.Kim@Sun.COM 	phystat.SASPhyStatistics = &sasphystat;
1026*10652SHyon.Kim@Sun.COM 	status = SMHBA_GetPhyStatistics(handle, portIndex, phyIndex, &phystat);
1027*10652SHyon.Kim@Sun.COM 	if (status != HBA_STATUS_OK) {
1028*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stdout, "%s\n",
1029*10652SHyon.Kim@Sun.COM 		    "        Link Error Statistics:");
1030*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
1031*10652SHyon.Kim@Sun.COM 		    gettext("            Failed to retrieve Link "
1032*10652SHyon.Kim@Sun.COM 		    "Error Statistics!"));
1033*10652SHyon.Kim@Sun.COM 		return (1);
1034*10652SHyon.Kim@Sun.COM 	}
1035*10652SHyon.Kim@Sun.COM 	printHBAPortPhyStatistics(phystat.SASPhyStatistics);
1036*10652SHyon.Kim@Sun.COM 	return (0);
1037*10652SHyon.Kim@Sun.COM }
1038*10652SHyon.Kim@Sun.COM 
1039*10652SHyon.Kim@Sun.COM /*
1040*10652SHyon.Kim@Sun.COM  * Check whether the pWWN exist in the WWNs list which specified by user.
1041*10652SHyon.Kim@Sun.COM  *
1042*10652SHyon.Kim@Sun.COM  * Arguments:
1043*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1044*10652SHyon.Kim@Sun.COM  *	pWWN - pointer to the hba port sas address.
1045*10652SHyon.Kim@Sun.COM  *
1046*10652SHyon.Kim@Sun.COM  *  Return Value:
1047*10652SHyon.Kim@Sun.COM  *	    1		true, the pWWN exist in the sas address list specified.
1048*10652SHyon.Kim@Sun.COM  *	    0		false.
1049*10652SHyon.Kim@Sun.COM  */
1050*10652SHyon.Kim@Sun.COM static int
isPortWWNInArgv(inputArg_t * input,PHBA_WWN pWWN)1051*10652SHyon.Kim@Sun.COM isPortWWNInArgv(inputArg_t *input, PHBA_WWN pWWN)
1052*10652SHyon.Kim@Sun.COM {
1053*10652SHyon.Kim@Sun.COM 	int 		port_wwn_counter = 0;
1054*10652SHyon.Kim@Sun.COM 	int		portfound = 0;
1055*10652SHyon.Kim@Sun.COM 	uint64_t	hbaWWN;
1056*10652SHyon.Kim@Sun.COM 
1057*10652SHyon.Kim@Sun.COM 	/* list only ports given in wwn_argv */
1058*10652SHyon.Kim@Sun.COM 	for (port_wwn_counter = 0;
1059*10652SHyon.Kim@Sun.COM 	    port_wwn_counter < input->wwnCount;
1060*10652SHyon.Kim@Sun.COM 	    port_wwn_counter++) {
1061*10652SHyon.Kim@Sun.COM 		hbaWWN = strtoull(input->wwn_argv[port_wwn_counter], NULL,
1062*10652SHyon.Kim@Sun.COM 		    16);
1063*10652SHyon.Kim@Sun.COM 		if (hbaWWN == 0 && errno != 0)
1064*10652SHyon.Kim@Sun.COM 			continue;
1065*10652SHyon.Kim@Sun.COM 		if (wwnConversion(pWWN->wwn) == hbaWWN) {
1066*10652SHyon.Kim@Sun.COM 			if (input->wwn_flag) {
1067*10652SHyon.Kim@Sun.COM 				input->wwn_flag[port_wwn_counter]++;
1068*10652SHyon.Kim@Sun.COM 			}
1069*10652SHyon.Kim@Sun.COM 			portfound = 1;
1070*10652SHyon.Kim@Sun.COM 		}
1071*10652SHyon.Kim@Sun.COM 	}
1072*10652SHyon.Kim@Sun.COM 	return (portfound);
1073*10652SHyon.Kim@Sun.COM }
1074*10652SHyon.Kim@Sun.COM 
1075*10652SHyon.Kim@Sun.COM /*
1076*10652SHyon.Kim@Sun.COM  * Check whether the string value exists in the input list,
1077*10652SHyon.Kim@Sun.COM  * which specified by user.
1078*10652SHyon.Kim@Sun.COM  *
1079*10652SHyon.Kim@Sun.COM  * Arguments:
1080*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1081*10652SHyon.Kim@Sun.COM  *	stringName - could be hba adapter name
1082*10652SHyon.Kim@Sun.COM  *	                      hba-port name.
1083*10652SHyon.Kim@Sun.COM  *
1084*10652SHyon.Kim@Sun.COM  *  Return Value:
1085*10652SHyon.Kim@Sun.COM  *	    1		true, the HBA exists in the list specified.
1086*10652SHyon.Kim@Sun.COM  *	    0		false.
1087*10652SHyon.Kim@Sun.COM  */
1088*10652SHyon.Kim@Sun.COM static int
isStringInArgv(inputArg_t * input,const char * stringName)1089*10652SHyon.Kim@Sun.COM isStringInArgv(inputArg_t *input, const char *stringName)
1090*10652SHyon.Kim@Sun.COM {
1091*10652SHyon.Kim@Sun.COM 	int 		counter = 0;
1092*10652SHyon.Kim@Sun.COM 	int		found = 0;
1093*10652SHyon.Kim@Sun.COM 
1094*10652SHyon.Kim@Sun.COM 	/* list only hba(s) given in wwn_argv */
1095*10652SHyon.Kim@Sun.COM 	for (counter = 0;
1096*10652SHyon.Kim@Sun.COM 	    counter < input->wwnCount;
1097*10652SHyon.Kim@Sun.COM 	    counter++) {
1098*10652SHyon.Kim@Sun.COM 		if (strcmp(input->wwn_argv[counter],
1099*10652SHyon.Kim@Sun.COM 		    stringName) == 0) {
1100*10652SHyon.Kim@Sun.COM 			if (input->wwn_flag)
1101*10652SHyon.Kim@Sun.COM 				input->wwn_flag[counter]++;
1102*10652SHyon.Kim@Sun.COM 			found = 1;
1103*10652SHyon.Kim@Sun.COM 		}
1104*10652SHyon.Kim@Sun.COM 	}
1105*10652SHyon.Kim@Sun.COM 	return (found);
1106*10652SHyon.Kim@Sun.COM }
1107*10652SHyon.Kim@Sun.COM 
1108*10652SHyon.Kim@Sun.COM /*
1109*10652SHyon.Kim@Sun.COM  * Callback function for hba subcommand.
1110*10652SHyon.Kim@Sun.COM  *
1111*10652SHyon.Kim@Sun.COM  * Arguments:
1112*10652SHyon.Kim@Sun.COM  *      attrs - pointer to adapter attributes currently being processed.
1113*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1114*10652SHyon.Kim@Sun.COM  *	numberOfPorts - number of ports of this HBA.
1115*10652SHyon.Kim@Sun.COM  *
1116*10652SHyon.Kim@Sun.COM  *  Return Value:
1117*10652SHyon.Kim@Sun.COM  *  	matching number
1118*10652SHyon.Kim@Sun.COM  */
handleHBA(SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input,int numberOfPorts,const char * adapterName)1119*10652SHyon.Kim@Sun.COM static int handleHBA(SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input,
1120*10652SHyon.Kim@Sun.COM     int numberOfPorts, const char *adapterName)
1121*10652SHyon.Kim@Sun.COM {
1122*10652SHyon.Kim@Sun.COM 	int matchingHBA = 1;
1123*10652SHyon.Kim@Sun.COM 
1124*10652SHyon.Kim@Sun.COM 	if (input->wwnCount == 0) {
1125*10652SHyon.Kim@Sun.COM 		printHBAInfo(attrs, input->pflag, numberOfPorts, adapterName);
1126*10652SHyon.Kim@Sun.COM 	} else {
1127*10652SHyon.Kim@Sun.COM 		if (isStringInArgv(input, adapterName)) {
1128*10652SHyon.Kim@Sun.COM 			printHBAInfo(attrs,
1129*10652SHyon.Kim@Sun.COM 			    input->pflag, numberOfPorts, adapterName);
1130*10652SHyon.Kim@Sun.COM 		} else {
1131*10652SHyon.Kim@Sun.COM 			matchingHBA = 0;
1132*10652SHyon.Kim@Sun.COM 		}
1133*10652SHyon.Kim@Sun.COM 	}
1134*10652SHyon.Kim@Sun.COM 
1135*10652SHyon.Kim@Sun.COM 	return (matchingHBA);
1136*10652SHyon.Kim@Sun.COM }
1137*10652SHyon.Kim@Sun.COM 
1138*10652SHyon.Kim@Sun.COM /*
1139*10652SHyon.Kim@Sun.COM  * Callback function for hba-port subcommand.
1140*10652SHyon.Kim@Sun.COM  *
1141*10652SHyon.Kim@Sun.COM  * Arguments:
1142*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1143*10652SHyon.Kim@Sun.COM  *      portIndex - the index of hba port currently being processed.
1144*10652SHyon.Kim@Sun.COM  *      port - pointer to hba port attributes.
1145*10652SHyon.Kim@Sun.COM  *      attrs - pointer to adapter attributes currently being processed.
1146*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1147*10652SHyon.Kim@Sun.COM  *
1148*10652SHyon.Kim@Sun.COM  *  Return Value:
1149*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1150*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1151*10652SHyon.Kim@Sun.COM  */
1152*10652SHyon.Kim@Sun.COM /*ARGSUSED*/
handleHBAPort(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1153*10652SHyon.Kim@Sun.COM static int handleHBAPort(HBA_HANDLE handle, char *adapterName,
1154*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1155*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1156*10652SHyon.Kim@Sun.COM {
1157*10652SHyon.Kim@Sun.COM 	int ret = 0;
1158*10652SHyon.Kim@Sun.COM 	printHBAPortInfo(port, attrs, input->pflag);
1159*10652SHyon.Kim@Sun.COM 	ret = processHBAPortPhyInfo(handle, portIndex, port, input->pflag);
1160*10652SHyon.Kim@Sun.COM 	return (ret);
1161*10652SHyon.Kim@Sun.COM }
1162*10652SHyon.Kim@Sun.COM 
1163*10652SHyon.Kim@Sun.COM /*
1164*10652SHyon.Kim@Sun.COM  * Callback function for expander subcommand.
1165*10652SHyon.Kim@Sun.COM  *
1166*10652SHyon.Kim@Sun.COM  * Arguments:
1167*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1168*10652SHyon.Kim@Sun.COM  *      portIndex - the index of hba port currently being processed.
1169*10652SHyon.Kim@Sun.COM  *      port - pointer to hba port attributes.
1170*10652SHyon.Kim@Sun.COM  *      attrs - pointer to adapter attributes currently being processed.
1171*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1172*10652SHyon.Kim@Sun.COM  *
1173*10652SHyon.Kim@Sun.COM  *  Return Value:
1174*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1175*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1176*10652SHyon.Kim@Sun.COM  */
1177*10652SHyon.Kim@Sun.COM /*ARGSUSED*/
handleExpander(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1178*10652SHyon.Kim@Sun.COM static int handleExpander(HBA_HANDLE handle, char *adapterName,
1179*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1180*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1181*10652SHyon.Kim@Sun.COM {
1182*10652SHyon.Kim@Sun.COM 	SMHBA_PORTATTRIBUTES	attr;
1183*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PORT		sasport;
1184*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
1185*10652SHyon.Kim@Sun.COM 	int			ret = 0;
1186*10652SHyon.Kim@Sun.COM 	int			i, numberOfRP;
1187*10652SHyon.Kim@Sun.COM 	rp_tree_t		*rpnode;
1188*10652SHyon.Kim@Sun.COM 	rp_tree_t		*rproot = NULL;
1189*10652SHyon.Kim@Sun.COM 	rp_tree_t		*unsolved_head = NULL;
1190*10652SHyon.Kim@Sun.COM 	rp_tree_t		*unsolved_tail = NULL;
1191*10652SHyon.Kim@Sun.COM 	rp_tree_t		*unsolved_sentinel = NULL;
1192*10652SHyon.Kim@Sun.COM 	int			printPort = 0;
1193*10652SHyon.Kim@Sun.COM 	int			numberOfEXP = 0;
1194*10652SHyon.Kim@Sun.COM 	int			unsolved_inserted = 0;
1195*10652SHyon.Kim@Sun.COM 	int			unsolved_left = 0;
1196*10652SHyon.Kim@Sun.COM 	int			disco_port_fail = 0;
1197*10652SHyon.Kim@Sun.COM 	boolean_t		firstPrinted = B_FALSE;
1198*10652SHyon.Kim@Sun.COM 
1199*10652SHyon.Kim@Sun.COM 	(void *) memset(&attr, 0, sizeof (attr));
1200*10652SHyon.Kim@Sun.COM 	(void *) memset(&sasport, 0, sizeof (sasport));
1201*10652SHyon.Kim@Sun.COM 	attr.PortSpecificAttribute.SASPort = &sasport;
1202*10652SHyon.Kim@Sun.COM 
1203*10652SHyon.Kim@Sun.COM 	/*
1204*10652SHyon.Kim@Sun.COM 	 * Retrive all expander device from this hba port first.
1205*10652SHyon.Kim@Sun.COM 	 */
1206*10652SHyon.Kim@Sun.COM 	if ((numberOfRP = port->PortSpecificAttribute.SASPort->
1207*10652SHyon.Kim@Sun.COM 	    NumberofDiscoveredPorts) == 0) {
1208*10652SHyon.Kim@Sun.COM 		/* no remote port. just return 0. */
1209*10652SHyon.Kim@Sun.COM 		return (ret);
1210*10652SHyon.Kim@Sun.COM 	}
1211*10652SHyon.Kim@Sun.COM 
1212*10652SHyon.Kim@Sun.COM 	for (i = 0; i < numberOfRP; i++) {
1213*10652SHyon.Kim@Sun.COM 		rpnode = calloc(1, sizeof (rp_tree_t));
1214*10652SHyon.Kim@Sun.COM 		rpnode->portattr.PortSpecificAttribute.SASPort =
1215*10652SHyon.Kim@Sun.COM 		    &rpnode->sasattr;
1216*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetDiscoveredPortAttributes(handle,
1217*10652SHyon.Kim@Sun.COM 		    portIndex, i, &rpnode->portattr);
1218*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
1219*10652SHyon.Kim@Sun.COM 			disco_port_fail++;
1220*10652SHyon.Kim@Sun.COM 			free(rpnode);
1221*10652SHyon.Kim@Sun.COM 			ret++;
1222*10652SHyon.Kim@Sun.COM 			continue;
1223*10652SHyon.Kim@Sun.COM 		}
1224*10652SHyon.Kim@Sun.COM 
1225*10652SHyon.Kim@Sun.COM 		if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
1226*10652SHyon.Kim@Sun.COM 			numberOfEXP++;
1227*10652SHyon.Kim@Sun.COM 		}
1228*10652SHyon.Kim@Sun.COM 		/*
1229*10652SHyon.Kim@Sun.COM 		 * We will try to insert this expander device and target
1230*10652SHyon.Kim@Sun.COM 		 * ports into the topology tree. If we failed, we can chain
1231*10652SHyon.Kim@Sun.COM 		 * them together and try again when we have all the
1232*10652SHyon.Kim@Sun.COM 		 * discovered port information in hands.
1233*10652SHyon.Kim@Sun.COM 		 */
1234*10652SHyon.Kim@Sun.COM 		if (rproot == NULL && memcmp(port->
1235*10652SHyon.Kim@Sun.COM 		    PortSpecificAttribute.SASPort->LocalSASAddress.wwn,
1236*10652SHyon.Kim@Sun.COM 		    rpnode->sasattr.AttachedSASAddress.wwn,
1237*10652SHyon.Kim@Sun.COM 		    sizeof (HBA_WWN)) == 0) {
1238*10652SHyon.Kim@Sun.COM 			/*
1239*10652SHyon.Kim@Sun.COM 			 * The root node of tree should
1240*10652SHyon.Kim@Sun.COM 			 * be set up first.
1241*10652SHyon.Kim@Sun.COM 			 */
1242*10652SHyon.Kim@Sun.COM 			rproot = rpnode;
1243*10652SHyon.Kim@Sun.COM 		} else {
1244*10652SHyon.Kim@Sun.COM 			/*
1245*10652SHyon.Kim@Sun.COM 			 * If we can not set up the root node of
1246*10652SHyon.Kim@Sun.COM 			 * the tree or we failed to insert
1247*10652SHyon.Kim@Sun.COM 			 * the disocvered port node, queue it up then.
1248*10652SHyon.Kim@Sun.COM 			 */
1249*10652SHyon.Kim@Sun.COM 			if (rproot == NULL ||
1250*10652SHyon.Kim@Sun.COM 			    sas_rp_tree_insert(&rproot, rpnode) != 0) {
1251*10652SHyon.Kim@Sun.COM 				if (unsolved_head == NULL) {
1252*10652SHyon.Kim@Sun.COM 					unsolved_head = rpnode;
1253*10652SHyon.Kim@Sun.COM 					unsolved_tail = rpnode;
1254*10652SHyon.Kim@Sun.COM 				} else {
1255*10652SHyon.Kim@Sun.COM 					rpnode->sibling = unsolved_head;
1256*10652SHyon.Kim@Sun.COM 					unsolved_head = rpnode;
1257*10652SHyon.Kim@Sun.COM 				}
1258*10652SHyon.Kim@Sun.COM 			}
1259*10652SHyon.Kim@Sun.COM 		}
1260*10652SHyon.Kim@Sun.COM 	}
1261*10652SHyon.Kim@Sun.COM 
1262*10652SHyon.Kim@Sun.COM 	if (disco_port_fail) {
1263*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %d %s %s\n",
1264*10652SHyon.Kim@Sun.COM 		    gettext("Error: Failed to get attributes for"),
1265*10652SHyon.Kim@Sun.COM 		    disco_port_fail,
1266*10652SHyon.Kim@Sun.COM 		    gettext("connected ports of HBA port"),
1267*10652SHyon.Kim@Sun.COM 		    port->OSDeviceName);
1268*10652SHyon.Kim@Sun.COM 	}
1269*10652SHyon.Kim@Sun.COM 
1270*10652SHyon.Kim@Sun.COM 	/* no expander found.  No need further processing. */
1271*10652SHyon.Kim@Sun.COM 	if (numberOfEXP == 0) {
1272*10652SHyon.Kim@Sun.COM 		while (unsolved_head) {
1273*10652SHyon.Kim@Sun.COM 			unsolved_tail =
1274*10652SHyon.Kim@Sun.COM 			    unsolved_head->sibling;
1275*10652SHyon.Kim@Sun.COM 			free(unsolved_head);
1276*10652SHyon.Kim@Sun.COM 			unsolved_head = unsolved_tail;
1277*10652SHyon.Kim@Sun.COM 		}
1278*10652SHyon.Kim@Sun.COM 		if (rproot) sas_rp_tree_free(rproot);
1279*10652SHyon.Kim@Sun.COM 		return (ret);
1280*10652SHyon.Kim@Sun.COM 	}
1281*10652SHyon.Kim@Sun.COM 
1282*10652SHyon.Kim@Sun.COM 	/*
1283*10652SHyon.Kim@Sun.COM 	 * When we're here, we should already have all information,
1284*10652SHyon.Kim@Sun.COM 	 * now we try again to insert them into the topology tree.
1285*10652SHyon.Kim@Sun.COM 	 * unsolved_head is the pointer which point to the head of
1286*10652SHyon.Kim@Sun.COM 	 * unsolved rpnode linked list.
1287*10652SHyon.Kim@Sun.COM 	 * unsolved_tail is the pointer which point to the tail of
1288*10652SHyon.Kim@Sun.COM 	 * unsolved rpnode linked list.
1289*10652SHyon.Kim@Sun.COM 	 * unsolved_sentinel is for insertion failure detection.
1290*10652SHyon.Kim@Sun.COM 	 * When we're trying to insert the rpnodes from unsolved
1291*10652SHyon.Kim@Sun.COM 	 * linked list, it may happen that some of the rpnodes can
1292*10652SHyon.Kim@Sun.COM 	 * not be inserted no matter how many times we loop through
1293*10652SHyon.Kim@Sun.COM 	 * this linked list. So we use unsolved_sentinel to identify
1294*10652SHyon.Kim@Sun.COM 	 * the tail of last round of scanning, and unsolved_inserted
1295*10652SHyon.Kim@Sun.COM 	 * which is a counter will be used to count how many rpnodes
1296*10652SHyon.Kim@Sun.COM 	 * have been inserted from last round, if it is zero, which
1297*10652SHyon.Kim@Sun.COM 	 * means that we can not insert rpnodes into rptree any more,
1298*10652SHyon.Kim@Sun.COM 	 * and we should stop and deallocate the memory they occupied.
1299*10652SHyon.Kim@Sun.COM 	 */
1300*10652SHyon.Kim@Sun.COM 	unsolved_sentinel = unsolved_tail;
1301*10652SHyon.Kim@Sun.COM 	while (unsolved_head) {
1302*10652SHyon.Kim@Sun.COM 		rpnode = unsolved_head;
1303*10652SHyon.Kim@Sun.COM 		unsolved_head = unsolved_head->sibling;
1304*10652SHyon.Kim@Sun.COM 		if (unsolved_head == NULL)
1305*10652SHyon.Kim@Sun.COM 			unsolved_tail = NULL;
1306*10652SHyon.Kim@Sun.COM 		rpnode->sibling = NULL;
1307*10652SHyon.Kim@Sun.COM 		if (sas_rp_tree_insert(&rproot, rpnode) != 0) {
1308*10652SHyon.Kim@Sun.COM 			unsolved_tail->sibling = rpnode;
1309*10652SHyon.Kim@Sun.COM 			unsolved_tail = rpnode;
1310*10652SHyon.Kim@Sun.COM 			if (rpnode == unsolved_sentinel) {
1311*10652SHyon.Kim@Sun.COM 				/*
1312*10652SHyon.Kim@Sun.COM 				 * We just scanned one round for the
1313*10652SHyon.Kim@Sun.COM 				 * unsolved list. Check to see whether we
1314*10652SHyon.Kim@Sun.COM 				 * have nodes inserted, if none, we should
1315*10652SHyon.Kim@Sun.COM 				 * break in case of an indefinite loop.
1316*10652SHyon.Kim@Sun.COM 				 */
1317*10652SHyon.Kim@Sun.COM 				if (unsolved_inserted == 0) {
1318*10652SHyon.Kim@Sun.COM 					/*
1319*10652SHyon.Kim@Sun.COM 					 * Indicate there is unhandled node.
1320*10652SHyon.Kim@Sun.COM 					 * Chain free the whole unsolved
1321*10652SHyon.Kim@Sun.COM 					 * list here.
1322*10652SHyon.Kim@Sun.COM 					 */
1323*10652SHyon.Kim@Sun.COM 					unsolved_left++;
1324*10652SHyon.Kim@Sun.COM 					break;
1325*10652SHyon.Kim@Sun.COM 				} else {
1326*10652SHyon.Kim@Sun.COM 					unsolved_inserted = 0;
1327*10652SHyon.Kim@Sun.COM 					unsolved_sentinel = unsolved_tail;
1328*10652SHyon.Kim@Sun.COM 				}
1329*10652SHyon.Kim@Sun.COM 			}
1330*10652SHyon.Kim@Sun.COM 		} else {
1331*10652SHyon.Kim@Sun.COM 			/*
1332*10652SHyon.Kim@Sun.COM 			 * We just inserted one rpnode, increment the
1333*10652SHyon.Kim@Sun.COM 			 * unsolved_inserted counter. We will utilize this
1334*10652SHyon.Kim@Sun.COM 			 * counter to detect an indefinite insertion loop.
1335*10652SHyon.Kim@Sun.COM 			 */
1336*10652SHyon.Kim@Sun.COM 			unsolved_inserted++;
1337*10652SHyon.Kim@Sun.COM 		}
1338*10652SHyon.Kim@Sun.COM 	}
1339*10652SHyon.Kim@Sun.COM 
1340*10652SHyon.Kim@Sun.COM 	/* check if there is left out discovered ports. */
1341*10652SHyon.Kim@Sun.COM 	if (unsolved_left) {
1342*10652SHyon.Kim@Sun.COM 		ret++;
1343*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %s\n",
1344*10652SHyon.Kim@Sun.COM 		    gettext("Error: Failed to establish expander topology on"),
1345*10652SHyon.Kim@Sun.COM 		    port->OSDeviceName);
1346*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
1347*10652SHyon.Kim@Sun.COM 		    gettext("       Folowing port(s) are unresolved."));
1348*10652SHyon.Kim@Sun.COM 		while (unsolved_head) {
1349*10652SHyon.Kim@Sun.COM 			unsolved_tail =
1350*10652SHyon.Kim@Sun.COM 			    unsolved_head->sibling;
1351*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s%016llx ",
1352*10652SHyon.Kim@Sun.COM 			    firstPrinted ? "" : "\t",
1353*10652SHyon.Kim@Sun.COM 			    wwnConversion(unsolved_head->sasattr.
1354*10652SHyon.Kim@Sun.COM 			    LocalSASAddress.wwn));
1355*10652SHyon.Kim@Sun.COM 			if (firstPrinted == B_FALSE) firstPrinted = B_TRUE;
1356*10652SHyon.Kim@Sun.COM 			free(unsolved_head);
1357*10652SHyon.Kim@Sun.COM 			unsolved_head = unsolved_tail;
1358*10652SHyon.Kim@Sun.COM 		}
1359*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "\n");
1360*10652SHyon.Kim@Sun.COM 		/* still print what we have */
1361*10652SHyon.Kim@Sun.COM 		ret += sas_rp_tree_print(handle, adapterName, portIndex,
1362*10652SHyon.Kim@Sun.COM 		    port, rproot, input, 2 * TABLEN, &printPort);
1363*10652SHyon.Kim@Sun.COM 	} else {
1364*10652SHyon.Kim@Sun.COM 		ret += sas_rp_tree_print(handle, adapterName, portIndex,
1365*10652SHyon.Kim@Sun.COM 		    port, rproot, input, 2 * TABLEN, &printPort);
1366*10652SHyon.Kim@Sun.COM 	}
1367*10652SHyon.Kim@Sun.COM 
1368*10652SHyon.Kim@Sun.COM 	if (rproot) sas_rp_tree_free(rproot);
1369*10652SHyon.Kim@Sun.COM 
1370*10652SHyon.Kim@Sun.COM 	return (ret);
1371*10652SHyon.Kim@Sun.COM }
1372*10652SHyon.Kim@Sun.COM 
1373*10652SHyon.Kim@Sun.COM /*
1374*10652SHyon.Kim@Sun.COM  * Callback function for target-port subcommand.
1375*10652SHyon.Kim@Sun.COM  *
1376*10652SHyon.Kim@Sun.COM  * Arguments:
1377*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1378*10652SHyon.Kim@Sun.COM  *      portIndex - the index of hba port currently being processed.
1379*10652SHyon.Kim@Sun.COM  *      port - pointer to hba port attributes.
1380*10652SHyon.Kim@Sun.COM  *      attrs - pointer to adapter attributes currently being processed.
1381*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1382*10652SHyon.Kim@Sun.COM  *
1383*10652SHyon.Kim@Sun.COM  *  Return Value:
1384*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1385*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1386*10652SHyon.Kim@Sun.COM  */
1387*10652SHyon.Kim@Sun.COM /*ARGSUSED*/
handleTargetPort(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1388*10652SHyon.Kim@Sun.COM static int handleTargetPort(HBA_HANDLE handle, char *adapterName,
1389*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1390*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1391*10652SHyon.Kim@Sun.COM {
1392*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
1393*10652SHyon.Kim@Sun.COM 	SMHBA_PORTATTRIBUTES	targetattr;
1394*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PORT		sasattr;
1395*10652SHyon.Kim@Sun.COM 	int			i;
1396*10652SHyon.Kim@Sun.COM 	int			ret = 0;
1397*10652SHyon.Kim@Sun.COM 	int			disco_port_fail = 0;
1398*10652SHyon.Kim@Sun.COM 
1399*10652SHyon.Kim@Sun.COM 	targetattr.PortSpecificAttribute.SASPort = &sasattr;
1400*10652SHyon.Kim@Sun.COM 
1401*10652SHyon.Kim@Sun.COM 	for (i = 0; i < port->PortSpecificAttribute.SASPort->
1402*10652SHyon.Kim@Sun.COM 	    NumberofDiscoveredPorts; i++) {
1403*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetDiscoveredPortAttributes(handle,
1404*10652SHyon.Kim@Sun.COM 		    portIndex, i, &targetattr);
1405*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
1406*10652SHyon.Kim@Sun.COM 			disco_port_fail++;
1407*10652SHyon.Kim@Sun.COM 		} else {
1408*10652SHyon.Kim@Sun.COM 			/* skip expander device */
1409*10652SHyon.Kim@Sun.COM 			if (targetattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
1410*10652SHyon.Kim@Sun.COM 				ret += searchTargetPort(handle, portIndex, port,
1411*10652SHyon.Kim@Sun.COM 				    &targetattr, &sasattr, input->pflag);
1412*10652SHyon.Kim@Sun.COM 			}
1413*10652SHyon.Kim@Sun.COM 		}
1414*10652SHyon.Kim@Sun.COM 	}
1415*10652SHyon.Kim@Sun.COM 
1416*10652SHyon.Kim@Sun.COM 	if (disco_port_fail) {
1417*10652SHyon.Kim@Sun.COM 		ret++;
1418*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %d %s %s\n",
1419*10652SHyon.Kim@Sun.COM 		    gettext("Error: Failed to get attributes for"),
1420*10652SHyon.Kim@Sun.COM 		    disco_port_fail,
1421*10652SHyon.Kim@Sun.COM 		    gettext("connected ports of HBA port"),
1422*10652SHyon.Kim@Sun.COM 		    port->OSDeviceName);
1423*10652SHyon.Kim@Sun.COM 	}
1424*10652SHyon.Kim@Sun.COM 	return (ret);
1425*10652SHyon.Kim@Sun.COM }
1426*10652SHyon.Kim@Sun.COM 
1427*10652SHyon.Kim@Sun.COM /*
1428*10652SHyon.Kim@Sun.COM  * ****************************************************************************
1429*10652SHyon.Kim@Sun.COM  *
1430*10652SHyon.Kim@Sun.COM  * compareLUName -
1431*10652SHyon.Kim@Sun.COM  * 	compare names directly and also check if disk namees match with
1432*10652SHyon.Kim@Sun.COM  *	different slice number or /devices path are speicified and matches.
1433*10652SHyon.Kim@Sun.COM  *
1434*10652SHyon.Kim@Sun.COM  * cmdArg	- first string to compare
1435*10652SHyon.Kim@Sun.COM  * osName	- os name from attributes
1436*10652SHyon.Kim@Sun.COM  *
1437*10652SHyon.Kim@Sun.COM  * returns 	B_TRUE if the strings match either directly or via devid
1438*10652SHyon.Kim@Sun.COM  *		B_FALSE otherwise
1439*10652SHyon.Kim@Sun.COM  *
1440*10652SHyon.Kim@Sun.COM  * ****************************************************************************
1441*10652SHyon.Kim@Sun.COM  */
1442*10652SHyon.Kim@Sun.COM static boolean_t
compareLUName(char * cmdArg,char * osName)1443*10652SHyon.Kim@Sun.COM compareLUName(char *cmdArg, char *osName)
1444*10652SHyon.Kim@Sun.COM {
1445*10652SHyon.Kim@Sun.COM 
1446*10652SHyon.Kim@Sun.COM 	boolean_t	isSame = B_FALSE;
1447*10652SHyon.Kim@Sun.COM 	char		dev1[MAXPATHLEN], dev2[MAXPATHLEN];
1448*10652SHyon.Kim@Sun.COM 	char		*ch1, *ch2;
1449*10652SHyon.Kim@Sun.COM 
1450*10652SHyon.Kim@Sun.COM 	if (strcmp(cmdArg, osName) == 0) {
1451*10652SHyon.Kim@Sun.COM 		isSame = B_TRUE;
1452*10652SHyon.Kim@Sun.COM 	} else {
1453*10652SHyon.Kim@Sun.COM 		/* user input didn't match, try to  match the core of args. */
1454*10652SHyon.Kim@Sun.COM 		(void) strlcpy(dev1, cmdArg, MAXPATHLEN);
1455*10652SHyon.Kim@Sun.COM 		(void) strlcpy(dev2, osName, MAXPATHLEN);
1456*10652SHyon.Kim@Sun.COM 		/* is this /devices path */
1457*10652SHyon.Kim@Sun.COM 		if (((ch1 = strrchr(dev1, ',')) != NULL) &&
1458*10652SHyon.Kim@Sun.COM 		    ((ch2 = strrchr(dev2, ',')) != NULL)) {
1459*10652SHyon.Kim@Sun.COM 			*ch1 = *ch2 = '\0';
1460*10652SHyon.Kim@Sun.COM 			if (strcmp(dev1, dev2) == 0) {
1461*10652SHyon.Kim@Sun.COM 				isSame = B_TRUE;
1462*10652SHyon.Kim@Sun.COM 			}
1463*10652SHyon.Kim@Sun.COM 		/* is this a /dev link */
1464*10652SHyon.Kim@Sun.COM 		} else if ((strncmp(dev1, "/dev/", 5) == 0) &&
1465*10652SHyon.Kim@Sun.COM 		    (strncmp(dev2, "/dev/", 5) == 0)) {
1466*10652SHyon.Kim@Sun.COM 			if ((strstr(dev1, "dsk") != NULL) &&
1467*10652SHyon.Kim@Sun.COM 			    ((strstr(dev2, "dsk") != NULL))) {
1468*10652SHyon.Kim@Sun.COM 				/* if it is disk link */
1469*10652SHyon.Kim@Sun.COM 				if (((ch1 = strrchr(dev1, 's')) != NULL) &&
1470*10652SHyon.Kim@Sun.COM 				    ((ch2 = strrchr(dev2, 's')) != NULL)) {
1471*10652SHyon.Kim@Sun.COM 					*ch1 = *ch2 = '\0';
1472*10652SHyon.Kim@Sun.COM 					if (strcmp(dev1, dev2) == 0) {
1473*10652SHyon.Kim@Sun.COM 						isSame = B_TRUE;
1474*10652SHyon.Kim@Sun.COM 					}
1475*10652SHyon.Kim@Sun.COM 				}
1476*10652SHyon.Kim@Sun.COM 			} else {
1477*10652SHyon.Kim@Sun.COM 				/* other dev links */
1478*10652SHyon.Kim@Sun.COM 				if (strcmp(dev1, dev2) == 0) {
1479*10652SHyon.Kim@Sun.COM 					isSame = B_TRUE;
1480*10652SHyon.Kim@Sun.COM 				}
1481*10652SHyon.Kim@Sun.COM 			}
1482*10652SHyon.Kim@Sun.COM 		}
1483*10652SHyon.Kim@Sun.COM 	} /* compare */
1484*10652SHyon.Kim@Sun.COM 
1485*10652SHyon.Kim@Sun.COM 	return (isSame);
1486*10652SHyon.Kim@Sun.COM }
1487*10652SHyon.Kim@Sun.COM 
1488*10652SHyon.Kim@Sun.COM /*
1489*10652SHyon.Kim@Sun.COM  * Process logical-unit(lu) subcommand.
1490*10652SHyon.Kim@Sun.COM  *
1491*10652SHyon.Kim@Sun.COM  * Arguments:
1492*10652SHyon.Kim@Sun.COM  *      luCount - number of OS device name(s) specified by user.
1493*10652SHyon.Kim@Sun.COM  *      luArgv - array of OS device name(s) specified by user.
1494*10652SHyon.Kim@Sun.COM  *      options - all the options specified by user.
1495*10652SHyon.Kim@Sun.COM  *
1496*10652SHyon.Kim@Sun.COM  *  Return Value:
1497*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1498*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1499*10652SHyon.Kim@Sun.COM  */
1500*10652SHyon.Kim@Sun.COM int
sas_util_list_logicalunit(int luCount,char ** luArgv,cmdOptions_t * options)1501*10652SHyon.Kim@Sun.COM sas_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
1502*10652SHyon.Kim@Sun.COM {
1503*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
1504*10652SHyon.Kim@Sun.COM 	int			processHBA_flags = 0;
1505*10652SHyon.Kim@Sun.COM 	int			lu;
1506*10652SHyon.Kim@Sun.COM 	boolean_t		pathFound;
1507*10652SHyon.Kim@Sun.COM 	boolean_t		verbose;
1508*10652SHyon.Kim@Sun.COM 	inputArg_t		input;
1509*10652SHyon.Kim@Sun.COM 	discoveredDevice	*LUListWalk = NULL;
1510*10652SHyon.Kim@Sun.COM 	int			err_cnt = 0;
1511*10652SHyon.Kim@Sun.COM 
1512*10652SHyon.Kim@Sun.COM 	for (; options->optval; options++) {
1513*10652SHyon.Kim@Sun.COM 		if (options->optval == 'v') {
1514*10652SHyon.Kim@Sun.COM 			processHBA_flags |= PRINT_VERBOSE;
1515*10652SHyon.Kim@Sun.COM 		}
1516*10652SHyon.Kim@Sun.COM 	}
1517*10652SHyon.Kim@Sun.COM 
1518*10652SHyon.Kim@Sun.COM 	/* HBA_LoadLibrary() */
1519*10652SHyon.Kim@Sun.COM 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
1520*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %s\n",
1521*10652SHyon.Kim@Sun.COM 		    gettext("Failed to load SM-HBA libraries."
1522*10652SHyon.Kim@Sun.COM 		    "Reason:"), getHBAStatus(status));
1523*10652SHyon.Kim@Sun.COM 		err_cnt++;
1524*10652SHyon.Kim@Sun.COM 		return (err_cnt);
1525*10652SHyon.Kim@Sun.COM 	}
1526*10652SHyon.Kim@Sun.COM 
1527*10652SHyon.Kim@Sun.COM 	(void *) memset(&input, 0, sizeof (input));
1528*10652SHyon.Kim@Sun.COM 	input.pflag = processHBA_flags;
1529*10652SHyon.Kim@Sun.COM 	input.wwnCount = luCount;
1530*10652SHyon.Kim@Sun.COM 	input.wwn_argv = luArgv;
1531*10652SHyon.Kim@Sun.COM 
1532*10652SHyon.Kim@Sun.COM 	err_cnt += processHBA(&input, handleLogicalUnit);
1533*10652SHyon.Kim@Sun.COM 	verbose = (input.pflag & PRINT_VERBOSE) ? B_TRUE : B_FALSE;
1534*10652SHyon.Kim@Sun.COM 
1535*10652SHyon.Kim@Sun.COM 	if (luCount == 0) {
1536*10652SHyon.Kim@Sun.COM 		/* list all paths */
1537*10652SHyon.Kim@Sun.COM 		for (LUListWalk = LUList; LUListWalk != NULL;
1538*10652SHyon.Kim@Sun.COM 		    LUListWalk = LUListWalk->next) {
1539*10652SHyon.Kim@Sun.COM 			err_cnt += printOSDeviceNameInfo(LUListWalk, verbose);
1540*10652SHyon.Kim@Sun.COM 		}
1541*10652SHyon.Kim@Sun.COM 	} else {
1542*10652SHyon.Kim@Sun.COM 		/*
1543*10652SHyon.Kim@Sun.COM 		 * When operands provided, we should set the error code
1544*10652SHyon.Kim@Sun.COM 		 * only if there are issues related with the operands.
1545*10652SHyon.Kim@Sun.COM 		 */
1546*10652SHyon.Kim@Sun.COM 		err_cnt = 0;
1547*10652SHyon.Kim@Sun.COM 		/*
1548*10652SHyon.Kim@Sun.COM 		 * list any paths not found first
1549*10652SHyon.Kim@Sun.COM 		 * this gives the user cleaner output
1550*10652SHyon.Kim@Sun.COM 		 */
1551*10652SHyon.Kim@Sun.COM 		for (lu = 0; lu < luCount; lu++) {
1552*10652SHyon.Kim@Sun.COM 			for (LUListWalk = LUList, pathFound = B_FALSE;
1553*10652SHyon.Kim@Sun.COM 			    LUListWalk != NULL;
1554*10652SHyon.Kim@Sun.COM 			    LUListWalk = LUListWalk->next) {
1555*10652SHyon.Kim@Sun.COM 				if (compareLUName(luArgv[lu],
1556*10652SHyon.Kim@Sun.COM 				    LUListWalk->OSDeviceName)) {
1557*10652SHyon.Kim@Sun.COM 					pathFound = B_TRUE;
1558*10652SHyon.Kim@Sun.COM 					break;
1559*10652SHyon.Kim@Sun.COM 				}
1560*10652SHyon.Kim@Sun.COM 			}
1561*10652SHyon.Kim@Sun.COM 			if (pathFound == B_FALSE) {
1562*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr,
1563*10652SHyon.Kim@Sun.COM 				    "Error: Logical Unit %s Not Found \n",
1564*10652SHyon.Kim@Sun.COM 				    luArgv[lu]);
1565*10652SHyon.Kim@Sun.COM 				err_cnt++;
1566*10652SHyon.Kim@Sun.COM 			}
1567*10652SHyon.Kim@Sun.COM 		}
1568*10652SHyon.Kim@Sun.COM 		/* list all paths requested in order requested */
1569*10652SHyon.Kim@Sun.COM 		for (lu = 0; lu < luCount; lu++) {
1570*10652SHyon.Kim@Sun.COM 			for (LUListWalk = LUList; LUListWalk != NULL;
1571*10652SHyon.Kim@Sun.COM 			    LUListWalk = LUListWalk->next) {
1572*10652SHyon.Kim@Sun.COM 				if (compareLUName(luArgv[lu],
1573*10652SHyon.Kim@Sun.COM 				    LUListWalk->OSDeviceName)) {
1574*10652SHyon.Kim@Sun.COM 					err_cnt += printOSDeviceNameInfo(
1575*10652SHyon.Kim@Sun.COM 					    LUListWalk,
1576*10652SHyon.Kim@Sun.COM 					    verbose);
1577*10652SHyon.Kim@Sun.COM 				}
1578*10652SHyon.Kim@Sun.COM 			}
1579*10652SHyon.Kim@Sun.COM 		}
1580*10652SHyon.Kim@Sun.COM 	}
1581*10652SHyon.Kim@Sun.COM 	(void) HBA_FreeLibrary();
1582*10652SHyon.Kim@Sun.COM 	return (err_cnt);
1583*10652SHyon.Kim@Sun.COM }
1584*10652SHyon.Kim@Sun.COM 
1585*10652SHyon.Kim@Sun.COM /*
1586*10652SHyon.Kim@Sun.COM  * Callback function for logical-unit(lu) subcommand.
1587*10652SHyon.Kim@Sun.COM  *
1588*10652SHyon.Kim@Sun.COM  * Arguments:
1589*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1590*10652SHyon.Kim@Sun.COM  *      portIndex - the index of hba port currently being processed.
1591*10652SHyon.Kim@Sun.COM  *      port - pointer to hba port attributes.
1592*10652SHyon.Kim@Sun.COM  *      attrs - pointer to adapter attributes currently being processed.
1593*10652SHyon.Kim@Sun.COM  *	input - contains all the input parameters.
1594*10652SHyon.Kim@Sun.COM  *
1595*10652SHyon.Kim@Sun.COM  *  Return Value:
1596*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1597*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1598*10652SHyon.Kim@Sun.COM  */
1599*10652SHyon.Kim@Sun.COM /*ARGSUSED*/
handleLogicalUnit(HBA_HANDLE handle,char * adapterName,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_ADAPTERATTRIBUTES * attrs,inputArg_t * input)1600*10652SHyon.Kim@Sun.COM static int handleLogicalUnit(HBA_HANDLE handle, char *adapterName,
1601*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
1602*10652SHyon.Kim@Sun.COM     SMHBA_ADAPTERATTRIBUTES *attrs, inputArg_t *input)
1603*10652SHyon.Kim@Sun.COM {
1604*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
1605*10652SHyon.Kim@Sun.COM 	SMHBA_TARGETMAPPING	*map;
1606*10652SHyon.Kim@Sun.COM 	HBA_WWN			hbaPortWWN, domainPortWWN;
1607*10652SHyon.Kim@Sun.COM 	char			*portName = NULL;
1608*10652SHyon.Kim@Sun.COM 	int			numentries;
1609*10652SHyon.Kim@Sun.COM 	int			count = 0;
1610*10652SHyon.Kim@Sun.COM 	int			ret = 0;
1611*10652SHyon.Kim@Sun.COM 
1612*10652SHyon.Kim@Sun.COM 	hbaPortWWN = port->PortSpecificAttribute.SASPort->LocalSASAddress;
1613*10652SHyon.Kim@Sun.COM 	portName = port->OSDeviceName;
1614*10652SHyon.Kim@Sun.COM 
1615*10652SHyon.Kim@Sun.COM 	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
1616*10652SHyon.Kim@Sun.COM 	switch (status) {
1617*10652SHyon.Kim@Sun.COM 		case HBA_STATUS_OK:
1618*10652SHyon.Kim@Sun.COM 			break;
1619*10652SHyon.Kim@Sun.COM 		case HBA_STATUS_ERROR_NOT_SUPPORTED:
1620*10652SHyon.Kim@Sun.COM 			/* don't increase error flag for no phy configuration */
1621*10652SHyon.Kim@Sun.COM 			return (ret);
1622*10652SHyon.Kim@Sun.COM 		case HBA_STATUS_ERROR:
1623*10652SHyon.Kim@Sun.COM 		default:
1624*10652SHyon.Kim@Sun.COM 			return (++ret);
1625*10652SHyon.Kim@Sun.COM 	}
1626*10652SHyon.Kim@Sun.COM 
1627*10652SHyon.Kim@Sun.COM 	if ((map = calloc(1, sizeof (*map))) == NULL) {
1628*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
1629*10652SHyon.Kim@Sun.COM 		    gettext("No enough memory on heap."));
1630*10652SHyon.Kim@Sun.COM 		return (++ret);
1631*10652SHyon.Kim@Sun.COM 	}
1632*10652SHyon.Kim@Sun.COM 	map->NumberOfEntries = 1;
1633*10652SHyon.Kim@Sun.COM 
1634*10652SHyon.Kim@Sun.COM 	/*
1635*10652SHyon.Kim@Sun.COM 	 * First, we need to get the target mapping data from this hba
1636*10652SHyon.Kim@Sun.COM 	 * port.
1637*10652SHyon.Kim@Sun.COM 	 */
1638*10652SHyon.Kim@Sun.COM 	status = SMHBA_GetTargetMapping(handle,
1639*10652SHyon.Kim@Sun.COM 	    hbaPortWWN, domainPortWWN, map);
1640*10652SHyon.Kim@Sun.COM 
1641*10652SHyon.Kim@Sun.COM 	if (status == HBA_STATUS_ERROR_MORE_DATA) {
1642*10652SHyon.Kim@Sun.COM 		numentries = map->NumberOfEntries;
1643*10652SHyon.Kim@Sun.COM 		free(map);
1644*10652SHyon.Kim@Sun.COM 		map = calloc(1, sizeof (HBA_UINT32) +
1645*10652SHyon.Kim@Sun.COM 		    (numentries * sizeof (SMHBA_SCSIENTRY)));
1646*10652SHyon.Kim@Sun.COM 		if (map == NULL) {
1647*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n",
1648*10652SHyon.Kim@Sun.COM 			    gettext("No enough memory on heap."));
1649*10652SHyon.Kim@Sun.COM 			return (++ret);
1650*10652SHyon.Kim@Sun.COM 		}
1651*10652SHyon.Kim@Sun.COM 		map->NumberOfEntries = numentries;
1652*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetTargetMapping(handle,
1653*10652SHyon.Kim@Sun.COM 		    hbaPortWWN, domainPortWWN, map);
1654*10652SHyon.Kim@Sun.COM 	}
1655*10652SHyon.Kim@Sun.COM 
1656*10652SHyon.Kim@Sun.COM 	if (status != HBA_STATUS_OK) {
1657*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s %016llx %s %s\n",
1658*10652SHyon.Kim@Sun.COM 		    gettext("Error: Failed to get SCSI mapping data for "
1659*10652SHyon.Kim@Sun.COM 		    "the HBA port"), wwnConversion(hbaPortWWN.wwn),
1660*10652SHyon.Kim@Sun.COM 		    gettext("Reason:"),
1661*10652SHyon.Kim@Sun.COM 		    getHBAStatus(status));
1662*10652SHyon.Kim@Sun.COM 		free(map);
1663*10652SHyon.Kim@Sun.COM 		return (++ret);
1664*10652SHyon.Kim@Sun.COM 	}
1665*10652SHyon.Kim@Sun.COM 
1666*10652SHyon.Kim@Sun.COM 	/*
1667*10652SHyon.Kim@Sun.COM 	 * By iterating each entry of the targetmapping data, we will
1668*10652SHyon.Kim@Sun.COM 	 * construct a global list of logical unit.
1669*10652SHyon.Kim@Sun.COM 	 */
1670*10652SHyon.Kim@Sun.COM 	for (count = 0; count < map->NumberOfEntries; count++) {
1671*10652SHyon.Kim@Sun.COM 		ret += searchDevice(
1672*10652SHyon.Kim@Sun.COM 		    &(map->entry[count]), handle, hbaPortWWN, domainPortWWN,
1673*10652SHyon.Kim@Sun.COM 		    portName, input->pflag);
1674*10652SHyon.Kim@Sun.COM 	}
1675*10652SHyon.Kim@Sun.COM 	free(map);
1676*10652SHyon.Kim@Sun.COM 	return (ret);
1677*10652SHyon.Kim@Sun.COM }
1678*10652SHyon.Kim@Sun.COM 
1679*10652SHyon.Kim@Sun.COM /*
1680*10652SHyon.Kim@Sun.COM  * Search the matching targetmapping data for given target port and SAM LUN
1681*10652SHyon.Kim@Sun.COM  *	and return target mapping data if found.
1682*10652SHyon.Kim@Sun.COM  *
1683*10652SHyon.Kim@Sun.COM  * Arguments:
1684*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1685*10652SHyon.Kim@Sun.COM  *      portIndex - hba port index
1686*10652SHyon.Kim@Sun.COM  *      port - hba port attributes.
1687*10652SHyon.Kim@Sun.COM  *      targetportWWN - target port SAS address.
1688*10652SHyon.Kim@Sun.COM  *      domainportWWN - domain port SAS address.
1689*10652SHyon.Kim@Sun.COM  *      domainportttr - target port SAS attributes.
1690*10652SHyon.Kim@Sun.COM  *      samLUN - samLUN from report LUNs data.
1691*10652SHyon.Kim@Sun.COM  *      data - matching target mapping data.
1692*10652SHyon.Kim@Sun.COM  *
1693*10652SHyon.Kim@Sun.COM  *  Return Value:
1694*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1695*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1696*10652SHyon.Kim@Sun.COM  */
1697*10652SHyon.Kim@Sun.COM static int
searchTargetPortMappingData(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_SAS_PORT * sasattr,struct targetPortConfig * configData)1698*10652SHyon.Kim@Sun.COM searchTargetPortMappingData(HBA_HANDLE handle, HBA_UINT32 portIndex,
1699*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, SMHBA_SAS_PORT *sasattr,
1700*10652SHyon.Kim@Sun.COM     struct targetPortConfig *configData)
1701*10652SHyon.Kim@Sun.COM {
1702*10652SHyon.Kim@Sun.COM 	int			ret = 0;
1703*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
1704*10652SHyon.Kim@Sun.COM 	SMHBA_TARGETMAPPING	*map = NULL;
1705*10652SHyon.Kim@Sun.COM 	HBA_WWN			hbaPortWWN, domainPortWWN;
1706*10652SHyon.Kim@Sun.COM 	int			numentries, count;
1707*10652SHyon.Kim@Sun.COM 	targetPortMappingData_t	*TPMapData;
1708*10652SHyon.Kim@Sun.COM 	struct scsi_inquiry	inq;
1709*10652SHyon.Kim@Sun.COM 	struct scsi_extended_sense  sense;
1710*10652SHyon.Kim@Sun.COM 	HBA_UINT32		responseSize, senseSize = 0;
1711*10652SHyon.Kim@Sun.COM 	uchar_t			rawLUNs[DEFAULT_LUN_LENGTH], *lun_string;
1712*10652SHyon.Kim@Sun.COM 	HBA_UINT8		scsiStatus;
1713*10652SHyon.Kim@Sun.COM 	rep_luns_rsp_t		*lun_resp;
1714*10652SHyon.Kim@Sun.COM 	int			lunNum, numberOfLun, lunCount;
1715*10652SHyon.Kim@Sun.COM 	uint32_t		lunlength, tmp_lunlength;
1716*10652SHyon.Kim@Sun.COM 	uint64_t		sasLUN;
1717*10652SHyon.Kim@Sun.COM 	SMHBA_SCSILUN		smhbaLUN;
1718*10652SHyon.Kim@Sun.COM 
1719*10652SHyon.Kim@Sun.COM 	hbaPortWWN = port->PortSpecificAttribute.SASPort->
1720*10652SHyon.Kim@Sun.COM 	    LocalSASAddress;
1721*10652SHyon.Kim@Sun.COM 
1722*10652SHyon.Kim@Sun.COM 	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
1723*10652SHyon.Kim@Sun.COM 	if (status == HBA_STATUS_OK) {
1724*10652SHyon.Kim@Sun.COM 		if ((map = calloc(1, sizeof (*map))) == NULL) {
1725*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n",
1726*10652SHyon.Kim@Sun.COM 			gettext("No enough memory on heap."));
1727*10652SHyon.Kim@Sun.COM 			return (++ret);
1728*10652SHyon.Kim@Sun.COM 		}
1729*10652SHyon.Kim@Sun.COM 		map->NumberOfEntries = 1;
1730*10652SHyon.Kim@Sun.COM 
1731*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetTargetMapping(handle, hbaPortWWN,
1732*10652SHyon.Kim@Sun.COM 		    domainPortWWN, map);
1733*10652SHyon.Kim@Sun.COM 
1734*10652SHyon.Kim@Sun.COM 		if (status == HBA_STATUS_ERROR_MORE_DATA) {
1735*10652SHyon.Kim@Sun.COM 			numentries = map->NumberOfEntries;
1736*10652SHyon.Kim@Sun.COM 			free(map);
1737*10652SHyon.Kim@Sun.COM 			map = calloc(1, sizeof (HBA_UINT32) +
1738*10652SHyon.Kim@Sun.COM 			    (numentries * sizeof (SMHBA_SCSIENTRY)));
1739*10652SHyon.Kim@Sun.COM 			if (map == NULL) {
1740*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr, "%s\n",
1741*10652SHyon.Kim@Sun.COM 				    gettext("No enough memory on heap."));
1742*10652SHyon.Kim@Sun.COM 				return (++ret);
1743*10652SHyon.Kim@Sun.COM 			}
1744*10652SHyon.Kim@Sun.COM 			map->NumberOfEntries = numentries;
1745*10652SHyon.Kim@Sun.COM 			status = SMHBA_GetTargetMapping(handle,
1746*10652SHyon.Kim@Sun.COM 			    hbaPortWWN, domainPortWWN, map);
1747*10652SHyon.Kim@Sun.COM 		}
1748*10652SHyon.Kim@Sun.COM 
1749*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
1750*10652SHyon.Kim@Sun.COM 			/* continue to build mapping data based SCSI info */
1751*10652SHyon.Kim@Sun.COM 			ret++;
1752*10652SHyon.Kim@Sun.COM 			free(map);
1753*10652SHyon.Kim@Sun.COM 			map = NULL;
1754*10652SHyon.Kim@Sun.COM 		}
1755*10652SHyon.Kim@Sun.COM 	}
1756*10652SHyon.Kim@Sun.COM 
1757*10652SHyon.Kim@Sun.COM 	/*
1758*10652SHyon.Kim@Sun.COM 	 * Get report lun data.
1759*10652SHyon.Kim@Sun.COM 	 */
1760*10652SHyon.Kim@Sun.COM 	responseSize = DEFAULT_LUN_LENGTH;
1761*10652SHyon.Kim@Sun.COM 	senseSize = sizeof (struct scsi_extended_sense);
1762*10652SHyon.Kim@Sun.COM 	(void) memset(&sense, 0, sizeof (sense));
1763*10652SHyon.Kim@Sun.COM 	status = SMHBA_ScsiReportLUNs(
1764*10652SHyon.Kim@Sun.COM 	    handle,
1765*10652SHyon.Kim@Sun.COM 	    hbaPortWWN,
1766*10652SHyon.Kim@Sun.COM 	    sasattr->LocalSASAddress,
1767*10652SHyon.Kim@Sun.COM 	    domainPortWWN,
1768*10652SHyon.Kim@Sun.COM 	    (void *)rawLUNs,
1769*10652SHyon.Kim@Sun.COM 	    &responseSize,
1770*10652SHyon.Kim@Sun.COM 	    &scsiStatus,
1771*10652SHyon.Kim@Sun.COM 	    (void *) &sense, &senseSize);
1772*10652SHyon.Kim@Sun.COM 
1773*10652SHyon.Kim@Sun.COM 	/*
1774*10652SHyon.Kim@Sun.COM 	 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
1775*10652SHyon.Kim@Sun.COM 	 * a remote HBA and move on
1776*10652SHyon.Kim@Sun.COM 	 */
1777*10652SHyon.Kim@Sun.COM 	if (status != HBA_STATUS_OK) {
1778*10652SHyon.Kim@Sun.COM 		configData->reportLUNsFailed = B_TRUE;
1779*10652SHyon.Kim@Sun.COM 		if (map != NULL) {
1780*10652SHyon.Kim@Sun.COM 			/*
1781*10652SHyon.Kim@Sun.COM 			 * Let's search mapping data and indicate that Report
1782*10652SHyon.Kim@Sun.COM 			 * LUNs failed.
1783*10652SHyon.Kim@Sun.COM 			 */
1784*10652SHyon.Kim@Sun.COM 			for (count = 0; count < map->NumberOfEntries; count++) {
1785*10652SHyon.Kim@Sun.COM 				if (memcmp(map->entry[count].PortLun.
1786*10652SHyon.Kim@Sun.COM 				    PortWWN.wwn, sasattr->LocalSASAddress.wwn,
1787*10652SHyon.Kim@Sun.COM 				    sizeof (HBA_WWN)) == 0) {
1788*10652SHyon.Kim@Sun.COM 					/* allocate mapping data for each LUN */
1789*10652SHyon.Kim@Sun.COM 					TPMapData = calloc(1,
1790*10652SHyon.Kim@Sun.COM 					    sizeof (targetPortMappingData_t));
1791*10652SHyon.Kim@Sun.COM 					if (TPMapData == NULL) {
1792*10652SHyon.Kim@Sun.COM 						(void *) fprintf(stderr, "%s\n",
1793*10652SHyon.Kim@Sun.COM 						    gettext("No enough "
1794*10652SHyon.Kim@Sun.COM 						    "memory."));
1795*10652SHyon.Kim@Sun.COM 						free(map);
1796*10652SHyon.Kim@Sun.COM 						return (++ret);
1797*10652SHyon.Kim@Sun.COM 					}
1798*10652SHyon.Kim@Sun.COM 					TPMapData->mappingExist = B_TRUE;
1799*10652SHyon.Kim@Sun.COM 					TPMapData->osLUN =
1800*10652SHyon.Kim@Sun.COM 					    map->entry[count].ScsiId.ScsiOSLun;
1801*10652SHyon.Kim@Sun.COM 					(void) strlcpy(TPMapData->osDeviceName,
1802*10652SHyon.Kim@Sun.COM 					    map->entry[count].ScsiId.
1803*10652SHyon.Kim@Sun.COM 					    OSDeviceName,
1804*10652SHyon.Kim@Sun.COM 					    sizeof (TPMapData->osDeviceName));
1805*10652SHyon.Kim@Sun.COM 					TPMapData->inq_vid[0] = '\0';
1806*10652SHyon.Kim@Sun.COM 					TPMapData->inq_pid[0] = '\0';
1807*10652SHyon.Kim@Sun.COM 					TPMapData->inq_dtype = DTYPE_UNKNOWN;
1808*10652SHyon.Kim@Sun.COM 					if (configData->map == NULL) {
1809*10652SHyon.Kim@Sun.COM 						configData->map = TPMapData;
1810*10652SHyon.Kim@Sun.COM 					} else {
1811*10652SHyon.Kim@Sun.COM 						TPMapData->next =
1812*10652SHyon.Kim@Sun.COM 						    configData->map->next;
1813*10652SHyon.Kim@Sun.COM 						configData->map = TPMapData;
1814*10652SHyon.Kim@Sun.COM 					}
1815*10652SHyon.Kim@Sun.COM 				}
1816*10652SHyon.Kim@Sun.COM 			}
1817*10652SHyon.Kim@Sun.COM 		}
1818*10652SHyon.Kim@Sun.COM 		(void) free(map);
1819*10652SHyon.Kim@Sun.COM 		return (++ret);
1820*10652SHyon.Kim@Sun.COM 	}
1821*10652SHyon.Kim@Sun.COM 	lun_resp = (rep_luns_rsp_t *)((void *)rawLUNs);
1822*10652SHyon.Kim@Sun.COM 	(void) memcpy(&tmp_lunlength, &(lun_resp->length),
1823*10652SHyon.Kim@Sun.COM 	    sizeof (tmp_lunlength));
1824*10652SHyon.Kim@Sun.COM 	lunlength = ntohl(tmp_lunlength);
1825*10652SHyon.Kim@Sun.COM 	(void) memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
1826*10652SHyon.Kim@Sun.COM 	for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
1827*10652SHyon.Kim@Sun.COM 		/* allocate mapping data for each LUN */
1828*10652SHyon.Kim@Sun.COM 		TPMapData = calloc(1,
1829*10652SHyon.Kim@Sun.COM 		    sizeof (targetPortMappingData_t));
1830*10652SHyon.Kim@Sun.COM 		if (TPMapData == NULL) {
1831*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n",
1832*10652SHyon.Kim@Sun.COM 			    gettext("No enough memory."));
1833*10652SHyon.Kim@Sun.COM 			free(map);
1834*10652SHyon.Kim@Sun.COM 			return (++ret);
1835*10652SHyon.Kim@Sun.COM 		}
1836*10652SHyon.Kim@Sun.COM 
1837*10652SHyon.Kim@Sun.COM 		(void) memcpy(&TPMapData->reportLUN, lun_resp->
1838*10652SHyon.Kim@Sun.COM 		    lun[lunCount].val, sizeof (SMHBA_SCSILUN));
1839*10652SHyon.Kim@Sun.COM 
1840*10652SHyon.Kim@Sun.COM 		/*
1841*10652SHyon.Kim@Sun.COM 		 * now issue standard inquiry to get Vendor
1842*10652SHyon.Kim@Sun.COM 		 * and product information
1843*10652SHyon.Kim@Sun.COM 		 */
1844*10652SHyon.Kim@Sun.COM 		responseSize = sizeof (struct scsi_inquiry);
1845*10652SHyon.Kim@Sun.COM 		senseSize = sizeof (struct scsi_extended_sense);
1846*10652SHyon.Kim@Sun.COM 		(void) memset(&inq, 0, sizeof (struct scsi_inquiry));
1847*10652SHyon.Kim@Sun.COM 		(void) memset(&sense, 0, sizeof (sense));
1848*10652SHyon.Kim@Sun.COM 		sasLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
1849*10652SHyon.Kim@Sun.COM 		(void) memcpy(&smhbaLUN, &sasLUN, sizeof (SMHBA_SCSILUN));
1850*10652SHyon.Kim@Sun.COM 		status = SMHBA_ScsiInquiry(
1851*10652SHyon.Kim@Sun.COM 		    handle,
1852*10652SHyon.Kim@Sun.COM 		    hbaPortWWN,
1853*10652SHyon.Kim@Sun.COM 		    sasattr->LocalSASAddress,
1854*10652SHyon.Kim@Sun.COM 		    domainPortWWN,
1855*10652SHyon.Kim@Sun.COM 		    smhbaLUN,
1856*10652SHyon.Kim@Sun.COM 		    0,
1857*10652SHyon.Kim@Sun.COM 		    0,
1858*10652SHyon.Kim@Sun.COM 		    (void *) &inq, &responseSize,
1859*10652SHyon.Kim@Sun.COM 		    &scsiStatus,
1860*10652SHyon.Kim@Sun.COM 		    (void *) &sense, &senseSize);
1861*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
1862*10652SHyon.Kim@Sun.COM 			TPMapData->inq_vid[0] = '\0';
1863*10652SHyon.Kim@Sun.COM 			TPMapData->inq_pid[0] = '\0';
1864*10652SHyon.Kim@Sun.COM 			TPMapData->inq_dtype = DTYPE_UNKNOWN;
1865*10652SHyon.Kim@Sun.COM 			/* indicate that inquiry for this lun is failed */
1866*10652SHyon.Kim@Sun.COM 			TPMapData->inquiryFailed = B_TRUE;
1867*10652SHyon.Kim@Sun.COM 		} else {
1868*10652SHyon.Kim@Sun.COM 			(void *) memcpy(TPMapData->inq_vid, inq.inq_vid,
1869*10652SHyon.Kim@Sun.COM 			    sizeof (TPMapData->inq_vid));
1870*10652SHyon.Kim@Sun.COM 			(void *) memcpy(TPMapData->inq_pid, inq.inq_pid,
1871*10652SHyon.Kim@Sun.COM 			    sizeof (TPMapData->inq_pid));
1872*10652SHyon.Kim@Sun.COM 			TPMapData->inq_dtype = inq.inq_dtype;
1873*10652SHyon.Kim@Sun.COM 		}
1874*10652SHyon.Kim@Sun.COM 
1875*10652SHyon.Kim@Sun.COM 		if (map != NULL) {
1876*10652SHyon.Kim@Sun.COM 			for (count = 0; count < map->NumberOfEntries; count++) {
1877*10652SHyon.Kim@Sun.COM 				if ((memcmp(map->entry[count].PortLun.
1878*10652SHyon.Kim@Sun.COM 				    PortWWN.wwn, sasattr->LocalSASAddress.wwn,
1879*10652SHyon.Kim@Sun.COM 				    sizeof (HBA_WWN)) == 0) &&
1880*10652SHyon.Kim@Sun.COM 				    (memcmp(&(map->entry[count].PortLun.
1881*10652SHyon.Kim@Sun.COM 				    TargetLun), &smhbaLUN,
1882*10652SHyon.Kim@Sun.COM 				    sizeof (SMHBA_SCSILUN))
1883*10652SHyon.Kim@Sun.COM 				    == 0)) {
1884*10652SHyon.Kim@Sun.COM 					TPMapData->mappingExist = B_TRUE;
1885*10652SHyon.Kim@Sun.COM 					TPMapData->osLUN =
1886*10652SHyon.Kim@Sun.COM 					    map->entry[count].ScsiId.ScsiOSLun;
1887*10652SHyon.Kim@Sun.COM 					(void) strlcpy(TPMapData->osDeviceName,
1888*10652SHyon.Kim@Sun.COM 					    map->entry[count].ScsiId.
1889*10652SHyon.Kim@Sun.COM 					    OSDeviceName,
1890*10652SHyon.Kim@Sun.COM 					    sizeof (TPMapData->osDeviceName));
1891*10652SHyon.Kim@Sun.COM 					break;
1892*10652SHyon.Kim@Sun.COM 				}
1893*10652SHyon.Kim@Sun.COM 			}
1894*10652SHyon.Kim@Sun.COM 			if (count == map->NumberOfEntries) {
1895*10652SHyon.Kim@Sun.COM 				TPMapData->osDeviceName[0] = '\0';
1896*10652SHyon.Kim@Sun.COM 				lun_string = lun_resp->lun[lunCount].val;
1897*10652SHyon.Kim@Sun.COM 				lunNum = ((lun_string[0] & 0x3F) << 8) |
1898*10652SHyon.Kim@Sun.COM 				    lun_string[1];
1899*10652SHyon.Kim@Sun.COM 				TPMapData->osLUN = lunNum;
1900*10652SHyon.Kim@Sun.COM 			}
1901*10652SHyon.Kim@Sun.COM 		} else {
1902*10652SHyon.Kim@Sun.COM 		/* Not able to get any target mapping information */
1903*10652SHyon.Kim@Sun.COM 			TPMapData->osDeviceName[0] = '\0';
1904*10652SHyon.Kim@Sun.COM 			lun_string = lun_resp->lun[lunCount].val;
1905*10652SHyon.Kim@Sun.COM 			lunNum = ((lun_string[0] & 0x3F) << 8) |
1906*10652SHyon.Kim@Sun.COM 			    lun_string[1];
1907*10652SHyon.Kim@Sun.COM 			TPMapData->osLUN = lunNum;
1908*10652SHyon.Kim@Sun.COM 		}
1909*10652SHyon.Kim@Sun.COM 
1910*10652SHyon.Kim@Sun.COM 		if (configData->map == NULL) {
1911*10652SHyon.Kim@Sun.COM 			configData->map = TPMapData;
1912*10652SHyon.Kim@Sun.COM 		} else {
1913*10652SHyon.Kim@Sun.COM 			TPMapData->next = configData->map->next;
1914*10652SHyon.Kim@Sun.COM 			configData->map = TPMapData;
1915*10652SHyon.Kim@Sun.COM 		}
1916*10652SHyon.Kim@Sun.COM 	}
1917*10652SHyon.Kim@Sun.COM 	free(map);
1918*10652SHyon.Kim@Sun.COM 	return (ret);
1919*10652SHyon.Kim@Sun.COM }
1920*10652SHyon.Kim@Sun.COM 
1921*10652SHyon.Kim@Sun.COM /*
1922*10652SHyon.Kim@Sun.COM  * Search the discovered LUs and construct the global LU list.
1923*10652SHyon.Kim@Sun.COM  *
1924*10652SHyon.Kim@Sun.COM  * Arguments:
1925*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
1926*10652SHyon.Kim@Sun.COM  *      portIndex - hba port index
1927*10652SHyon.Kim@Sun.COM  *      port - hba port attributes.
1928*10652SHyon.Kim@Sun.COM  *      targetattr - target port attributes.
1929*10652SHyon.Kim@Sun.COM  *      sasattr - target port SAS attributes.
1930*10652SHyon.Kim@Sun.COM  *      pflag - options the user specified.
1931*10652SHyon.Kim@Sun.COM  *
1932*10652SHyon.Kim@Sun.COM  *  Return Value:
1933*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
1934*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
1935*10652SHyon.Kim@Sun.COM  */
1936*10652SHyon.Kim@Sun.COM static int
searchTargetPort(HBA_HANDLE handle,HBA_UINT32 portIndex,SMHBA_PORTATTRIBUTES * port,SMHBA_PORTATTRIBUTES * targetattr,SMHBA_SAS_PORT * sasattr,int pflag)1937*10652SHyon.Kim@Sun.COM searchTargetPort(HBA_HANDLE handle, HBA_UINT32 portIndex,
1938*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, SMHBA_PORTATTRIBUTES *targetattr,
1939*10652SHyon.Kim@Sun.COM     SMHBA_SAS_PORT *sasattr, int pflag)
1940*10652SHyon.Kim@Sun.COM {
1941*10652SHyon.Kim@Sun.COM 	int			ret = 0;
1942*10652SHyon.Kim@Sun.COM 	HBA_WWN			expander;
1943*10652SHyon.Kim@Sun.COM 	HBA_WWN			domainPortWWN;
1944*10652SHyon.Kim@Sun.COM 	targetPortList_t 	*discoveredTP, *newTP;
1945*10652SHyon.Kim@Sun.COM 	targetPortConfig_t	*TPConfig, *newConfig, *prevConfig;
1946*10652SHyon.Kim@Sun.COM 	boolean_t		foundTP = B_FALSE;
1947*10652SHyon.Kim@Sun.COM 	boolean_t		foundConfig = B_FALSE;
1948*10652SHyon.Kim@Sun.COM 	int			status;
1949*10652SHyon.Kim@Sun.COM 	SMHBA_PORTATTRIBUTES	tgtattr;
1950*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PORT		tgtsasport;
1951*10652SHyon.Kim@Sun.COM 	int			expanderValid = 0;
1952*10652SHyon.Kim@Sun.COM 
1953*10652SHyon.Kim@Sun.COM 	status = get_domainPort(handle, portIndex, port, &domainPortWWN);
1954*10652SHyon.Kim@Sun.COM 	switch (status) {
1955*10652SHyon.Kim@Sun.COM 		case HBA_STATUS_OK:
1956*10652SHyon.Kim@Sun.COM 			break;
1957*10652SHyon.Kim@Sun.COM 		case HBA_STATUS_ERROR_NOT_SUPPORTED:
1958*10652SHyon.Kim@Sun.COM 			/* don't increase error flag for no phy configuration */
1959*10652SHyon.Kim@Sun.COM 			return (ret);
1960*10652SHyon.Kim@Sun.COM 		case HBA_STATUS_ERROR:
1961*10652SHyon.Kim@Sun.COM 		default:
1962*10652SHyon.Kim@Sun.COM 			return (++ret);
1963*10652SHyon.Kim@Sun.COM 	}
1964*10652SHyon.Kim@Sun.COM 
1965*10652SHyon.Kim@Sun.COM 	/*
1966*10652SHyon.Kim@Sun.COM 	 * First, we will iterate the already constructed target port
1967*10652SHyon.Kim@Sun.COM 	 * list to see whether there is a target port already exist with
1968*10652SHyon.Kim@Sun.COM 	 * matching target port SAS address.
1969*10652SHyon.Kim@Sun.COM 	 */
1970*10652SHyon.Kim@Sun.COM 	for (discoveredTP = gTargetPortList; discoveredTP != NULL;
1971*10652SHyon.Kim@Sun.COM 	    discoveredTP = discoveredTP->next) {
1972*10652SHyon.Kim@Sun.COM 		if (memcmp((void *)sasattr->LocalSASAddress.wwn,
1973*10652SHyon.Kim@Sun.COM 		    (void *)discoveredTP->sasattr.LocalSASAddress.wwn,
1974*10652SHyon.Kim@Sun.COM 		    sizeof (HBA_WWN)) == 0) {
1975*10652SHyon.Kim@Sun.COM 			/*
1976*10652SHyon.Kim@Sun.COM 			 * if the target port exist and
1977*10652SHyon.Kim@Sun.COM 			 * verbose is not set, just return
1978*10652SHyon.Kim@Sun.COM 			 */
1979*10652SHyon.Kim@Sun.COM 			if (((pflag & PRINT_VERBOSE) == 0) &&
1980*10652SHyon.Kim@Sun.COM 			    ((pflag & PRINT_TARGET_SCSI) == 0)) {
1981*10652SHyon.Kim@Sun.COM 				return (ret);
1982*10652SHyon.Kim@Sun.COM 			}
1983*10652SHyon.Kim@Sun.COM 			foundTP = B_TRUE;
1984*10652SHyon.Kim@Sun.COM 			break;
1985*10652SHyon.Kim@Sun.COM 		}
1986*10652SHyon.Kim@Sun.COM 	}
1987*10652SHyon.Kim@Sun.COM 
1988*10652SHyon.Kim@Sun.COM 	if (foundTP == B_TRUE) {
1989*10652SHyon.Kim@Sun.COM 		/*
1990*10652SHyon.Kim@Sun.COM 		 * If there is a target port already exist, we should
1991*10652SHyon.Kim@Sun.COM 		 * add more information on the target port to construct the
1992*10652SHyon.Kim@Sun.COM 		 * whole topology.
1993*10652SHyon.Kim@Sun.COM 		 * Here we will check whether the current hba port name
1994*10652SHyon.Kim@Sun.COM 		 * has already been added.
1995*10652SHyon.Kim@Sun.COM 		 */
1996*10652SHyon.Kim@Sun.COM 		/* first get the expander SAS address compare */
1997*10652SHyon.Kim@Sun.COM 		if (memcmp((void *)port->PortSpecificAttribute.SASPort->
1998*10652SHyon.Kim@Sun.COM 		    LocalSASAddress.wwn, (void *)sasattr->
1999*10652SHyon.Kim@Sun.COM 		    AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
2000*10652SHyon.Kim@Sun.COM 			/* NO expander */
2001*10652SHyon.Kim@Sun.COM 			(void) memset((void *)expander.wwn, 0,
2002*10652SHyon.Kim@Sun.COM 			    sizeof (HBA_WWN));
2003*10652SHyon.Kim@Sun.COM 			expanderValid = 1;
2004*10652SHyon.Kim@Sun.COM 		} else {
2005*10652SHyon.Kim@Sun.COM 			if (wwnConversion(sasattr->AttachedSASAddress.wwn)
2006*10652SHyon.Kim@Sun.COM 			    != 0) {
2007*10652SHyon.Kim@Sun.COM 				/* expander exist.  We should verify it.  */
2008*10652SHyon.Kim@Sun.COM 				(void) memcpy((void *)expander.wwn,
2009*10652SHyon.Kim@Sun.COM 				    (void *)sasattr->AttachedSASAddress.wwn,
2010*10652SHyon.Kim@Sun.COM 				    sizeof (HBA_WWN));
2011*10652SHyon.Kim@Sun.COM 
2012*10652SHyon.Kim@Sun.COM 				(void *) memset(&tgtattr, 0, sizeof (tgtattr));
2013*10652SHyon.Kim@Sun.COM 				(void *) memset(&tgtsasport, 0,
2014*10652SHyon.Kim@Sun.COM 				    sizeof (tgtsasport));
2015*10652SHyon.Kim@Sun.COM 				tgtattr.PortSpecificAttribute.SASPort
2016*10652SHyon.Kim@Sun.COM 				    = &tgtsasport;
2017*10652SHyon.Kim@Sun.COM 				status = SMHBA_GetPortAttributesByWWN(handle,
2018*10652SHyon.Kim@Sun.COM 				    sasattr->AttachedSASAddress, domainPortWWN,
2019*10652SHyon.Kim@Sun.COM 				    &tgtattr);
2020*10652SHyon.Kim@Sun.COM 				if (status == HBA_STATUS_OK && tgtattr.PortType
2021*10652SHyon.Kim@Sun.COM 				    == HBA_PORTTYPE_SASEXPANDER) {
2022*10652SHyon.Kim@Sun.COM 					expanderValid = 1;
2023*10652SHyon.Kim@Sun.COM 				}
2024*10652SHyon.Kim@Sun.COM 			}
2025*10652SHyon.Kim@Sun.COM 		}
2026*10652SHyon.Kim@Sun.COM 
2027*10652SHyon.Kim@Sun.COM 		for (TPConfig = discoveredTP->configEntry,
2028*10652SHyon.Kim@Sun.COM 		    foundConfig = B_FALSE; TPConfig != NULL;
2029*10652SHyon.Kim@Sun.COM 		    TPConfig = TPConfig->next) {
2030*10652SHyon.Kim@Sun.COM 			if ((strcmp(TPConfig->hbaPortName,
2031*10652SHyon.Kim@Sun.COM 			    port->OSDeviceName) == 0) &&
2032*10652SHyon.Kim@Sun.COM 			    (memcmp((void *)expander.wwn, (void *)TPConfig->
2033*10652SHyon.Kim@Sun.COM 			    expanderSASAddr.wwn,
2034*10652SHyon.Kim@Sun.COM 			    sizeof (HBA_WWN)) == 0)) {
2035*10652SHyon.Kim@Sun.COM 				foundConfig = B_TRUE;
2036*10652SHyon.Kim@Sun.COM 				break;
2037*10652SHyon.Kim@Sun.COM 			}
2038*10652SHyon.Kim@Sun.COM 		}
2039*10652SHyon.Kim@Sun.COM 
2040*10652SHyon.Kim@Sun.COM 		/*
2041*10652SHyon.Kim@Sun.COM 		 * If we get here, it means that it is a new hba port/exapnder
2042*10652SHyon.Kim@Sun.COM 		 * sas address for this discovered target port.
2043*10652SHyon.Kim@Sun.COM 		 */
2044*10652SHyon.Kim@Sun.COM 		if (foundConfig == B_FALSE) {
2045*10652SHyon.Kim@Sun.COM 			newConfig = (targetPortConfig_t *)calloc(1,
2046*10652SHyon.Kim@Sun.COM 			    sizeof (targetPortConfig_t));
2047*10652SHyon.Kim@Sun.COM 			if (newConfig == NULL) {
2048*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr,
2049*10652SHyon.Kim@Sun.COM 				    "%s\n", strerror(errno));
2050*10652SHyon.Kim@Sun.COM 				return (++ret);
2051*10652SHyon.Kim@Sun.COM 			}
2052*10652SHyon.Kim@Sun.COM 
2053*10652SHyon.Kim@Sun.COM 			(void) strlcpy(newConfig->hbaPortName, port->
2054*10652SHyon.Kim@Sun.COM 			    OSDeviceName, sizeof (newConfig->hbaPortName));
2055*10652SHyon.Kim@Sun.COM 			(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
2056*10652SHyon.Kim@Sun.COM 			    (void *)expander.wwn, sizeof (HBA_WWN));
2057*10652SHyon.Kim@Sun.COM 			newConfig->expanderValid = expanderValid;
2058*10652SHyon.Kim@Sun.COM 			if (discoveredTP->configEntry == NULL) {
2059*10652SHyon.Kim@Sun.COM 				discoveredTP->configEntry = newConfig;
2060*10652SHyon.Kim@Sun.COM 			} else {
2061*10652SHyon.Kim@Sun.COM 				TPConfig = discoveredTP->configEntry;
2062*10652SHyon.Kim@Sun.COM 				prevConfig = TPConfig;
2063*10652SHyon.Kim@Sun.COM 				while (TPConfig != NULL &&
2064*10652SHyon.Kim@Sun.COM 				    sas_name_comp(newConfig->hbaPortName,
2065*10652SHyon.Kim@Sun.COM 				    TPConfig->hbaPortName) > 0) {
2066*10652SHyon.Kim@Sun.COM 					prevConfig = TPConfig;
2067*10652SHyon.Kim@Sun.COM 					TPConfig = TPConfig->next;
2068*10652SHyon.Kim@Sun.COM 				}
2069*10652SHyon.Kim@Sun.COM 				if (TPConfig == prevConfig) {
2070*10652SHyon.Kim@Sun.COM 					/* Should be inserted in the head. */
2071*10652SHyon.Kim@Sun.COM 					newConfig->next = TPConfig;
2072*10652SHyon.Kim@Sun.COM 					discoveredTP->configEntry = newConfig;
2073*10652SHyon.Kim@Sun.COM 				} else {
2074*10652SHyon.Kim@Sun.COM 					newConfig->next = TPConfig;
2075*10652SHyon.Kim@Sun.COM 					prevConfig->next = newConfig;
2076*10652SHyon.Kim@Sun.COM 				}
2077*10652SHyon.Kim@Sun.COM 			}
2078*10652SHyon.Kim@Sun.COM 			/* if scsi option is not set return */
2079*10652SHyon.Kim@Sun.COM 			if ((pflag & PRINT_TARGET_SCSI) == 0) {
2080*10652SHyon.Kim@Sun.COM 				return (0);
2081*10652SHyon.Kim@Sun.COM 			} else {
2082*10652SHyon.Kim@Sun.COM 				return (searchTargetPortMappingData(
2083*10652SHyon.Kim@Sun.COM 				    handle, portIndex, port,
2084*10652SHyon.Kim@Sun.COM 				    sasattr, newConfig));
2085*10652SHyon.Kim@Sun.COM 			}
2086*10652SHyon.Kim@Sun.COM 		}
2087*10652SHyon.Kim@Sun.COM 	} else {
2088*10652SHyon.Kim@Sun.COM 		/*
2089*10652SHyon.Kim@Sun.COM 		 * Here we got a new target port which has not ever exist
2090*10652SHyon.Kim@Sun.COM 		 * in our global target port list. So add it to the list.
2091*10652SHyon.Kim@Sun.COM 		 * list.
2092*10652SHyon.Kim@Sun.COM 		 */
2093*10652SHyon.Kim@Sun.COM 		newTP = (targetPortList_t *)calloc(1,
2094*10652SHyon.Kim@Sun.COM 		    sizeof (targetPortList_t));
2095*10652SHyon.Kim@Sun.COM 
2096*10652SHyon.Kim@Sun.COM 		if (newTP == NULL) {
2097*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n", strerror(errno));
2098*10652SHyon.Kim@Sun.COM 			return (++ret);
2099*10652SHyon.Kim@Sun.COM 		}
2100*10652SHyon.Kim@Sun.COM 
2101*10652SHyon.Kim@Sun.COM 		(void) memcpy((void *)&newTP->targetattr, (void *)targetattr,
2102*10652SHyon.Kim@Sun.COM 		    sizeof (SMHBA_PORTATTRIBUTES));
2103*10652SHyon.Kim@Sun.COM 		(void) memcpy((void *)&newTP->sasattr, (void *)sasattr,
2104*10652SHyon.Kim@Sun.COM 		    sizeof (SMHBA_SAS_PORT));
2105*10652SHyon.Kim@Sun.COM 
2106*10652SHyon.Kim@Sun.COM 		newConfig = (targetPortConfig_t *)calloc(1,
2107*10652SHyon.Kim@Sun.COM 		    sizeof (targetPortConfig_t));
2108*10652SHyon.Kim@Sun.COM 
2109*10652SHyon.Kim@Sun.COM 		if (newConfig == NULL) {
2110*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n", strerror(errno));
2111*10652SHyon.Kim@Sun.COM 			free(newTP);
2112*10652SHyon.Kim@Sun.COM 			return (++ret);
2113*10652SHyon.Kim@Sun.COM 		}
2114*10652SHyon.Kim@Sun.COM 
2115*10652SHyon.Kim@Sun.COM 		(void) strlcpy(newConfig->hbaPortName, port->OSDeviceName,
2116*10652SHyon.Kim@Sun.COM 		    sizeof (newConfig->hbaPortName));
2117*10652SHyon.Kim@Sun.COM 		if (memcmp((void *)port->PortSpecificAttribute.SASPort->
2118*10652SHyon.Kim@Sun.COM 		    LocalSASAddress.wwn, (void *)sasattr->
2119*10652SHyon.Kim@Sun.COM 		    AttachedSASAddress.wwn, sizeof (HBA_WWN)) == 0) {
2120*10652SHyon.Kim@Sun.COM 			/* NO expander */
2121*10652SHyon.Kim@Sun.COM 			(void) memset((void *)newConfig->expanderSASAddr.wwn,
2122*10652SHyon.Kim@Sun.COM 			    0, sizeof (HBA_WWN));
2123*10652SHyon.Kim@Sun.COM 		} else {
2124*10652SHyon.Kim@Sun.COM 			/* expander exist.  We should verify it. */
2125*10652SHyon.Kim@Sun.COM 			(void) memcpy((void *)newConfig->expanderSASAddr.wwn,
2126*10652SHyon.Kim@Sun.COM 			    (void *)sasattr->AttachedSASAddress.wwn,
2127*10652SHyon.Kim@Sun.COM 			    sizeof (HBA_WWN));
2128*10652SHyon.Kim@Sun.COM 
2129*10652SHyon.Kim@Sun.COM 			(void *) memset(&tgtattr, 0, sizeof (tgtattr));
2130*10652SHyon.Kim@Sun.COM 			(void *) memset(&tgtsasport, 0, sizeof (tgtsasport));
2131*10652SHyon.Kim@Sun.COM 			tgtattr.PortSpecificAttribute.SASPort = &tgtsasport;
2132*10652SHyon.Kim@Sun.COM 			status = SMHBA_GetPortAttributesByWWN(handle,
2133*10652SHyon.Kim@Sun.COM 			    sasattr->AttachedSASAddress, domainPortWWN,
2134*10652SHyon.Kim@Sun.COM 			    &tgtattr);
2135*10652SHyon.Kim@Sun.COM 			if (status == HBA_STATUS_OK && tgtattr.PortType ==
2136*10652SHyon.Kim@Sun.COM 			    HBA_PORTTYPE_SASEXPANDER) {
2137*10652SHyon.Kim@Sun.COM 				expanderValid = 1;
2138*10652SHyon.Kim@Sun.COM 			}
2139*10652SHyon.Kim@Sun.COM 			newConfig->expanderValid = expanderValid;
2140*10652SHyon.Kim@Sun.COM 		}
2141*10652SHyon.Kim@Sun.COM 
2142*10652SHyon.Kim@Sun.COM 		newTP->configEntry = newConfig;
2143*10652SHyon.Kim@Sun.COM 
2144*10652SHyon.Kim@Sun.COM 		newTP->next = gTargetPortList; /* insert at head */
2145*10652SHyon.Kim@Sun.COM 		gTargetPortList = newTP; /* set new head */
2146*10652SHyon.Kim@Sun.COM 
2147*10652SHyon.Kim@Sun.COM 		/* if scsi option is not set return */
2148*10652SHyon.Kim@Sun.COM 		if ((pflag & PRINT_TARGET_SCSI) == 0) {
2149*10652SHyon.Kim@Sun.COM 			return (0);
2150*10652SHyon.Kim@Sun.COM 		} else {
2151*10652SHyon.Kim@Sun.COM 			return (searchTargetPortMappingData(
2152*10652SHyon.Kim@Sun.COM 			    handle, portIndex, port, sasattr, newConfig));
2153*10652SHyon.Kim@Sun.COM 		}
2154*10652SHyon.Kim@Sun.COM 	}
2155*10652SHyon.Kim@Sun.COM 	return (ret);
2156*10652SHyon.Kim@Sun.COM }
2157*10652SHyon.Kim@Sun.COM 
2158*10652SHyon.Kim@Sun.COM /*
2159*10652SHyon.Kim@Sun.COM  * Search the discovered LUs and construct the global LU list.
2160*10652SHyon.Kim@Sun.COM  *
2161*10652SHyon.Kim@Sun.COM  * Arguments:
2162*10652SHyon.Kim@Sun.COM  *      entryP - one of the target mapping data.
2163*10652SHyon.Kim@Sun.COM  *      handle - handle to hba port.
2164*10652SHyon.Kim@Sun.COM  *      hbaPortWWN - hba port sas address.
2165*10652SHyon.Kim@Sun.COM  *      domainPortWWN - domain port WWN for this sas domain.
2166*10652SHyon.Kim@Sun.COM  *      portName - HBA port OS Device Name.
2167*10652SHyon.Kim@Sun.COM  *      pflag - options the user specified.
2168*10652SHyon.Kim@Sun.COM  *
2169*10652SHyon.Kim@Sun.COM  *  Return Value:
2170*10652SHyon.Kim@Sun.COM  *	    0		sucessfully processed handle
2171*10652SHyon.Kim@Sun.COM  *	    >0		error has occured
2172*10652SHyon.Kim@Sun.COM  */
2173*10652SHyon.Kim@Sun.COM static int
searchDevice(PSMHBA_SCSIENTRY entryP,HBA_HANDLE handle,HBA_WWN hbaPortWWN,HBA_WWN domainPortWWN,char * portName,int pflag)2174*10652SHyon.Kim@Sun.COM searchDevice(PSMHBA_SCSIENTRY entryP,
2175*10652SHyon.Kim@Sun.COM     HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN domainPortWWN,
2176*10652SHyon.Kim@Sun.COM     char *portName, int pflag)
2177*10652SHyon.Kim@Sun.COM {
2178*10652SHyon.Kim@Sun.COM 	HBA_STATUS		status;
2179*10652SHyon.Kim@Sun.COM 	int			ret = 0;
2180*10652SHyon.Kim@Sun.COM 	discoveredDevice 	*discoveredLU, *newDevice;
2181*10652SHyon.Kim@Sun.COM 	portList		*portElem, *newPort, *prevElem;
2182*10652SHyon.Kim@Sun.COM 	tgtPortWWNList 		*newTgtWWN, *TgtWWNList;
2183*10652SHyon.Kim@Sun.COM 	boolean_t		foundDevice = B_FALSE;
2184*10652SHyon.Kim@Sun.COM 	boolean_t		foundPort = B_FALSE;
2185*10652SHyon.Kim@Sun.COM 	struct scsi_inquiry	inq;
2186*10652SHyon.Kim@Sun.COM 	HBA_UINT32		responseSize, senseSize = 0;
2187*10652SHyon.Kim@Sun.COM 	HBA_UINT8		inq_status;
2188*10652SHyon.Kim@Sun.COM 	SMHBA_SCSILUN		smhbaLUN;
2189*10652SHyon.Kim@Sun.COM 	struct scsi_extended_sense sense;
2190*10652SHyon.Kim@Sun.COM 
2191*10652SHyon.Kim@Sun.COM 	/* if OSDeviceName is not set, we don't need to search */
2192*10652SHyon.Kim@Sun.COM 	if (entryP->ScsiId.OSDeviceName[0] == '\0') {
2193*10652SHyon.Kim@Sun.COM 		return (ret);
2194*10652SHyon.Kim@Sun.COM 	}
2195*10652SHyon.Kim@Sun.COM 
2196*10652SHyon.Kim@Sun.COM 	/*
2197*10652SHyon.Kim@Sun.COM 	 * First, we will iterate the already constructed discovered LU
2198*10652SHyon.Kim@Sun.COM 	 * list to see whether there is a LU already exist with the same OS
2199*10652SHyon.Kim@Sun.COM 	 * device name as current target mapping data entry.
2200*10652SHyon.Kim@Sun.COM 	 */
2201*10652SHyon.Kim@Sun.COM 	for (discoveredLU = LUList; discoveredLU != NULL;
2202*10652SHyon.Kim@Sun.COM 	    discoveredLU = discoveredLU->next) {
2203*10652SHyon.Kim@Sun.COM 		if (strcmp(entryP->ScsiId.OSDeviceName,
2204*10652SHyon.Kim@Sun.COM 		    discoveredLU->OSDeviceName) == 0) {
2205*10652SHyon.Kim@Sun.COM 			/*
2206*10652SHyon.Kim@Sun.COM 			 * if there is existing OS Device Name and
2207*10652SHyon.Kim@Sun.COM 			 * verbose is not set, just return
2208*10652SHyon.Kim@Sun.COM 			 */
2209*10652SHyon.Kim@Sun.COM 			if ((pflag & PRINT_VERBOSE) == 0) {
2210*10652SHyon.Kim@Sun.COM 				return (ret);
2211*10652SHyon.Kim@Sun.COM 			}
2212*10652SHyon.Kim@Sun.COM 			foundDevice = B_TRUE;
2213*10652SHyon.Kim@Sun.COM 			break;
2214*10652SHyon.Kim@Sun.COM 		}
2215*10652SHyon.Kim@Sun.COM 	}
2216*10652SHyon.Kim@Sun.COM 
2217*10652SHyon.Kim@Sun.COM 	if (foundDevice == B_TRUE) {
2218*10652SHyon.Kim@Sun.COM 		/*
2219*10652SHyon.Kim@Sun.COM 		 * If there is a discovered LU already exist, we should
2220*10652SHyon.Kim@Sun.COM 		 * add more information on this LU to construct the whole
2221*10652SHyon.Kim@Sun.COM 		 * topology.
2222*10652SHyon.Kim@Sun.COM 		 * Here we will check whether the current hba port has
2223*10652SHyon.Kim@Sun.COM 		 * already been added.
2224*10652SHyon.Kim@Sun.COM 		 */
2225*10652SHyon.Kim@Sun.COM 		for (portElem = discoveredLU->HBAPortList,
2226*10652SHyon.Kim@Sun.COM 		    foundPort = B_FALSE;  portElem != NULL;
2227*10652SHyon.Kim@Sun.COM 		    portElem = portElem->next) {
2228*10652SHyon.Kim@Sun.COM 			if (strcmp(portElem->portName,
2229*10652SHyon.Kim@Sun.COM 			    portName) == 0) {
2230*10652SHyon.Kim@Sun.COM 				foundPort = B_TRUE;
2231*10652SHyon.Kim@Sun.COM 				break;
2232*10652SHyon.Kim@Sun.COM 			}
2233*10652SHyon.Kim@Sun.COM 		}
2234*10652SHyon.Kim@Sun.COM 
2235*10652SHyon.Kim@Sun.COM 		/*
2236*10652SHyon.Kim@Sun.COM 		 * If we get here, it means that it is a new hba port name
2237*10652SHyon.Kim@Sun.COM 		 * for this discovered LU.
2238*10652SHyon.Kim@Sun.COM 		 */
2239*10652SHyon.Kim@Sun.COM 		if (foundPort == B_FALSE) {
2240*10652SHyon.Kim@Sun.COM 			newPort = (portList *)calloc(1, sizeof (portList));
2241*10652SHyon.Kim@Sun.COM 			if (newPort == NULL) {
2242*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr,
2243*10652SHyon.Kim@Sun.COM 				    "%s\n", strerror(errno));
2244*10652SHyon.Kim@Sun.COM 				return (++ret);
2245*10652SHyon.Kim@Sun.COM 			}
2246*10652SHyon.Kim@Sun.COM 			(void) strlcpy(newPort->portName, portName,
2247*10652SHyon.Kim@Sun.COM 			    sizeof (newPort->portName));
2248*10652SHyon.Kim@Sun.COM 
2249*10652SHyon.Kim@Sun.COM 			portElem = discoveredLU->HBAPortList;
2250*10652SHyon.Kim@Sun.COM 			prevElem = portElem;
2251*10652SHyon.Kim@Sun.COM 			while (portElem != NULL &&
2252*10652SHyon.Kim@Sun.COM 			    sas_name_comp(newPort->portName, portElem->portName)
2253*10652SHyon.Kim@Sun.COM 			    > 0) {
2254*10652SHyon.Kim@Sun.COM 				prevElem = portElem;
2255*10652SHyon.Kim@Sun.COM 				portElem = portElem->next;
2256*10652SHyon.Kim@Sun.COM 			}
2257*10652SHyon.Kim@Sun.COM 			if (portElem == prevElem) {
2258*10652SHyon.Kim@Sun.COM 				/* Insert in the head of list. */
2259*10652SHyon.Kim@Sun.COM 				newPort->next = portElem;
2260*10652SHyon.Kim@Sun.COM 				discoveredLU->HBAPortList = newPort;
2261*10652SHyon.Kim@Sun.COM 			} else {
2262*10652SHyon.Kim@Sun.COM 				newPort->next = portElem;
2263*10652SHyon.Kim@Sun.COM 				prevElem->next = newPort;
2264*10652SHyon.Kim@Sun.COM 			}
2265*10652SHyon.Kim@Sun.COM 			/* add Target Port */
2266*10652SHyon.Kim@Sun.COM 			newPort->tgtPortWWN = (tgtPortWWNList *)calloc(1,
2267*10652SHyon.Kim@Sun.COM 			    sizeof (tgtPortWWNList));
2268*10652SHyon.Kim@Sun.COM 			if (newPort->tgtPortWWN == NULL) {
2269*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr,
2270*10652SHyon.Kim@Sun.COM 				    "%s\n", strerror(errno));
2271*10652SHyon.Kim@Sun.COM 				return (++ret);
2272*10652SHyon.Kim@Sun.COM 			}
2273*10652SHyon.Kim@Sun.COM 			(void *) memcpy((void *)&(newPort->tgtPortWWN->portWWN),
2274*10652SHyon.Kim@Sun.COM 			    (void *)&(entryP->PortLun.PortWWN),
2275*10652SHyon.Kim@Sun.COM 			    sizeof (HBA_WWN));
2276*10652SHyon.Kim@Sun.COM 			/* Set LUN data */
2277*10652SHyon.Kim@Sun.COM 			newPort->tgtPortWWN->scsiOSLun =
2278*10652SHyon.Kim@Sun.COM 			    entryP->ScsiId.ScsiOSLun;
2279*10652SHyon.Kim@Sun.COM 		} else {
2280*10652SHyon.Kim@Sun.COM 			/*
2281*10652SHyon.Kim@Sun.COM 			 * Otherwise, we just need to add the target port
2282*10652SHyon.Kim@Sun.COM 			 * sas address information.
2283*10652SHyon.Kim@Sun.COM 			 */
2284*10652SHyon.Kim@Sun.COM 			for (TgtWWNList = portElem->tgtPortWWN;
2285*10652SHyon.Kim@Sun.COM 			    TgtWWNList != NULL;
2286*10652SHyon.Kim@Sun.COM 			    TgtWWNList = TgtWWNList->next) {
2287*10652SHyon.Kim@Sun.COM 				if (memcmp(&TgtWWNList->portWWN,
2288*10652SHyon.Kim@Sun.COM 				    &entryP->PortLun.PortWWN,
2289*10652SHyon.Kim@Sun.COM 				    sizeof (HBA_WWN)) == 0)
2290*10652SHyon.Kim@Sun.COM 					return (0);
2291*10652SHyon.Kim@Sun.COM 			}
2292*10652SHyon.Kim@Sun.COM 			/* add it to existing */
2293*10652SHyon.Kim@Sun.COM 			newTgtWWN = (tgtPortWWNList *)calloc(1,
2294*10652SHyon.Kim@Sun.COM 			    sizeof (tgtPortWWNList));
2295*10652SHyon.Kim@Sun.COM 			if (newTgtWWN == NULL) {
2296*10652SHyon.Kim@Sun.COM 				(void *) fprintf(stderr,
2297*10652SHyon.Kim@Sun.COM 				    "%s\n", strerror(errno));
2298*10652SHyon.Kim@Sun.COM 				return (++ret);
2299*10652SHyon.Kim@Sun.COM 			}
2300*10652SHyon.Kim@Sun.COM 			/* insert at head */
2301*10652SHyon.Kim@Sun.COM 			newTgtWWN->next = portElem->tgtPortWWN;
2302*10652SHyon.Kim@Sun.COM 			portElem->tgtPortWWN = newTgtWWN;
2303*10652SHyon.Kim@Sun.COM 			(void *) memcpy((void *)&(newTgtWWN->portWWN),
2304*10652SHyon.Kim@Sun.COM 			    (void *)&(entryP->PortLun.PortWWN),
2305*10652SHyon.Kim@Sun.COM 			    sizeof (HBA_WWN));
2306*10652SHyon.Kim@Sun.COM 			/* Set LUN data */
2307*10652SHyon.Kim@Sun.COM 			newTgtWWN->scsiOSLun =
2308*10652SHyon.Kim@Sun.COM 			    entryP->ScsiId.ScsiOSLun;
2309*10652SHyon.Kim@Sun.COM 		}
2310*10652SHyon.Kim@Sun.COM 	} else {
2311*10652SHyon.Kim@Sun.COM 		/*
2312*10652SHyon.Kim@Sun.COM 		 * Here we got a new discovered LU which has not ever exist
2313*10652SHyon.Kim@Sun.COM 		 * in our global LU list. So add it into our global LU
2314*10652SHyon.Kim@Sun.COM 		 * list.
2315*10652SHyon.Kim@Sun.COM 		 */
2316*10652SHyon.Kim@Sun.COM 		newDevice = (discoveredDevice *)calloc(1,
2317*10652SHyon.Kim@Sun.COM 		    sizeof (discoveredDevice));
2318*10652SHyon.Kim@Sun.COM 
2319*10652SHyon.Kim@Sun.COM 		if (newDevice == NULL) {
2320*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n", strerror(errno));
2321*10652SHyon.Kim@Sun.COM 			return (++ret);
2322*10652SHyon.Kim@Sun.COM 		}
2323*10652SHyon.Kim@Sun.COM 		newDevice->next = LUList; /* insert at head */
2324*10652SHyon.Kim@Sun.COM 		LUList = newDevice; /* set new head */
2325*10652SHyon.Kim@Sun.COM 
2326*10652SHyon.Kim@Sun.COM 		/* copy device name */
2327*10652SHyon.Kim@Sun.COM 		(void *) strlcpy(newDevice->OSDeviceName,
2328*10652SHyon.Kim@Sun.COM 		    entryP->ScsiId.OSDeviceName,
2329*10652SHyon.Kim@Sun.COM 		    sizeof (newDevice->OSDeviceName));
2330*10652SHyon.Kim@Sun.COM 
2331*10652SHyon.Kim@Sun.COM 		/* if verbose is not set return */
2332*10652SHyon.Kim@Sun.COM 		if ((pflag & PRINT_VERBOSE) == 0) {
2333*10652SHyon.Kim@Sun.COM 			return (0);
2334*10652SHyon.Kim@Sun.COM 		}
2335*10652SHyon.Kim@Sun.COM 
2336*10652SHyon.Kim@Sun.COM 		/* copy WWN data */
2337*10652SHyon.Kim@Sun.COM 		newDevice->HBAPortList = (portList *)calloc(1,
2338*10652SHyon.Kim@Sun.COM 		    sizeof (portList));
2339*10652SHyon.Kim@Sun.COM 		if (newDevice->HBAPortList == NULL) {
2340*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n", strerror(errno));
2341*10652SHyon.Kim@Sun.COM 			return (++ret);
2342*10652SHyon.Kim@Sun.COM 		}
2343*10652SHyon.Kim@Sun.COM 		(void) strlcpy(newDevice->HBAPortList->portName,
2344*10652SHyon.Kim@Sun.COM 		    portName, sizeof (newDevice->HBAPortList->portName));
2345*10652SHyon.Kim@Sun.COM 
2346*10652SHyon.Kim@Sun.COM 		newDevice->HBAPortList->tgtPortWWN =
2347*10652SHyon.Kim@Sun.COM 		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
2348*10652SHyon.Kim@Sun.COM 		if (newDevice->HBAPortList->tgtPortWWN == NULL) {
2349*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stderr, "%s\n", strerror(errno));
2350*10652SHyon.Kim@Sun.COM 			return (++ret);
2351*10652SHyon.Kim@Sun.COM 		}
2352*10652SHyon.Kim@Sun.COM 
2353*10652SHyon.Kim@Sun.COM 		(void *) memcpy((void *)&(newDevice->HBAPortList->\
2354*10652SHyon.Kim@Sun.COM 		    tgtPortWWN->portWWN),
2355*10652SHyon.Kim@Sun.COM 		    (void *)&(entryP->PortLun.PortWWN),
2356*10652SHyon.Kim@Sun.COM 		    sizeof (HBA_WWN));
2357*10652SHyon.Kim@Sun.COM 		newDevice->HBAPortList->tgtPortWWN->scsiOSLun =
2358*10652SHyon.Kim@Sun.COM 		    entryP->ScsiId.ScsiOSLun;
2359*10652SHyon.Kim@Sun.COM 
2360*10652SHyon.Kim@Sun.COM 		responseSize = sizeof (struct scsi_inquiry);
2361*10652SHyon.Kim@Sun.COM 		senseSize = sizeof (struct scsi_extended_sense);
2362*10652SHyon.Kim@Sun.COM 		(void *) memset(&inq, 0, sizeof (struct scsi_inquiry));
2363*10652SHyon.Kim@Sun.COM 		(void *) memset(&sense, 0, sizeof (sense));
2364*10652SHyon.Kim@Sun.COM 		(void *) memcpy(&smhbaLUN, &entryP->PortLun.TargetLun,
2365*10652SHyon.Kim@Sun.COM 		    sizeof (smhbaLUN));
2366*10652SHyon.Kim@Sun.COM 
2367*10652SHyon.Kim@Sun.COM 		/*
2368*10652SHyon.Kim@Sun.COM 		 * Retrieve the VPD data for the newly found discovered LU.
2369*10652SHyon.Kim@Sun.COM 		 */
2370*10652SHyon.Kim@Sun.COM 		status = SMHBA_ScsiInquiry(
2371*10652SHyon.Kim@Sun.COM 		    handle,
2372*10652SHyon.Kim@Sun.COM 		    hbaPortWWN,
2373*10652SHyon.Kim@Sun.COM 		    entryP->PortLun.PortWWN,
2374*10652SHyon.Kim@Sun.COM 		    domainPortWWN,
2375*10652SHyon.Kim@Sun.COM 		    smhbaLUN,
2376*10652SHyon.Kim@Sun.COM 		    0,
2377*10652SHyon.Kim@Sun.COM 		    0,
2378*10652SHyon.Kim@Sun.COM 		    (void *) &inq, &responseSize,
2379*10652SHyon.Kim@Sun.COM 		    &inq_status,
2380*10652SHyon.Kim@Sun.COM 		    (void *) &sense, &senseSize);
2381*10652SHyon.Kim@Sun.COM 
2382*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK) {
2383*10652SHyon.Kim@Sun.COM 			/* init VID/PID/dType as '\0' */
2384*10652SHyon.Kim@Sun.COM 			newDevice->VID[0] = '\0';
2385*10652SHyon.Kim@Sun.COM 			newDevice->PID[0] = '\0';
2386*10652SHyon.Kim@Sun.COM 			newDevice->dType = DTYPE_UNKNOWN;
2387*10652SHyon.Kim@Sun.COM 			/* initialize inq status */
2388*10652SHyon.Kim@Sun.COM 			newDevice->inquiryFailed = B_TRUE;
2389*10652SHyon.Kim@Sun.COM 			ret++;
2390*10652SHyon.Kim@Sun.COM 		} else {
2391*10652SHyon.Kim@Sun.COM 			(void *) memcpy(newDevice->VID, inq.inq_vid,
2392*10652SHyon.Kim@Sun.COM 			    sizeof (newDevice->VID));
2393*10652SHyon.Kim@Sun.COM 			(void *) memcpy(newDevice->PID, inq.inq_pid,
2394*10652SHyon.Kim@Sun.COM 			    sizeof (newDevice->PID));
2395*10652SHyon.Kim@Sun.COM 			newDevice->dType = inq.inq_dtype;
2396*10652SHyon.Kim@Sun.COM 			/* initialize inq status */
2397*10652SHyon.Kim@Sun.COM 			newDevice->inquiryFailed = B_FALSE;
2398*10652SHyon.Kim@Sun.COM 		}
2399*10652SHyon.Kim@Sun.COM 	}
2400*10652SHyon.Kim@Sun.COM 	return (ret);
2401*10652SHyon.Kim@Sun.COM }
2402*10652SHyon.Kim@Sun.COM 
2403*10652SHyon.Kim@Sun.COM /*
2404*10652SHyon.Kim@Sun.COM  * Function we use to insert a newly discovered port.
2405*10652SHyon.Kim@Sun.COM  * Return:
2406*10652SHyon.Kim@Sun.COM  * 	0 - success
2407*10652SHyon.Kim@Sun.COM  * 	>0 - failed
2408*10652SHyon.Kim@Sun.COM  */
2409*10652SHyon.Kim@Sun.COM static int
sas_rp_tree_insert(rp_tree_t ** rproot,rp_tree_t * rpnode)2410*10652SHyon.Kim@Sun.COM sas_rp_tree_insert(rp_tree_t **rproot,
2411*10652SHyon.Kim@Sun.COM     rp_tree_t *rpnode)
2412*10652SHyon.Kim@Sun.COM {
2413*10652SHyon.Kim@Sun.COM 	HBA_UINT8 *wwn1, *wwn2, *wwn3;
2414*10652SHyon.Kim@Sun.COM 	rp_tree_t *node_ptr;
2415*10652SHyon.Kim@Sun.COM 	int ret = 0;
2416*10652SHyon.Kim@Sun.COM 
2417*10652SHyon.Kim@Sun.COM 	if (rproot == NULL) {
2418*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
2419*10652SHyon.Kim@Sun.COM 		    gettext("Error: NULL rproot"));
2420*10652SHyon.Kim@Sun.COM 		return (1);
2421*10652SHyon.Kim@Sun.COM 	}
2422*10652SHyon.Kim@Sun.COM 
2423*10652SHyon.Kim@Sun.COM 	if (rpnode == NULL) {
2424*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stderr, "%s\n",
2425*10652SHyon.Kim@Sun.COM 		    gettext("Error: NULL rpnode"));
2426*10652SHyon.Kim@Sun.COM 		return (1);
2427*10652SHyon.Kim@Sun.COM 	}
2428*10652SHyon.Kim@Sun.COM 
2429*10652SHyon.Kim@Sun.COM 	if (*rproot == NULL) {
2430*10652SHyon.Kim@Sun.COM 		*rproot = rpnode;
2431*10652SHyon.Kim@Sun.COM 		return (0);
2432*10652SHyon.Kim@Sun.COM 	}
2433*10652SHyon.Kim@Sun.COM 
2434*10652SHyon.Kim@Sun.COM 	wwn1 = (*rproot)->sasattr.LocalSASAddress.wwn;
2435*10652SHyon.Kim@Sun.COM 	wwn2 = (*rproot)->sasattr.AttachedSASAddress.wwn;
2436*10652SHyon.Kim@Sun.COM 	wwn3 = rpnode->sasattr.AttachedSASAddress.wwn;
2437*10652SHyon.Kim@Sun.COM 
2438*10652SHyon.Kim@Sun.COM 	/*
2439*10652SHyon.Kim@Sun.COM 	 * If the attched sas address is equal to the local sas address,
2440*10652SHyon.Kim@Sun.COM 	 * then this should be a child node of current root node.
2441*10652SHyon.Kim@Sun.COM 	 */
2442*10652SHyon.Kim@Sun.COM 	if (memcmp(wwn1, wwn3, sizeof (HBA_WWN)) == 0) {
2443*10652SHyon.Kim@Sun.COM 		(void) sas_rp_tree_insert(&(*rproot)->child, rpnode);
2444*10652SHyon.Kim@Sun.COM 		rpnode->parent = *rproot;
2445*10652SHyon.Kim@Sun.COM 	} else if (memcmp(wwn2, wwn3, sizeof (HBA_WWN)) == 0) {
2446*10652SHyon.Kim@Sun.COM 		/*
2447*10652SHyon.Kim@Sun.COM 		 * If the attached sas address is equal to the attached sas
2448*10652SHyon.Kim@Sun.COM 		 * address of current root node, then this should be a
2449*10652SHyon.Kim@Sun.COM 		 * sibling node.
2450*10652SHyon.Kim@Sun.COM 		 * Insert the SAS/SATA Device at the head of sibling list.
2451*10652SHyon.Kim@Sun.COM 		 */
2452*10652SHyon.Kim@Sun.COM 		if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2453*10652SHyon.Kim@Sun.COM 			rpnode->sibling = *rproot;
2454*10652SHyon.Kim@Sun.COM 			*rproot = rpnode;
2455*10652SHyon.Kim@Sun.COM 		} else {
2456*10652SHyon.Kim@Sun.COM 			/*
2457*10652SHyon.Kim@Sun.COM 			 * Insert the SAS Expander at the tail of sibling
2458*10652SHyon.Kim@Sun.COM 			 * list.
2459*10652SHyon.Kim@Sun.COM 			 */
2460*10652SHyon.Kim@Sun.COM 			node_ptr = *rproot;
2461*10652SHyon.Kim@Sun.COM 			while (node_ptr->sibling != NULL)
2462*10652SHyon.Kim@Sun.COM 				node_ptr = node_ptr->sibling;
2463*10652SHyon.Kim@Sun.COM 			node_ptr->sibling = rpnode;
2464*10652SHyon.Kim@Sun.COM 		}
2465*10652SHyon.Kim@Sun.COM 		rpnode->parent = (*rproot)->parent;
2466*10652SHyon.Kim@Sun.COM 	} else {
2467*10652SHyon.Kim@Sun.COM 		/*
2468*10652SHyon.Kim@Sun.COM 		 * If enter here, we should first try to insert the discovered
2469*10652SHyon.Kim@Sun.COM 		 * port node into the child sub-tree, then try to insert to the
2470*10652SHyon.Kim@Sun.COM 		 * sibling sub-trees. If we failed to insert the discovered
2471*10652SHyon.Kim@Sun.COM 		 * port node, return 1. The caller will queue this node
2472*10652SHyon.Kim@Sun.COM 		 * up and retry insertion later.
2473*10652SHyon.Kim@Sun.COM 		 */
2474*10652SHyon.Kim@Sun.COM 		if ((*rproot)->child) {
2475*10652SHyon.Kim@Sun.COM 			ret = sas_rp_tree_insert(&(*rproot)->child, rpnode);
2476*10652SHyon.Kim@Sun.COM 		}
2477*10652SHyon.Kim@Sun.COM 		if ((*rproot)->child == NULL || ret != 0) {
2478*10652SHyon.Kim@Sun.COM 			if ((*rproot)->sibling) {
2479*10652SHyon.Kim@Sun.COM 				ret = sas_rp_tree_insert(&(*rproot)->sibling,
2480*10652SHyon.Kim@Sun.COM 				    rpnode);
2481*10652SHyon.Kim@Sun.COM 			} else
2482*10652SHyon.Kim@Sun.COM 				ret = 1;
2483*10652SHyon.Kim@Sun.COM 		}
2484*10652SHyon.Kim@Sun.COM 		return (ret);
2485*10652SHyon.Kim@Sun.COM 	}
2486*10652SHyon.Kim@Sun.COM 	return (0);
2487*10652SHyon.Kim@Sun.COM }
2488*10652SHyon.Kim@Sun.COM 
2489*10652SHyon.Kim@Sun.COM /*
2490*10652SHyon.Kim@Sun.COM  * Function which will print out the whole disocvered port topology.
2491*10652SHyon.Kim@Sun.COM  * Here we use the Preorder Traversal algorithm.
2492*10652SHyon.Kim@Sun.COM  * The indentation rules are:
2493*10652SHyon.Kim@Sun.COM  * 	1 * TABLEN - for attributes
2494*10652SHyon.Kim@Sun.COM  * 	2 * TABLEN - for next tier target port/expander
2495*10652SHyon.Kim@Sun.COM  */
2496*10652SHyon.Kim@Sun.COM 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)2497*10652SHyon.Kim@Sun.COM sas_rp_tree_print(HBA_HANDLE handle, char *adapterName,
2498*10652SHyon.Kim@Sun.COM     HBA_UINT32 portIndex, SMHBA_PORTATTRIBUTES *port,
2499*10652SHyon.Kim@Sun.COM     rp_tree_t *rpnode, inputArg_t *input,
2500*10652SHyon.Kim@Sun.COM     int gident, int *printPort)
2501*10652SHyon.Kim@Sun.COM {
2502*10652SHyon.Kim@Sun.COM 	int ret = 0, lident;
2503*10652SHyon.Kim@Sun.COM 
2504*10652SHyon.Kim@Sun.COM 	if (rpnode == NULL)
2505*10652SHyon.Kim@Sun.COM 		return (ret);
2506*10652SHyon.Kim@Sun.COM 	lident = gident;
2507*10652SHyon.Kim@Sun.COM 
2508*10652SHyon.Kim@Sun.COM 	/*
2509*10652SHyon.Kim@Sun.COM 	 * We assume that all the nodes are disocvered ports(sas device or
2510*10652SHyon.Kim@Sun.COM 	 * expander).
2511*10652SHyon.Kim@Sun.COM 	 */
2512*10652SHyon.Kim@Sun.COM 	if (input->wwnCount > 0) {
2513*10652SHyon.Kim@Sun.COM 		/* Adjust local indentation if a discovered port specified. */
2514*10652SHyon.Kim@Sun.COM 		lident = 2 * TABLEN;
2515*10652SHyon.Kim@Sun.COM 		/*
2516*10652SHyon.Kim@Sun.COM 		 * Check whether current node match one of the specified
2517*10652SHyon.Kim@Sun.COM 		 * SAS addresses.
2518*10652SHyon.Kim@Sun.COM 		 */
2519*10652SHyon.Kim@Sun.COM 		if ((rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) ||
2520*10652SHyon.Kim@Sun.COM 		    !isPortWWNInArgv(input,
2521*10652SHyon.Kim@Sun.COM 		    &rpnode->sasattr.LocalSASAddress)) {
2522*10652SHyon.Kim@Sun.COM 			/*
2523*10652SHyon.Kim@Sun.COM 			 * Step down to child tree first.
2524*10652SHyon.Kim@Sun.COM 			 */
2525*10652SHyon.Kim@Sun.COM 			ret += sas_rp_tree_print(handle, adapterName,
2526*10652SHyon.Kim@Sun.COM 			    portIndex, port, rpnode->child, input,
2527*10652SHyon.Kim@Sun.COM 			    gident + 2 * TABLEN, printPort);
2528*10652SHyon.Kim@Sun.COM 			/*
2529*10652SHyon.Kim@Sun.COM 			 * Then check the sibling tree.
2530*10652SHyon.Kim@Sun.COM 			 */
2531*10652SHyon.Kim@Sun.COM 			ret += sas_rp_tree_print(handle, adapterName,
2532*10652SHyon.Kim@Sun.COM 			    portIndex, port, rpnode->sibling, input,
2533*10652SHyon.Kim@Sun.COM 			    gident, printPort);
2534*10652SHyon.Kim@Sun.COM 			return (ret);
2535*10652SHyon.Kim@Sun.COM 		}
2536*10652SHyon.Kim@Sun.COM 	}
2537*10652SHyon.Kim@Sun.COM 
2538*10652SHyon.Kim@Sun.COM 	if ((rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) ||
2539*10652SHyon.Kim@Sun.COM 	    (input->pflag & PRINT_TARGET_PORT)) {
2540*10652SHyon.Kim@Sun.COM 		/*
2541*10652SHyon.Kim@Sun.COM 		 * We should print the header(HBA Name + HBA Port Name)
2542*10652SHyon.Kim@Sun.COM 		 * on-demand. It means that, if we have expander device
2543*10652SHyon.Kim@Sun.COM 		 * address specified on the command line, we should print
2544*10652SHyon.Kim@Sun.COM 		 * the header once we find a matching one. Or we will
2545*10652SHyon.Kim@Sun.COM 		 * print the header from the beginning of the output.
2546*10652SHyon.Kim@Sun.COM 		 */
2547*10652SHyon.Kim@Sun.COM 		if (g_printHBA == 0) {
2548*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stdout, "%s %s\n",
2549*10652SHyon.Kim@Sun.COM 			    "HBA Name:", adapterName);
2550*10652SHyon.Kim@Sun.COM 			g_printHBA = 1;
2551*10652SHyon.Kim@Sun.COM 		}
2552*10652SHyon.Kim@Sun.COM 
2553*10652SHyon.Kim@Sun.COM 		if (*printPort == 0) {
2554*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stdout, "%s%s %s\n",
2555*10652SHyon.Kim@Sun.COM 			    getIndentSpaces(TABLEN),
2556*10652SHyon.Kim@Sun.COM 			    "HBA Port Name:", port->OSDeviceName);
2557*10652SHyon.Kim@Sun.COM 			*printPort = 1;
2558*10652SHyon.Kim@Sun.COM 		}
2559*10652SHyon.Kim@Sun.COM 		ret += sas_print_rpnode(input, rpnode, lident, gident);
2560*10652SHyon.Kim@Sun.COM 	}
2561*10652SHyon.Kim@Sun.COM 
2562*10652SHyon.Kim@Sun.COM 	/*
2563*10652SHyon.Kim@Sun.COM 	 * If operands provided with "-t" option specified, we will print
2564*10652SHyon.Kim@Sun.COM 	 * the immediate child nodes information under the expander.
2565*10652SHyon.Kim@Sun.COM 	 */
2566*10652SHyon.Kim@Sun.COM 	if (input->pflag & PRINT_TARGET_PORT) {
2567*10652SHyon.Kim@Sun.COM 		/* no operand. ignore the option. */
2568*10652SHyon.Kim@Sun.COM 		if (input->wwnCount > 0) {
2569*10652SHyon.Kim@Sun.COM 			if (rpnode->portattr.PortType ==
2570*10652SHyon.Kim@Sun.COM 			    HBA_PORTTYPE_SASEXPANDER) {
2571*10652SHyon.Kim@Sun.COM 				ret += sas_rp_tree_print_desc(handle,
2572*10652SHyon.Kim@Sun.COM 				    portIndex, port, rpnode->child,
2573*10652SHyon.Kim@Sun.COM 				    input,
2574*10652SHyon.Kim@Sun.COM 				    lident + 2 * TABLEN,
2575*10652SHyon.Kim@Sun.COM 				    gident + 2 * TABLEN);
2576*10652SHyon.Kim@Sun.COM 			}
2577*10652SHyon.Kim@Sun.COM 		}
2578*10652SHyon.Kim@Sun.COM 	}
2579*10652SHyon.Kim@Sun.COM 
2580*10652SHyon.Kim@Sun.COM 	/*
2581*10652SHyon.Kim@Sun.COM 	 * Here we use DFS(Depth First Search) algorithm to traverse the
2582*10652SHyon.Kim@Sun.COM 	 * whole tree.
2583*10652SHyon.Kim@Sun.COM 	 */
2584*10652SHyon.Kim@Sun.COM 	ret += sas_rp_tree_print(handle, adapterName,
2585*10652SHyon.Kim@Sun.COM 	    portIndex, port, rpnode->child, input,
2586*10652SHyon.Kim@Sun.COM 	    gident + 2 * TABLEN, printPort);
2587*10652SHyon.Kim@Sun.COM 	ret += sas_rp_tree_print(handle, adapterName,
2588*10652SHyon.Kim@Sun.COM 	    portIndex, port, rpnode->sibling, input,
2589*10652SHyon.Kim@Sun.COM 	    gident, printPort);
2590*10652SHyon.Kim@Sun.COM 	return (ret);
2591*10652SHyon.Kim@Sun.COM }
2592*10652SHyon.Kim@Sun.COM 
2593*10652SHyon.Kim@Sun.COM /*
2594*10652SHyon.Kim@Sun.COM  * Function which will destroy the whole discovered port tree.
2595*10652SHyon.Kim@Sun.COM  * Here we use the Postorder Traversal algorithm.
2596*10652SHyon.Kim@Sun.COM  */
sas_rp_tree_free(rp_tree_t * rproot)2597*10652SHyon.Kim@Sun.COM static void sas_rp_tree_free(rp_tree_t *rproot)
2598*10652SHyon.Kim@Sun.COM {
2599*10652SHyon.Kim@Sun.COM 	tgt_mapping *cur, *next;
2600*10652SHyon.Kim@Sun.COM 
2601*10652SHyon.Kim@Sun.COM 	if (rproot == NULL)
2602*10652SHyon.Kim@Sun.COM 		return;
2603*10652SHyon.Kim@Sun.COM 
2604*10652SHyon.Kim@Sun.COM 	/*
2605*10652SHyon.Kim@Sun.COM 	 * Free child tree first.
2606*10652SHyon.Kim@Sun.COM 	 */
2607*10652SHyon.Kim@Sun.COM 	if (rproot->child) {
2608*10652SHyon.Kim@Sun.COM 		sas_rp_tree_free(rproot->child);
2609*10652SHyon.Kim@Sun.COM 	}
2610*10652SHyon.Kim@Sun.COM 
2611*10652SHyon.Kim@Sun.COM 	/*
2612*10652SHyon.Kim@Sun.COM 	 * Free sibling trees then.
2613*10652SHyon.Kim@Sun.COM 	 */
2614*10652SHyon.Kim@Sun.COM 	if (rproot->sibling) {
2615*10652SHyon.Kim@Sun.COM 		sas_rp_tree_free(rproot->sibling);
2616*10652SHyon.Kim@Sun.COM 	}
2617*10652SHyon.Kim@Sun.COM 
2618*10652SHyon.Kim@Sun.COM 	/*
2619*10652SHyon.Kim@Sun.COM 	 * Free root node at last.
2620*10652SHyon.Kim@Sun.COM 	 */
2621*10652SHyon.Kim@Sun.COM 	cur = rproot->first_entry;
2622*10652SHyon.Kim@Sun.COM 	while (cur != NULL) {
2623*10652SHyon.Kim@Sun.COM 		next = cur->next;
2624*10652SHyon.Kim@Sun.COM 		free(cur);
2625*10652SHyon.Kim@Sun.COM 		cur = next;
2626*10652SHyon.Kim@Sun.COM 	}
2627*10652SHyon.Kim@Sun.COM 	free(rproot);
2628*10652SHyon.Kim@Sun.COM }
2629*10652SHyon.Kim@Sun.COM 
2630*10652SHyon.Kim@Sun.COM /*
2631*10652SHyon.Kim@Sun.COM  * Function used to print out all the descendant nodes.
2632*10652SHyon.Kim@Sun.COM  * handle - handle to HBA.
2633*10652SHyon.Kim@Sun.COM  * port - port attributes of current HBA port.
2634*10652SHyon.Kim@Sun.COM  * desc - the root node of a subtree which will be processed.
2635*10652SHyon.Kim@Sun.COM  * input - input argument.
2636*10652SHyon.Kim@Sun.COM  * lident - local indentation for shifting indentation.
2637*10652SHyon.Kim@Sun.COM  * gident - global indentation, can also be used to obtain Tier number.
2638*10652SHyon.Kim@Sun.COM  */
2639*10652SHyon.Kim@Sun.COM /*ARGSUSED*/
2640*10652SHyon.Kim@Sun.COM 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)2641*10652SHyon.Kim@Sun.COM sas_rp_tree_print_desc(HBA_HANDLE handle, HBA_UINT32 portIndex,
2642*10652SHyon.Kim@Sun.COM     SMHBA_PORTATTRIBUTES *port, rp_tree_t *desc,
2643*10652SHyon.Kim@Sun.COM     inputArg_t *input, int lident, int gident)
2644*10652SHyon.Kim@Sun.COM {
2645*10652SHyon.Kim@Sun.COM 	int ret = 0;
2646*10652SHyon.Kim@Sun.COM 	rp_tree_t   *rp_node;
2647*10652SHyon.Kim@Sun.COM 
2648*10652SHyon.Kim@Sun.COM 	if (desc == NULL)
2649*10652SHyon.Kim@Sun.COM 		return (ret);
2650*10652SHyon.Kim@Sun.COM 	/*
2651*10652SHyon.Kim@Sun.COM 	 * Walk through the subtree of desc by Pre-Order Traversal Algo.
2652*10652SHyon.Kim@Sun.COM 	 */
2653*10652SHyon.Kim@Sun.COM 	for (rp_node = desc; rp_node !=	NULL; rp_node = rp_node->sibling) {
2654*10652SHyon.Kim@Sun.COM 		ret += sas_print_rpnode(input, rp_node, lident, gident);
2655*10652SHyon.Kim@Sun.COM 	}
2656*10652SHyon.Kim@Sun.COM 
2657*10652SHyon.Kim@Sun.COM 	return (ret);
2658*10652SHyon.Kim@Sun.COM }
2659*10652SHyon.Kim@Sun.COM 
2660*10652SHyon.Kim@Sun.COM /*
2661*10652SHyon.Kim@Sun.COM  * Function used to print the information of specified SAS address.
2662*10652SHyon.Kim@Sun.COM  * handle - handle to a HBA.
2663*10652SHyon.Kim@Sun.COM  * port - port attributes of a HBA port.
2664*10652SHyon.Kim@Sun.COM  * rpnode - discovered port which will be processed.
2665*10652SHyon.Kim@Sun.COM  * lident - local indentation used for shifting indentation.
2666*10652SHyon.Kim@Sun.COM  * gident - global indentation used for calculating "Tier" number.
2667*10652SHyon.Kim@Sun.COM  */
2668*10652SHyon.Kim@Sun.COM static int
sas_print_rpnode(inputArg_t * input,rp_tree_t * rpnode,int lident,int gident)2669*10652SHyon.Kim@Sun.COM sas_print_rpnode(inputArg_t *input,
2670*10652SHyon.Kim@Sun.COM     rp_tree_t *rpnode, int lident, int gident)
2671*10652SHyon.Kim@Sun.COM {
2672*10652SHyon.Kim@Sun.COM 	int ret = 0;
2673*10652SHyon.Kim@Sun.COM 
2674*10652SHyon.Kim@Sun.COM 	if (rpnode->portattr.PortType == HBA_PORTTYPE_SASEXPANDER) {
2675*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stdout, "%s%s(Tier %d): %016llx\n",
2676*10652SHyon.Kim@Sun.COM 		    getIndentSpaces(lident),
2677*10652SHyon.Kim@Sun.COM 		    "Expander SAS Address",
2678*10652SHyon.Kim@Sun.COM 		    gident / (2 * TABLEN),
2679*10652SHyon.Kim@Sun.COM 		    wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
2680*10652SHyon.Kim@Sun.COM 	} else {
2681*10652SHyon.Kim@Sun.COM 		(void *) fprintf(stdout, "%s%s %016llx\n",
2682*10652SHyon.Kim@Sun.COM 		    getIndentSpaces(lident),
2683*10652SHyon.Kim@Sun.COM 		    "Target Port SAS Address:",
2684*10652SHyon.Kim@Sun.COM 		    wwnConversion(rpnode->sasattr.LocalSASAddress.wwn));
2685*10652SHyon.Kim@Sun.COM 	}
2686*10652SHyon.Kim@Sun.COM 	if (input->pflag & PRINT_VERBOSE) {
2687*10652SHyon.Kim@Sun.COM 		if (rpnode->portattr.PortType != HBA_PORTTYPE_SASEXPANDER) {
2688*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stdout, "%s%s %s\n",
2689*10652SHyon.Kim@Sun.COM 			    getIndentSpaces(TABLEN + lident),
2690*10652SHyon.Kim@Sun.COM 			    "Type:",
2691*10652SHyon.Kim@Sun.COM 			    getStateString(rpnode->portattr.PortType,
2692*10652SHyon.Kim@Sun.COM 			    porttype_string));
2693*10652SHyon.Kim@Sun.COM 		} else {
2694*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stdout, "%s%s %s\n",
2695*10652SHyon.Kim@Sun.COM 			    getIndentSpaces(TABLEN + lident),
2696*10652SHyon.Kim@Sun.COM 			    "OS Device Name:",
2697*10652SHyon.Kim@Sun.COM 			    rpnode->portattr.OSDeviceName);
2698*10652SHyon.Kim@Sun.COM 			(void *) fprintf(stdout, "%s%s %s\n",
2699*10652SHyon.Kim@Sun.COM 			    getIndentSpaces(TABLEN + lident),
2700*10652SHyon.Kim@Sun.COM 			    "State: ",
2701*10652SHyon.Kim@Sun.COM 			    getStateString(rpnode->portattr.PortState,
2702*10652SHyon.Kim@Sun.COM 			    portstate_string));
2703*10652SHyon.Kim@Sun.COM 		}
2704*10652SHyon.Kim@Sun.COM 	}
2705*10652SHyon.Kim@Sun.COM 	rpnode->printed = 1;
2706*10652SHyon.Kim@Sun.COM 	return (ret);
2707*10652SHyon.Kim@Sun.COM }
2708*10652SHyon.Kim@Sun.COM 
2709*10652SHyon.Kim@Sun.COM /*
2710*10652SHyon.Kim@Sun.COM  * Function used to get the correct domainPortWWN as needed by some of the
2711*10652SHyon.Kim@Sun.COM  * SMHBA APIs.
2712*10652SHyon.Kim@Sun.COM  * handle - handle to a HBA.
2713*10652SHyon.Kim@Sun.COM  * portIndex - index to locate the port.
2714*10652SHyon.Kim@Sun.COM  * port - pointer to the structure holding port attributes.
2715*10652SHyon.Kim@Sun.COM  * pdomainPort - pointer to the buffer holding domainPortWWN.
2716*10652SHyon.Kim@Sun.COM  */
2717*10652SHyon.Kim@Sun.COM HBA_STATUS
get_domainPort(HBA_HANDLE handle,int portIndex,PSMHBA_PORTATTRIBUTES port,HBA_WWN * pdomainPort)2718*10652SHyon.Kim@Sun.COM get_domainPort(HBA_HANDLE handle,
2719*10652SHyon.Kim@Sun.COM     int portIndex, PSMHBA_PORTATTRIBUTES port,
2720*10652SHyon.Kim@Sun.COM     HBA_WWN *pdomainPort)
2721*10652SHyon.Kim@Sun.COM {
2722*10652SHyon.Kim@Sun.COM 	HBA_STATUS status;
2723*10652SHyon.Kim@Sun.COM 	PSMHBA_SAS_PORT sasport;
2724*10652SHyon.Kim@Sun.COM 	SMHBA_SAS_PHY phyattr;
2725*10652SHyon.Kim@Sun.COM 
2726*10652SHyon.Kim@Sun.COM 	sasport = port->PortSpecificAttribute.SASPort;
2727*10652SHyon.Kim@Sun.COM 	(void *) memset(pdomainPort, 0, sizeof (HBA_WWN));
2728*10652SHyon.Kim@Sun.COM 	/*
2729*10652SHyon.Kim@Sun.COM 	 * Since iport can exist without any phys,
2730*10652SHyon.Kim@Sun.COM 	 * sasinfo hba-port -v has indicated numberOfPhys;
2731*10652SHyon.Kim@Sun.COM 	 * if there is no phys within the hba, just return OK.
2732*10652SHyon.Kim@Sun.COM 	 */
2733*10652SHyon.Kim@Sun.COM 	if (sasport->NumberofPhys > 0) {
2734*10652SHyon.Kim@Sun.COM 		status = SMHBA_GetSASPhyAttributes(handle, portIndex,
2735*10652SHyon.Kim@Sun.COM 		    0, &phyattr);
2736*10652SHyon.Kim@Sun.COM 		if (status != HBA_STATUS_OK)
2737*10652SHyon.Kim@Sun.COM 			return (status);
2738*10652SHyon.Kim@Sun.COM 		(void *) memcpy(pdomainPort, &phyattr.domainPortWWN,
2739*10652SHyon.Kim@Sun.COM 		    sizeof (HBA_WWN));
2740*10652SHyon.Kim@Sun.COM 	} else {
2741*10652SHyon.Kim@Sun.COM 		/* return not supported for no phy configured */
2742*10652SHyon.Kim@Sun.COM 		return (HBA_STATUS_ERROR_NOT_SUPPORTED);
2743*10652SHyon.Kim@Sun.COM 	}
2744*10652SHyon.Kim@Sun.COM 	return (HBA_STATUS_OK);
2745*10652SHyon.Kim@Sun.COM }
2746*10652SHyon.Kim@Sun.COM 
2747*10652SHyon.Kim@Sun.COM /*
2748*10652SHyon.Kim@Sun.COM  * Comparison function for comparing names possibly ending with digits.
2749*10652SHyon.Kim@Sun.COM  * Return:
2750*10652SHyon.Kim@Sun.COM  * 	<0 - name1 is less than name2.
2751*10652SHyon.Kim@Sun.COM  * 	0 - name1 is equal with name2.
2752*10652SHyon.Kim@Sun.COM  * 	>0 - name1 is more than name2.
2753*10652SHyon.Kim@Sun.COM  */
2754*10652SHyon.Kim@Sun.COM static int
sas_name_comp(const char * name1,const char * name2)2755*10652SHyon.Kim@Sun.COM sas_name_comp(const char *name1, const char *name2)
2756*10652SHyon.Kim@Sun.COM {
2757*10652SHyon.Kim@Sun.COM 	int i = 0;
2758*10652SHyon.Kim@Sun.COM 
2759*10652SHyon.Kim@Sun.COM 	if (name1 == name2)
2760*10652SHyon.Kim@Sun.COM 		return (0);
2761*10652SHyon.Kim@Sun.COM 
2762*10652SHyon.Kim@Sun.COM 	while ((name1[i] == name2[i]) && (name1[i] != '\0'))
2763*10652SHyon.Kim@Sun.COM 		i++;
2764*10652SHyon.Kim@Sun.COM 
2765*10652SHyon.Kim@Sun.COM 	/* If neither of name1[i] and name2[i] is '\0'. */
2766*10652SHyon.Kim@Sun.COM 	if (isdigit(name1[i]) && isdigit(name2[i]))
2767*10652SHyon.Kim@Sun.COM 		return (atoi(&name1[i]) - atoi(&name2[i]));
2768*10652SHyon.Kim@Sun.COM 
2769*10652SHyon.Kim@Sun.COM 	/* One of name1[i] and name2[i] is not digit. */
2770*10652SHyon.Kim@Sun.COM 	return (name1[i] - name2[i]);
2771*10652SHyon.Kim@Sun.COM }
2772*10652SHyon.Kim@Sun.COM /*
2773*10652SHyon.Kim@Sun.COM  * Comparison function for sorting HBA/HBA Port.
2774*10652SHyon.Kim@Sun.COM  * arg1 - first argument of type sas_elem_t.
2775*10652SHyon.Kim@Sun.COM  * arg2 - second argument of type sas_elem_t.
2776*10652SHyon.Kim@Sun.COM  * Return:
2777*10652SHyon.Kim@Sun.COM  * 	<0 - arg1 is less than arg2.
2778*10652SHyon.Kim@Sun.COM  * 	0 - arg1 is equal with arg2.
2779*10652SHyon.Kim@Sun.COM  * 	>0 - arg1 is more than arg2.
2780*10652SHyon.Kim@Sun.COM  */
2781*10652SHyon.Kim@Sun.COM static int
sas_elem_compare(const void * arg1,const void * arg2)2782*10652SHyon.Kim@Sun.COM sas_elem_compare(const void *arg1, const void *arg2)
2783*10652SHyon.Kim@Sun.COM {
2784*10652SHyon.Kim@Sun.COM 	sas_elem_t *p1, *p2;
2785*10652SHyon.Kim@Sun.COM 	p1 = (sas_elem_t *)arg1;
2786*10652SHyon.Kim@Sun.COM 	p2 = (sas_elem_t *)arg2;
2787*10652SHyon.Kim@Sun.COM 	return (sas_name_comp(p1->name, p2->name));
2788*10652SHyon.Kim@Sun.COM }
2789*10652SHyon.Kim@Sun.COM 
2790*10652SHyon.Kim@Sun.COM /*
2791*10652SHyon.Kim@Sun.COM  * Sorting function for HBA/HBA Port output.
2792*10652SHyon.Kim@Sun.COM  * array - elements array of type sas_elem_t.
2793*10652SHyon.Kim@Sun.COM  * nelem - number of elements in array of type sas_elem_t.
2794*10652SHyon.Kim@Sun.COM  */
2795*10652SHyon.Kim@Sun.COM static void
sas_elem_sort(sas_elem_t * array,int nelem)2796*10652SHyon.Kim@Sun.COM sas_elem_sort(sas_elem_t *array, int nelem)
2797*10652SHyon.Kim@Sun.COM {
2798*10652SHyon.Kim@Sun.COM 	qsort((void *)array, nelem, sizeof (sas_elem_t), sas_elem_compare);
2799*10652SHyon.Kim@Sun.COM }
2800