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