4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 #include <printAttrs.h>
34 typedef struct inputArgs
{
43 typedef struct tgt_mapping
{
44 SMHBA_SCSIENTRY tgtentry
;
48 struct tgt_mapping
*next
;
52 * Remote port tree node structure.
54 typedef struct smhba_rp_tree
{
55 SMHBA_PORTATTRIBUTES portattr
;
56 SMHBA_SAS_PORT sasattr
;
57 tgt_mapping
*first_entry
;
59 struct smhba_rp_tree
*parent
;
60 struct smhba_rp_tree
*child
;
61 struct smhba_rp_tree
*sibling
;
65 * Report LUN data structure.
71 typedef struct rep_luns_rsp
{
78 * The following flag is used for printing HBA header on-demand.
80 static int g_printHBA
= 0;
83 * The following structure is for sorted output of HBA and HBA Port.
85 typedef struct _sas_elem
{
91 * The following two functions are for generating hierachy of expander
95 sas_rp_tree_insert(rp_tree_t
**rproot
, rp_tree_t
*rpnode
);
97 sas_rp_tree_print(HBA_HANDLE handle
, char *adapterName
,
98 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
99 rp_tree_t
*rpnode
, inputArg_t
*input
, int gident
,
102 sas_rp_tree_print_desc(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
103 SMHBA_PORTATTRIBUTES
*port
, rp_tree_t
*desc
,
104 inputArg_t
*input
, int lident
, int gident
);
106 sas_print_rpnode(inputArg_t
*input
,
107 rp_tree_t
*rpnode
, int lident
, int gident
);
108 static void sas_rp_tree_free(rp_tree_t
*rproot
);
110 typedef int (*processPortFunc
)(HBA_HANDLE handle
, char *adapterName
,
111 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
112 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
);
114 static int processHBA(inputArg_t
*input
,
115 processPortFunc processPort
);
117 static int isPortWWNInArgv(inputArg_t
*input
, PHBA_WWN pWWN
);
118 static int isStringInArgv(inputArg_t
*input
, const char *adapterName
);
119 static boolean_t
compareLUName(char *cmdArg
, char *osName
);
120 static discoveredDevice
*LUList
= NULL
;
121 static targetPortList_t
*gTargetPortList
= NULL
;
123 /* processes for hanlding local HBA info */
124 static int handleHBA(SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
,
125 int numberOfPorts
, const char *adapterName
);
126 static int handleHBAPort(HBA_HANDLE handle
, char *adapterName
,
127 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
128 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
);
129 static int processHBAPortPhyInfo(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
130 SMHBA_PORTATTRIBUTES
*port
, int pflag
);
131 static int processHBAPortPhyStat(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
132 int phyIndex
, PSMHBA_SAS_PHY phyattrs
, int pflag
);
134 /* process for handling expander info */
135 static int handleExpander(HBA_HANDLE handle
, char *adapterName
,
136 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
137 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
);
139 /* process for handling target port info */
140 static int handleTargetPort(HBA_HANDLE handle
, char *adapterName
,
141 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
142 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
);
144 /* process for handling logical unit info */
145 static int handleLogicalUnit(HBA_HANDLE handle
, char *adapterName
,
146 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
147 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
);
149 /* process for target port SCSI processing */
151 searchTargetPortMappingData(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
152 SMHBA_PORTATTRIBUTES
*port
, SMHBA_SAS_PORT
*sasattr
,
153 struct targetPortConfig
*configData
);
155 /* process for target port config processing */
156 static int searchTargetPort(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
157 SMHBA_PORTATTRIBUTES
*port
, SMHBA_PORTATTRIBUTES
*targetattr
,
158 SMHBA_SAS_PORT
*sasattr
, int pflag
);
160 /* process for logical-unit config processing */
162 searchDevice(PSMHBA_SCSIENTRY entryP
, HBA_HANDLE handle
, HBA_WWN hbaPortWWN
,
163 HBA_WWN domainPortWWN
, char *portName
, int pflag
);
165 /* get domain port out of hba-port phy attr. */
166 HBA_STATUS
get_domainPort(HBA_HANDLE handle
,
167 int portindex
, PSMHBA_PORTATTRIBUTES port
,
168 HBA_WWN
*pdomainPort
);
171 sas_name_comp(const char *name1
, const char *name2
);
173 sas_elem_sort(sas_elem_t
*array
, int nelem
);
176 * function for hba subcommand
179 * wwnCount - count of the number of WWNs in wwn_argv
180 * if wwnCount > 0, then we will only print information for
181 * the hba ports listed in wwn_argv
182 * if wwnCount == 0, then we will print information on all hba ports
183 * wwn_argv - argument array of hba port WWNs
184 * options - any options specified by the caller
191 sas_util_list_hba(int hbaCount
, char **hba_argv
, cmdOptions_t
*options
)
194 int processHBA_flags
= 0;
198 /* process each of the options */
199 for (; options
->optval
; options
++) {
200 switch (options
->optval
) {
202 processHBA_flags
|= PRINT_VERBOSE
;
209 if ((status
= HBA_LoadLibrary()) != HBA_STATUS_OK
) {
210 (void *) fprintf(stderr
, "%s %s\n",
211 gettext("Failed to load SM-HBA libraries."
212 "Reason:"), getHBAStatus(status
));
217 memset(&input
, 0, sizeof (input
));
218 /* utilize wwnCount and wwn_argv for hbaCount and hba_argv */
219 input
.wwnCount
= hbaCount
;
220 input
.wwn_argv
= hba_argv
;
221 input
.pflag
= processHBA_flags
;
224 * Process and filter for every local hba,
225 * when the hba is not specificed, print all hba(s).
227 err_cnt
+= processHBA(&input
, NULL
);
229 (void) HBA_FreeLibrary();
235 * function for hba-port subcommand
238 * wwnCount - count of the number of WWNs in wwn_argv
239 * if wwnCount > 0, then we will only print information for
240 * the hba ports listed in wwn_argv
241 * if wwnCount == 0, then we will print information on all hba ports
242 * wwn_argv - argument array of hba port WWNs
243 * options - any options specified by the caller
250 sas_util_list_hbaport(int wwnCount
, char **wwn_argv
, cmdOptions_t
*options
)
253 int processHBA_flags
= 0;
256 char hbaName
[256] = {'\0'};
258 /* process each of the options */
259 for (; options
->optval
; options
++) {
260 switch (options
->optval
) {
262 (void *) strlcpy(hbaName
,
263 options
->optarg
, sizeof (hbaName
));
266 processHBA_flags
|= PRINT_PHY
;
269 processHBA_flags
|= PRINT_PHY_LINKSTAT
;
272 processHBA_flags
|= PRINT_VERBOSE
;
279 if ((status
= HBA_LoadLibrary()) != HBA_STATUS_OK
) {
280 (void *) fprintf(stderr
, "%s %s\n",
281 gettext("Failed to load SM-HBA libraries."
282 "Reason:"), getHBAStatus(status
));
287 memset(&input
, 0, sizeof (input
));
288 input
.wwnCount
= wwnCount
;
289 input
.wwn_argv
= wwn_argv
;
290 input
.hbaName
= hbaName
;
291 input
.pflag
= processHBA_flags
;
294 * Process and filter for every local hba-port,
295 * when the hba-port is not specificed, print all hba-port(s).
297 err_cnt
+= processHBA(&input
, handleHBAPort
);
299 (void) HBA_FreeLibrary();
305 * function for expander subcommand
308 * wwnCount - the number of Remote Port SAS Address in wwn_argv
309 * if wwnCount == 0, then print information on all
311 * if wwnCount > 0, then print information for the exapnders
313 * wwn_argv - array of WWNs
314 * options - options specified by the caller
321 sas_util_list_expander(int wwnCount
, char **wwn_argv
, cmdOptions_t
*options
)
324 int processHBA_flags
= 0;
325 char hbaPort
[MAXPATHLEN
+ 1] = {0};
329 /* process each of the options */
330 for (; options
->optval
; options
++) {
331 switch (options
->optval
) {
333 (void) strlcpy(hbaPort
, options
->optarg
,
337 processHBA_flags
|= PRINT_TARGET_PORT
;
340 processHBA_flags
|= PRINT_VERBOSE
;
347 if ((status
= HBA_LoadLibrary()) != HBA_STATUS_OK
) {
348 (void *) fprintf(stderr
, "%s %s\n",
349 gettext("Failed to load SM-HBA libraries."
350 "Reason:"), getHBAStatus(status
));
355 memset(&input
, 0, sizeof (input
));
356 input
.wwnCount
= wwnCount
;
357 input
.wwn_argv
= wwn_argv
;
358 input
.pflag
= processHBA_flags
;
359 input
.hbaName
= hbaPort
;
362 * Process and filter for every hba-port,
363 * when the hba-port is not specificed, print all hba-port(s).
365 err_cnt
+= processHBA(&input
, handleExpander
);
367 (void) HBA_FreeLibrary();
373 * function for target-port subcommand
376 * wwnCount - the number of Remote Port SAS Address in wwn_argv
377 * if wwnCount == 0, then print information on all
379 * if wwnCount > 0, then print information for the target ports
381 * wwn_argv - array of WWNs
382 * options - options specified by the caller
389 sas_util_list_targetport(int tpCount
, char **tpArgv
, cmdOptions_t
*options
)
392 int processHBA_flags
= 0;
395 targetPortList_t
*tpListWalk
;
399 /* process each of the options */
400 for (; options
->optval
; options
++) {
401 switch (options
->optval
) {
403 processHBA_flags
|= PRINT_TARGET_SCSI
;
406 processHBA_flags
|= PRINT_VERBOSE
;
413 if ((status
= HBA_LoadLibrary()) != HBA_STATUS_OK
) {
414 (void *) fprintf(stderr
, "%s %s\n",
415 gettext("Failed to load SM-HBA libraries."
416 "Reason:"), getHBAStatus(status
));
421 memset(&input
, 0, sizeof (input
));
422 input
.wwnCount
= tpCount
;
423 input
.wwn_argv
= tpArgv
;
424 input
.pflag
= processHBA_flags
;
427 * Process and filter for every hba-port,
428 * when the hba-port is not specificed, print all hba-port(s).
430 err_cnt
+= processHBA(&input
, handleTargetPort
);
433 /* list all target port */
434 for (tpListWalk
= gTargetPortList
; tpListWalk
!= NULL
;
435 tpListWalk
= tpListWalk
->next
) {
436 err_cnt
+= printTargetPortInfo(tpListWalk
, input
.pflag
);
440 * When operands provided, we should set the error code
441 * only if there are issues related with the operands.
445 * list any paths not found first
446 * this gives the user cleaner output
448 for (tp
= 0; tp
< tpCount
; tp
++) {
450 tmpAddr
= strtoull(tpArgv
[tp
], NULL
, 16);
451 if ((tmpAddr
== 0) && (errno
!= 0)) {
455 for (tpListWalk
= gTargetPortList
, tpFound
= B_FALSE
;
457 tpListWalk
= tpListWalk
->next
) {
458 if (wwnConversion(tpListWalk
->sasattr
.
459 LocalSASAddress
.wwn
) == tmpAddr
) {
464 if (tpFound
== B_FALSE
) {
465 (void *) fprintf(stderr
,
466 "Error: Target Port %s Not Found \n",
471 /* list all paths requested in order requested */
472 for (tp
= 0; tp
< tpCount
; tp
++) {
474 tmpAddr
= strtoull(tpArgv
[tp
], NULL
, 16);
475 if ((tmpAddr
== 0) && (errno
!= 0)) {
478 for (tpListWalk
= gTargetPortList
, tpFound
= B_FALSE
;
480 tpListWalk
= tpListWalk
->next
) {
481 if (wwnConversion(tpListWalk
->sasattr
.
482 LocalSASAddress
.wwn
) == tmpAddr
) {
483 err_cnt
+= printTargetPortInfo(
490 (void) HBA_FreeLibrary();
494 * This function will enumerate all the hba and hba ports,
495 * call the callback function to proceed with futher process.
498 * input - contains all the input parameters.
499 * processPort - a callback function when handling each port.
502 * 0 sucessfully processed handle
503 * >0 error has occured
506 processHBA(inputArg_t
*input
, processPortFunc processPort
)
510 int matchedHBAPorts
= 0;
511 int hbaPortExist
= 0;
514 HBA_UINT32 numberOfPorts
= 0;
516 HBA_PORTTYPE porttype
;
517 SMHBA_LIBRARYATTRIBUTES libattrs
;
518 SMHBA_ADAPTERATTRIBUTES attrs
;
519 SMHBA_PORTATTRIBUTES port
;
520 SMHBA_SAS_PORT sasattrs
;
522 int remote_avail
= 0;
524 sas_elem_t
*adpt_array
= NULL
;
525 sas_elem_t
*port_array
= NULL
;
527 numAdapters
= HBA_GetNumberOfAdapters();
528 if (numAdapters
== 0) {
529 (void *) fprintf(stderr
, "%s\n",
530 gettext("Error: No Adapters Found."));
535 * To deal with mismatching HBA/HBA Port/Expander Port, we need an
536 * array of flags for each operands.
538 if (input
->wwnCount
&& (processPort
!= handleTargetPort
) &&
539 (processPort
!= handleLogicalUnit
)) {
540 input
->wwn_flag
= calloc(input
->wwnCount
, sizeof (int));
541 if (input
->wwn_flag
== NULL
) {
542 (void *) fprintf(stderr
, "%s\n",
543 gettext("No enough memory on heap"));
548 adpt_array
= calloc(numAdapters
, sizeof (sas_elem_t
));
549 if (adpt_array
== NULL
) {
550 (void *) fprintf(stderr
, "%s\n",
551 gettext("No enough memory on heap"));
552 if (input
->wwn_flag
) {
553 free(input
->wwn_flag
);
554 input
->wwn_flag
= NULL
;
558 for (i
= 0; i
< numAdapters
; i
++) {
560 SMHBA_GetVendorLibraryAttributes(i
, &libattrs
);
562 * If we get SAS incompatible library warning here,
563 * just skip the following steps.
568 status
= HBA_GetAdapterName(i
, adpt_array
[i
].name
);
569 if (status
!= HBA_STATUS_OK
) {
570 (void *) fprintf(stderr
, "%s %d %s %s\n",
571 gettext("Error: Failed to get the name for"
573 i
, gettext("Reason:"),
574 getHBAStatus(status
));
578 adpt_array
[i
].index
= i
;
580 /* Sort the HBA Name in place. */
581 sas_elem_sort(adpt_array
, numAdapters
);
583 for (i
= 0; i
< numAdapters
; i
++) {
585 if (adpt_array
[i
].name
[0] != '\0') {
586 if ((handle
= HBA_OpenAdapter(adpt_array
[i
].name
))
588 (void *) fprintf(stderr
, "%s %s.\n",
589 gettext("Error: Failed to open adapter"),
599 * We need to support an adapter without hba port.
600 * So get attributes anyway.
602 memset(&attrs
, 0, sizeof (attrs
));
603 status
= SMHBA_GetAdapterAttributes(handle
, &attrs
);
604 while ((status
== HBA_STATUS_ERROR_TRY_AGAIN
||
605 status
== HBA_STATUS_ERROR_BUSY
) &&
606 times
++ < HBA_MAX_RETRIES
) {
608 status
= SMHBA_GetAdapterAttributes(handle
,
611 if (status
!= HBA_STATUS_OK
) {
612 (void *) fprintf(stderr
, "%s %s %s %s\n",
613 gettext("Error: Failed to get attributes"
614 " for HBA "), adpt_array
[i
].name
,
616 getHBAStatus(status
));
618 HBA_CloseAdapter(handle
);
623 status
= SMHBA_GetNumberOfPorts(handle
, &numberOfPorts
);
624 if (status
!= HBA_STATUS_OK
) {
625 (void *) fprintf(stderr
, "%s %s %s %s\n",
626 gettext("Error: Failed to get number of ports "
627 "for HBA"), adpt_array
[i
].name
,
629 getHBAStatus(status
));
630 HBA_CloseAdapter(handle
);
636 * Deal with each subcommand for hba filter here,
637 * processPort is NULL for hba subcommand.
639 if (processPort
== NULL
) {
640 matchedHBAs
+= handleHBA(&attrs
, input
,
641 numberOfPorts
, adpt_array
[i
].name
);
642 HBA_CloseAdapter(handle
);
644 } else if (processPort
== handleHBAPort
) {
645 if (input
->hbaName
[0] != '\0') {
646 if (strcmp(input
->hbaName
,
647 adpt_array
[i
].name
) == 0) {
660 * In order to have a sorted output for HBA Port, we should
661 * do the sorting before moving on.
664 port_array
= calloc(numberOfPorts
, sizeof (sas_elem_t
));
666 for (portIndex
= 0; portIndex
< numberOfPorts
; portIndex
++) {
667 if ((status
= SMHBA_GetPortType(handle
,
668 portIndex
, &porttype
)) != HBA_STATUS_OK
) {
669 (void *) fprintf(stderr
, "%s %s %s %s\n",
670 gettext("Failed to get adapter port type "
671 "for HBA"), adpt_array
[i
].name
,
673 getHBAStatus(status
));
677 if (porttype
!= HBA_PORTTYPE_SASDEVICE
) {
678 /* skip any non-sas hba port */
681 memset(&port
, 0, sizeof (port
));
682 memset(&sasattrs
, 0, sizeof (sasattrs
));
683 port
.PortSpecificAttribute
.SASPort
= &sasattrs
;
684 if ((status
= SMHBA_GetAdapterPortAttributes(
685 handle
, portIndex
, &port
)) != HBA_STATUS_OK
) {
687 * Not able to get port attributes.
688 * print out error message and
689 * move on to the next port
691 (void *) fprintf(stderr
, "%s %s %s %d %s %s\n",
692 gettext("Error: Failed to get port "
693 "attributes for HBA"), adpt_array
[i
].name
,
694 gettext("port index"), portIndex
,
696 getHBAStatus(status
));
700 (void) strlcpy(port_array
[portIndex
].name
,
702 sizeof (port_array
[portIndex
].name
));
703 port_array
[portIndex
].index
= portIndex
;
705 /* Sort the HBA Port Name here. */
707 sas_elem_sort(port_array
, numberOfPorts
);
710 * Sum up the local hba ports available.
712 local_avail
+= numberOfPorts
;
715 * Clear g_printHBA flag for expander subcommand.
719 /* process each port on the given adapter */
721 portIndex
< numberOfPorts
;
724 * We only handle the port which is valid.
726 if (port_array
[portIndex
].name
[0] == '\0') {
729 memset(&port
, 0, sizeof (port
));
730 memset(&sasattrs
, 0, sizeof (sasattrs
));
731 port
.PortSpecificAttribute
.SASPort
= &sasattrs
;
733 (void) SMHBA_GetAdapterPortAttributes(handle
,
734 port_array
[portIndex
].index
, &port
);
737 * We have different things to do for the three
740 if (processPort
== handleHBAPort
) {
742 * For hba-port, we will check whether the
743 * specified hba port exist first.
744 * But if no hba port specified, we should
745 * by pass this check(just let hbaPortExist
748 if (input
->wwnCount
> 0) {
749 if (isStringInArgv(input
,
750 port
.OSDeviceName
)) {
752 if (g_printHBA
== 0) {
753 (void *) fprintf(stdout
,
762 if (g_printHBA
== 0) {
763 (void *) fprintf(stdout
,
772 if (processPort
== handleExpander
) {
774 * For expander device, input->hbaName is
775 * the hba port name specified on the
776 * command line(with -p option).
778 if (input
->hbaName
[0] != '\0') {
779 if (strcmp(input
->hbaName
,
780 port
.OSDeviceName
) == 0)
786 if (processPort
== handleTargetPort
) {
788 * For target port, we don't need to check the
789 * hba port address, so let it go here.
794 if (processPort
== handleLogicalUnit
) {
796 * For lu, we don't need to check the hba
797 * port address, so let it go here.
803 if (port
.PortSpecificAttribute
.SASPort
->
804 NumberofDiscoveredPorts
) {
807 ret
+= (*processPort
)(handle
,
809 port_array
[portIndex
].index
, &port
,
812 * We should reset the hbaPortExist flag
813 * here for next round of check and count
814 * for the machedHBAPorts.
824 HBA_CloseAdapter(handle
);
832 * When we are here, we have traversed all the hba and hba ports.
834 if (matchedHBAs
== 0) {
835 (void *) fprintf(stderr
, "%s\n",
836 gettext("Error: Matching HBA not found."));
837 if (input
->wwn_flag
) {
838 free(input
->wwn_flag
);
839 input
->wwn_flag
= NULL
;
842 } else if (processPort
== NULL
) {
844 * processPort == NULL signifies hba subcommand.
845 * If enter here, it means we have at least one matching
846 * hba, we need to check if there are mismatching ones.
848 for (i
= 0; i
< input
->wwnCount
; i
++) {
849 if (input
->wwn_flag
[i
] == 0) {
850 (void *) fprintf(stderr
, "%s %s %s\n",
851 gettext("Error: HBA"),
853 gettext("not found."));
858 if (local_avail
> 0 && matchedHBAPorts
== 0) {
859 (void *) fprintf(stderr
, "%s\n",
860 gettext("Error: Matching HBA Port "
862 if (input
->wwn_flag
) {
863 free(input
->wwn_flag
);
864 input
->wwn_flag
= NULL
;
867 } else if (local_avail
== 0) {
868 (void *) fprintf(stderr
, "%s\n",
869 gettext("Error: No HBA Port Configured."));
870 if (input
->wwn_flag
) {
871 free(input
->wwn_flag
);
872 input
->wwn_flag
= NULL
;
875 } else if (processPort
== handleHBAPort
) {
877 * If enter here, we have at least one HBA port
878 * matched. For hba-port subcommand, we shall check
879 * whether there are operands mismatching.
881 for (i
= 0; i
< input
->wwnCount
; i
++) {
882 if (input
->wwn_flag
[i
] == 0) {
883 (void *) fprintf(stderr
, "%s %s %s\n",
884 gettext("Error: HBA Port"),
886 gettext("not found."));
894 * For expander subcommand, we need to check if the
895 * specified sas address(ese) exist (none/partial/all).
897 if (processPort
== handleExpander
) {
898 if (input
->wwnCount
> 0) {
900 for (i
= 0; i
< input
->wwnCount
; i
++) {
901 sum
+= input
->wwn_flag
[i
];
904 * If sum is zero, it means that for all the given
905 * operands matching count is zero. So none of the
906 * specified SAS address exist actually.
909 (void *) fprintf(stderr
, gettext("Error: "
910 "Matching SAS Address not found.\n"));
911 free(input
->wwn_flag
);
912 input
->wwn_flag
= NULL
;
917 * If we get here, it means that some of the specified
918 * sas address exist, we will know through looping the
921 for (i
= 0; i
< input
->wwnCount
; i
++) {
922 if (input
->wwn_flag
[i
] == 0) {
923 (void *) fprintf(stderr
, "%s %s %s\n",
924 gettext("Error: SAS Address"),
926 gettext("not found."));
931 /* even if no remote port is found it is not an error. */
933 if (input
->wwn_flag
) {
934 free(input
->wwn_flag
);
935 input
->wwn_flag
= NULL
;
941 * This function will handle the phy stuff for hba-port subcommand.
944 * handle - handle to hba port.
945 * portIndex - the index of hba port currently being processed.
946 * port - pointer to hba port attributes.
947 * pflag - options user specified.
950 * 0 sucessfully processed handle
951 * >0 error has occured
954 processHBAPortPhyInfo(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
955 SMHBA_PORTATTRIBUTES
*port
, int pflag
)
957 int phyIndex
= 0, err_cnt
= 0;
958 HBA_UINT32 numphys
= 0;
959 HBA_STATUS status
= 0;
960 SMHBA_SAS_PHY phyattrs
;
965 numphys
= port
->PortSpecificAttribute
.SASPort
->NumberofPhys
;
969 if ((pflag
& PRINT_PHY
) || (pflag
& PRINT_PHY_LINKSTAT
))
970 (void *) fprintf(stdout
, "%s\n", " Phy Information:");
975 for (phyIndex
= 0; phyIndex
< numphys
; phyIndex
++) {
976 memset(&phyattrs
, 0, sizeof (phyattrs
));
977 status
= SMHBA_GetSASPhyAttributes(
978 handle
, portIndex
, phyIndex
, &phyattrs
);
979 if (status
!= HBA_STATUS_OK
) {
980 (void *) fprintf(stderr
, "%s %d %s %s\n",
981 gettext("Failed to get SAS Phy attributes"
982 "phyIndex"), phyIndex
,
984 getHBAStatus(status
));
988 if (pflag
& PRINT_PHY
)
989 printHBAPortPhyInfo(&phyattrs
);
990 if (pflag
& PRINT_PHY_LINKSTAT
)
991 err_cnt
+= processHBAPortPhyStat(handle
,
992 portIndex
, phyIndex
, &phyattrs
, pflag
);
998 * This function will handle the phy stuff for hba-port subcommand.
1001 * handle - handle to hba port.
1002 * portIndex - the index of hba port currently being processed.
1003 * port - pointer to hba port attributes.
1004 * pflag - options user specified.
1007 * 0 sucessfully processed handle
1008 * >0 error has occured
1011 processHBAPortPhyStat(HBA_HANDLE handle
, HBA_UINT32 portIndex
, int phyIndex
,
1012 PSMHBA_SAS_PHY phyattrs
, int pflag
)
1014 HBA_STATUS status
= 0;
1015 SMHBA_PHYSTATISTICS phystat
;
1016 SMHBA_SASPHYSTATISTICS sasphystat
;
1018 if ((pflag
& PRINT_PHY
) == 0) {
1019 (void *) fprintf(stdout
, "%s %d\n",
1020 " Identifier:", phyattrs
->PhyIdentifier
);
1023 memset(&phystat
, 0, sizeof (phystat
));
1024 memset(&sasphystat
, 0, sizeof (sasphystat
));
1025 phystat
.SASPhyStatistics
= &sasphystat
;
1026 status
= SMHBA_GetPhyStatistics(handle
, portIndex
, phyIndex
, &phystat
);
1027 if (status
!= HBA_STATUS_OK
) {
1028 (void *) fprintf(stdout
, "%s\n",
1029 " Link Error Statistics:");
1030 (void *) fprintf(stderr
, "%s\n",
1031 gettext(" Failed to retrieve Link "
1032 "Error Statistics!"));
1035 printHBAPortPhyStatistics(phystat
.SASPhyStatistics
);
1040 * Check whether the pWWN exist in the WWNs list which specified by user.
1043 * input - contains all the input parameters.
1044 * pWWN - pointer to the hba port sas address.
1047 * 1 true, the pWWN exist in the sas address list specified.
1051 isPortWWNInArgv(inputArg_t
*input
, PHBA_WWN pWWN
)
1053 int port_wwn_counter
= 0;
1057 /* list only ports given in wwn_argv */
1058 for (port_wwn_counter
= 0;
1059 port_wwn_counter
< input
->wwnCount
;
1060 port_wwn_counter
++) {
1061 hbaWWN
= strtoull(input
->wwn_argv
[port_wwn_counter
], NULL
,
1063 if (hbaWWN
== 0 && errno
!= 0)
1065 if (wwnConversion(pWWN
->wwn
) == hbaWWN
) {
1066 if (input
->wwn_flag
) {
1067 input
->wwn_flag
[port_wwn_counter
]++;
1076 * Check whether the string value exists in the input list,
1077 * which specified by user.
1080 * input - contains all the input parameters.
1081 * stringName - could be hba adapter name
1085 * 1 true, the HBA exists in the list specified.
1089 isStringInArgv(inputArg_t
*input
, const char *stringName
)
1094 /* list only hba(s) given in wwn_argv */
1096 counter
< input
->wwnCount
;
1098 if (strcmp(input
->wwn_argv
[counter
],
1100 if (input
->wwn_flag
)
1101 input
->wwn_flag
[counter
]++;
1109 * Callback function for hba subcommand.
1112 * attrs - pointer to adapter attributes currently being processed.
1113 * input - contains all the input parameters.
1114 * numberOfPorts - number of ports of this HBA.
1119 static int handleHBA(SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
,
1120 int numberOfPorts
, const char *adapterName
)
1122 int matchingHBA
= 1;
1124 if (input
->wwnCount
== 0) {
1125 printHBAInfo(attrs
, input
->pflag
, numberOfPorts
, adapterName
);
1127 if (isStringInArgv(input
, adapterName
)) {
1129 input
->pflag
, numberOfPorts
, adapterName
);
1135 return (matchingHBA
);
1139 * Callback function for hba-port subcommand.
1142 * handle - handle to hba port.
1143 * portIndex - the index of hba port currently being processed.
1144 * port - pointer to hba port attributes.
1145 * attrs - pointer to adapter attributes currently being processed.
1146 * input - contains all the input parameters.
1149 * 0 sucessfully processed handle
1150 * >0 error has occured
1153 static int handleHBAPort(HBA_HANDLE handle
, char *adapterName
,
1154 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
1155 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
)
1158 printHBAPortInfo(port
, attrs
, input
->pflag
);
1159 ret
= processHBAPortPhyInfo(handle
, portIndex
, port
, input
->pflag
);
1164 * Callback function for expander subcommand.
1167 * handle - handle to hba port.
1168 * portIndex - the index of hba port currently being processed.
1169 * port - pointer to hba port attributes.
1170 * attrs - pointer to adapter attributes currently being processed.
1171 * input - contains all the input parameters.
1174 * 0 sucessfully processed handle
1175 * >0 error has occured
1178 static int handleExpander(HBA_HANDLE handle
, char *adapterName
,
1179 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
1180 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
)
1182 SMHBA_PORTATTRIBUTES attr
;
1183 SMHBA_SAS_PORT sasport
;
1188 rp_tree_t
*rproot
= NULL
;
1189 rp_tree_t
*unsolved_head
= NULL
;
1190 rp_tree_t
*unsolved_tail
= NULL
;
1191 rp_tree_t
*unsolved_sentinel
= NULL
;
1193 int numberOfEXP
= 0;
1194 int unsolved_inserted
= 0;
1195 int unsolved_left
= 0;
1196 int disco_port_fail
= 0;
1197 boolean_t firstPrinted
= B_FALSE
;
1199 memset(&attr
, 0, sizeof (attr
));
1200 memset(&sasport
, 0, sizeof (sasport
));
1201 attr
.PortSpecificAttribute
.SASPort
= &sasport
;
1204 * Retrive all expander device from this hba port first.
1206 if ((numberOfRP
= port
->PortSpecificAttribute
.SASPort
->
1207 NumberofDiscoveredPorts
) == 0) {
1208 /* no remote port. just return 0. */
1212 for (i
= 0; i
< numberOfRP
; i
++) {
1213 rpnode
= calloc(1, sizeof (rp_tree_t
));
1214 rpnode
->portattr
.PortSpecificAttribute
.SASPort
=
1216 status
= SMHBA_GetDiscoveredPortAttributes(handle
,
1217 portIndex
, i
, &rpnode
->portattr
);
1218 if (status
!= HBA_STATUS_OK
) {
1225 if (rpnode
->portattr
.PortType
== HBA_PORTTYPE_SASEXPANDER
) {
1229 * We will try to insert this expander device and target
1230 * ports into the topology tree. If we failed, we can chain
1231 * them together and try again when we have all the
1232 * discovered port information in hands.
1234 if (rproot
== NULL
&& memcmp(port
->
1235 PortSpecificAttribute
.SASPort
->LocalSASAddress
.wwn
,
1236 rpnode
->sasattr
.AttachedSASAddress
.wwn
,
1237 sizeof (HBA_WWN
)) == 0) {
1239 * The root node of tree should
1245 * If we can not set up the root node of
1246 * the tree or we failed to insert
1247 * the disocvered port node, queue it up then.
1249 if (rproot
== NULL
||
1250 sas_rp_tree_insert(&rproot
, rpnode
) != 0) {
1251 if (unsolved_head
== NULL
) {
1252 unsolved_head
= rpnode
;
1253 unsolved_tail
= rpnode
;
1255 rpnode
->sibling
= unsolved_head
;
1256 unsolved_head
= rpnode
;
1262 if (disco_port_fail
) {
1263 (void *) fprintf(stderr
, "%s %d %s %s\n",
1264 gettext("Error: Failed to get attributes for"),
1266 gettext("connected ports of HBA port"),
1267 port
->OSDeviceName
);
1270 /* no expander found. No need further processing. */
1271 if (numberOfEXP
== 0) {
1272 while (unsolved_head
) {
1274 unsolved_head
->sibling
;
1275 free(unsolved_head
);
1276 unsolved_head
= unsolved_tail
;
1278 if (rproot
) sas_rp_tree_free(rproot
);
1283 * When we're here, we should already have all information,
1284 * now we try again to insert them into the topology tree.
1285 * unsolved_head is the pointer which point to the head of
1286 * unsolved rpnode linked list.
1287 * unsolved_tail is the pointer which point to the tail of
1288 * unsolved rpnode linked list.
1289 * unsolved_sentinel is for insertion failure detection.
1290 * When we're trying to insert the rpnodes from unsolved
1291 * linked list, it may happen that some of the rpnodes can
1292 * not be inserted no matter how many times we loop through
1293 * this linked list. So we use unsolved_sentinel to identify
1294 * the tail of last round of scanning, and unsolved_inserted
1295 * which is a counter will be used to count how many rpnodes
1296 * have been inserted from last round, if it is zero, which
1297 * means that we can not insert rpnodes into rptree any more,
1298 * and we should stop and deallocate the memory they occupied.
1300 unsolved_sentinel
= unsolved_tail
;
1301 while (unsolved_head
) {
1302 rpnode
= unsolved_head
;
1303 unsolved_head
= unsolved_head
->sibling
;
1304 if (unsolved_head
== NULL
)
1305 unsolved_tail
= NULL
;
1306 rpnode
->sibling
= NULL
;
1307 if (sas_rp_tree_insert(&rproot
, rpnode
) != 0) {
1308 unsolved_tail
->sibling
= rpnode
;
1309 unsolved_tail
= rpnode
;
1310 if (rpnode
== unsolved_sentinel
) {
1312 * We just scanned one round for the
1313 * unsolved list. Check to see whether we
1314 * have nodes inserted, if none, we should
1315 * break in case of an indefinite loop.
1317 if (unsolved_inserted
== 0) {
1319 * Indicate there is unhandled node.
1320 * Chain free the whole unsolved
1326 unsolved_inserted
= 0;
1327 unsolved_sentinel
= unsolved_tail
;
1332 * We just inserted one rpnode, increment the
1333 * unsolved_inserted counter. We will utilize this
1334 * counter to detect an indefinite insertion loop.
1336 unsolved_inserted
++;
1340 /* check if there is left out discovered ports. */
1341 if (unsolved_left
) {
1343 (void *) fprintf(stderr
, "%s %s\n",
1344 gettext("Error: Failed to establish expander topology on"),
1345 port
->OSDeviceName
);
1346 (void *) fprintf(stderr
, "%s\n",
1347 gettext(" Folowing port(s) are unresolved."));
1348 while (unsolved_head
) {
1350 unsolved_head
->sibling
;
1351 (void *) fprintf(stderr
, "%s%016llx ",
1352 firstPrinted
? "" : "\t",
1353 wwnConversion(unsolved_head
->sasattr
.
1354 LocalSASAddress
.wwn
));
1355 if (firstPrinted
== B_FALSE
) firstPrinted
= B_TRUE
;
1356 free(unsolved_head
);
1357 unsolved_head
= unsolved_tail
;
1359 (void *) fprintf(stderr
, "\n");
1360 /* still print what we have */
1361 ret
+= sas_rp_tree_print(handle
, adapterName
, portIndex
,
1362 port
, rproot
, input
, 2 * TABLEN
, &printPort
);
1364 ret
+= sas_rp_tree_print(handle
, adapterName
, portIndex
,
1365 port
, rproot
, input
, 2 * TABLEN
, &printPort
);
1368 if (rproot
) sas_rp_tree_free(rproot
);
1374 * Callback function for target-port subcommand.
1377 * handle - handle to hba port.
1378 * portIndex - the index of hba port currently being processed.
1379 * port - pointer to hba port attributes.
1380 * attrs - pointer to adapter attributes currently being processed.
1381 * input - contains all the input parameters.
1384 * 0 sucessfully processed handle
1385 * >0 error has occured
1388 static int handleTargetPort(HBA_HANDLE handle
, char *adapterName
,
1389 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
1390 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
)
1393 SMHBA_PORTATTRIBUTES targetattr
;
1394 SMHBA_SAS_PORT sasattr
;
1397 int disco_port_fail
= 0;
1399 targetattr
.PortSpecificAttribute
.SASPort
= &sasattr
;
1401 for (i
= 0; i
< port
->PortSpecificAttribute
.SASPort
->
1402 NumberofDiscoveredPorts
; i
++) {
1403 status
= SMHBA_GetDiscoveredPortAttributes(handle
,
1404 portIndex
, i
, &targetattr
);
1405 if (status
!= HBA_STATUS_OK
) {
1408 /* skip expander device */
1409 if (targetattr
.PortType
!= HBA_PORTTYPE_SASEXPANDER
) {
1410 ret
+= searchTargetPort(handle
, portIndex
, port
,
1411 &targetattr
, &sasattr
, input
->pflag
);
1416 if (disco_port_fail
) {
1418 (void *) fprintf(stderr
, "%s %d %s %s\n",
1419 gettext("Error: Failed to get attributes for"),
1421 gettext("connected ports of HBA port"),
1422 port
->OSDeviceName
);
1428 * ****************************************************************************
1431 * compare names directly and also check if disk namees match with
1432 * different slice number or /devices path are speicified and matches.
1434 * cmdArg - first string to compare
1435 * osName - os name from attributes
1437 * returns B_TRUE if the strings match either directly or via devid
1440 * ****************************************************************************
1443 compareLUName(char *cmdArg
, char *osName
)
1446 boolean_t isSame
= B_FALSE
;
1447 char dev1
[MAXPATHLEN
], dev2
[MAXPATHLEN
];
1450 if (strcmp(cmdArg
, osName
) == 0) {
1453 /* user input didn't match, try to match the core of args. */
1454 (void) strlcpy(dev1
, cmdArg
, MAXPATHLEN
);
1455 (void) strlcpy(dev2
, osName
, MAXPATHLEN
);
1456 /* is this /devices path */
1457 if (((ch1
= strrchr(dev1
, ',')) != NULL
) &&
1458 ((ch2
= strrchr(dev2
, ',')) != NULL
)) {
1460 if (strcmp(dev1
, dev2
) == 0) {
1463 /* is this a /dev link */
1464 } else if ((strncmp(dev1
, "/dev/", 5) == 0) &&
1465 (strncmp(dev2
, "/dev/", 5) == 0)) {
1466 if ((strstr(dev1
, "dsk") != NULL
) &&
1467 ((strstr(dev2
, "dsk") != NULL
))) {
1468 /* if it is disk link */
1469 if (((ch1
= strrchr(dev1
, 's')) != NULL
) &&
1470 ((ch2
= strrchr(dev2
, 's')) != NULL
)) {
1472 if (strcmp(dev1
, dev2
) == 0) {
1477 /* other dev links */
1478 if (strcmp(dev1
, dev2
) == 0) {
1489 * Process logical-unit(lu) subcommand.
1492 * luCount - number of OS device name(s) specified by user.
1493 * luArgv - array of OS device name(s) specified by user.
1494 * options - all the options specified by user.
1497 * 0 sucessfully processed handle
1498 * >0 error has occured
1501 sas_util_list_logicalunit(int luCount
, char **luArgv
, cmdOptions_t
*options
)
1504 int processHBA_flags
= 0;
1506 boolean_t pathFound
;
1509 discoveredDevice
*LUListWalk
= NULL
;
1512 for (; options
->optval
; options
++) {
1513 if (options
->optval
== 'v') {
1514 processHBA_flags
|= PRINT_VERBOSE
;
1518 /* HBA_LoadLibrary() */
1519 if ((status
= HBA_LoadLibrary()) != HBA_STATUS_OK
) {
1520 (void *) fprintf(stderr
, "%s %s\n",
1521 gettext("Failed to load SM-HBA libraries."
1522 "Reason:"), getHBAStatus(status
));
1527 memset(&input
, 0, sizeof (input
));
1528 input
.pflag
= processHBA_flags
;
1529 input
.wwnCount
= luCount
;
1530 input
.wwn_argv
= luArgv
;
1532 err_cnt
+= processHBA(&input
, handleLogicalUnit
);
1533 verbose
= (input
.pflag
& PRINT_VERBOSE
) ? B_TRUE
: B_FALSE
;
1536 /* list all paths */
1537 for (LUListWalk
= LUList
; LUListWalk
!= NULL
;
1538 LUListWalk
= LUListWalk
->next
) {
1539 err_cnt
+= printOSDeviceNameInfo(LUListWalk
, verbose
);
1543 * When operands provided, we should set the error code
1544 * only if there are issues related with the operands.
1548 * list any paths not found first
1549 * this gives the user cleaner output
1551 for (lu
= 0; lu
< luCount
; lu
++) {
1552 for (LUListWalk
= LUList
, pathFound
= B_FALSE
;
1554 LUListWalk
= LUListWalk
->next
) {
1555 if (compareLUName(luArgv
[lu
],
1556 LUListWalk
->OSDeviceName
)) {
1561 if (pathFound
== B_FALSE
) {
1562 (void *) fprintf(stderr
,
1563 "Error: Logical Unit %s Not Found \n",
1568 /* list all paths requested in order requested */
1569 for (lu
= 0; lu
< luCount
; lu
++) {
1570 for (LUListWalk
= LUList
; LUListWalk
!= NULL
;
1571 LUListWalk
= LUListWalk
->next
) {
1572 if (compareLUName(luArgv
[lu
],
1573 LUListWalk
->OSDeviceName
)) {
1574 err_cnt
+= printOSDeviceNameInfo(
1581 (void) HBA_FreeLibrary();
1586 * Callback function for logical-unit(lu) subcommand.
1589 * handle - handle to hba port.
1590 * portIndex - the index of hba port currently being processed.
1591 * port - pointer to hba port attributes.
1592 * attrs - pointer to adapter attributes currently being processed.
1593 * input - contains all the input parameters.
1596 * 0 sucessfully processed handle
1597 * >0 error has occured
1600 static int handleLogicalUnit(HBA_HANDLE handle
, char *adapterName
,
1601 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
1602 SMHBA_ADAPTERATTRIBUTES
*attrs
, inputArg_t
*input
)
1605 SMHBA_TARGETMAPPING
*map
;
1606 HBA_WWN hbaPortWWN
, domainPortWWN
;
1607 char *portName
= NULL
;
1612 hbaPortWWN
= port
->PortSpecificAttribute
.SASPort
->LocalSASAddress
;
1613 portName
= port
->OSDeviceName
;
1615 status
= get_domainPort(handle
, portIndex
, port
, &domainPortWWN
);
1619 case HBA_STATUS_ERROR_NOT_SUPPORTED
:
1620 /* don't increase error flag for no phy configuration */
1622 case HBA_STATUS_ERROR
:
1627 if ((map
= calloc(1, sizeof (*map
))) == NULL
) {
1628 (void *) fprintf(stderr
, "%s\n",
1629 gettext("No enough memory on heap."));
1632 map
->NumberOfEntries
= 1;
1635 * First, we need to get the target mapping data from this hba
1638 status
= SMHBA_GetTargetMapping(handle
,
1639 hbaPortWWN
, domainPortWWN
, map
);
1641 if (status
== HBA_STATUS_ERROR_MORE_DATA
) {
1642 numentries
= map
->NumberOfEntries
;
1644 map
= calloc(1, sizeof (HBA_UINT32
) +
1645 (numentries
* sizeof (SMHBA_SCSIENTRY
)));
1647 (void *) fprintf(stderr
, "%s\n",
1648 gettext("No enough memory on heap."));
1651 map
->NumberOfEntries
= numentries
;
1652 status
= SMHBA_GetTargetMapping(handle
,
1653 hbaPortWWN
, domainPortWWN
, map
);
1656 if (status
!= HBA_STATUS_OK
) {
1657 (void *) fprintf(stderr
, "%s %016llx %s %s\n",
1658 gettext("Error: Failed to get SCSI mapping data for "
1659 "the HBA port"), wwnConversion(hbaPortWWN
.wwn
),
1661 getHBAStatus(status
));
1667 * By iterating each entry of the targetmapping data, we will
1668 * construct a global list of logical unit.
1670 for (count
= 0; count
< map
->NumberOfEntries
; count
++) {
1671 ret
+= searchDevice(
1672 &(map
->entry
[count
]), handle
, hbaPortWWN
, domainPortWWN
,
1673 portName
, input
->pflag
);
1680 * Search the matching targetmapping data for given target port and SAM LUN
1681 * and return target mapping data if found.
1684 * handle - handle to hba port.
1685 * portIndex - hba port index
1686 * port - hba port attributes.
1687 * targetportWWN - target port SAS address.
1688 * domainportWWN - domain port SAS address.
1689 * domainportttr - target port SAS attributes.
1690 * samLUN - samLUN from report LUNs data.
1691 * data - matching target mapping data.
1694 * 0 sucessfully processed handle
1695 * >0 error has occured
1698 searchTargetPortMappingData(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
1699 SMHBA_PORTATTRIBUTES
*port
, SMHBA_SAS_PORT
*sasattr
,
1700 struct targetPortConfig
*configData
)
1704 SMHBA_TARGETMAPPING
*map
= NULL
;
1705 HBA_WWN hbaPortWWN
, domainPortWWN
;
1706 int numentries
, count
;
1707 targetPortMappingData_t
*TPMapData
;
1708 struct scsi_inquiry inq
;
1709 struct scsi_extended_sense sense
;
1710 HBA_UINT32 responseSize
, senseSize
= 0;
1711 uchar_t rawLUNs
[DEFAULT_LUN_LENGTH
], *lun_string
;
1712 HBA_UINT8 scsiStatus
;
1713 rep_luns_rsp_t
*lun_resp
;
1714 int lunNum
, numberOfLun
, lunCount
;
1715 uint32_t lunlength
, tmp_lunlength
;
1717 SMHBA_SCSILUN smhbaLUN
;
1719 hbaPortWWN
= port
->PortSpecificAttribute
.SASPort
->
1722 status
= get_domainPort(handle
, portIndex
, port
, &domainPortWWN
);
1723 if (status
== HBA_STATUS_OK
) {
1724 if ((map
= calloc(1, sizeof (*map
))) == NULL
) {
1725 (void *) fprintf(stderr
, "%s\n",
1726 gettext("No enough memory on heap."));
1729 map
->NumberOfEntries
= 1;
1731 status
= SMHBA_GetTargetMapping(handle
, hbaPortWWN
,
1732 domainPortWWN
, map
);
1734 if (status
== HBA_STATUS_ERROR_MORE_DATA
) {
1735 numentries
= map
->NumberOfEntries
;
1737 map
= calloc(1, sizeof (HBA_UINT32
) +
1738 (numentries
* sizeof (SMHBA_SCSIENTRY
)));
1740 (void *) fprintf(stderr
, "%s\n",
1741 gettext("No enough memory on heap."));
1744 map
->NumberOfEntries
= numentries
;
1745 status
= SMHBA_GetTargetMapping(handle
,
1746 hbaPortWWN
, domainPortWWN
, map
);
1749 if (status
!= HBA_STATUS_OK
) {
1750 /* continue to build mapping data based SCSI info */
1758 * Get report lun data.
1760 responseSize
= DEFAULT_LUN_LENGTH
;
1761 senseSize
= sizeof (struct scsi_extended_sense
);
1762 (void) memset(&sense
, 0, sizeof (sense
));
1763 status
= SMHBA_ScsiReportLUNs(
1766 sasattr
->LocalSASAddress
,
1771 (void *) &sense
, &senseSize
);
1774 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
1775 * a remote HBA and move on
1777 if (status
!= HBA_STATUS_OK
) {
1778 configData
->reportLUNsFailed
= B_TRUE
;
1781 * Let's search mapping data and indicate that Report
1784 for (count
= 0; count
< map
->NumberOfEntries
; count
++) {
1785 if (memcmp(map
->entry
[count
].PortLun
.
1786 PortWWN
.wwn
, sasattr
->LocalSASAddress
.wwn
,
1787 sizeof (HBA_WWN
)) == 0) {
1788 /* allocate mapping data for each LUN */
1789 TPMapData
= calloc(1,
1790 sizeof (targetPortMappingData_t
));
1791 if (TPMapData
== NULL
) {
1792 (void *) fprintf(stderr
, "%s\n",
1793 gettext("No enough "
1798 TPMapData
->mappingExist
= B_TRUE
;
1800 map
->entry
[count
].ScsiId
.ScsiOSLun
;
1801 (void) strlcpy(TPMapData
->osDeviceName
,
1802 map
->entry
[count
].ScsiId
.
1804 sizeof (TPMapData
->osDeviceName
));
1805 TPMapData
->inq_vid
[0] = '\0';
1806 TPMapData
->inq_pid
[0] = '\0';
1807 TPMapData
->inq_dtype
= DTYPE_UNKNOWN
;
1808 if (configData
->map
== NULL
) {
1809 configData
->map
= TPMapData
;
1812 configData
->map
->next
;
1813 configData
->map
= TPMapData
;
1821 lun_resp
= (rep_luns_rsp_t
*)((void *)rawLUNs
);
1822 (void) memcpy(&tmp_lunlength
, &(lun_resp
->length
),
1823 sizeof (tmp_lunlength
));
1824 lunlength
= ntohl(tmp_lunlength
);
1825 (void) memcpy(&numberOfLun
, &lunlength
, sizeof (numberOfLun
));
1826 for (lunCount
= 0; lunCount
< (numberOfLun
/ 8); lunCount
++) {
1827 /* allocate mapping data for each LUN */
1828 TPMapData
= calloc(1,
1829 sizeof (targetPortMappingData_t
));
1830 if (TPMapData
== NULL
) {
1831 (void *) fprintf(stderr
, "%s\n",
1832 gettext("No enough memory."));
1837 (void) memcpy(&TPMapData
->reportLUN
, lun_resp
->
1838 lun
[lunCount
].val
, sizeof (SMHBA_SCSILUN
));
1841 * now issue standard inquiry to get Vendor
1842 * and product information
1844 responseSize
= sizeof (struct scsi_inquiry
);
1845 senseSize
= sizeof (struct scsi_extended_sense
);
1846 (void) memset(&inq
, 0, sizeof (struct scsi_inquiry
));
1847 (void) memset(&sense
, 0, sizeof (sense
));
1848 sasLUN
= ntohll(wwnConversion(lun_resp
->lun
[lunCount
].val
));
1849 (void) memcpy(&smhbaLUN
, &sasLUN
, sizeof (SMHBA_SCSILUN
));
1850 status
= SMHBA_ScsiInquiry(
1853 sasattr
->LocalSASAddress
,
1858 (void *) &inq
, &responseSize
,
1860 (void *) &sense
, &senseSize
);
1861 if (status
!= HBA_STATUS_OK
) {
1862 TPMapData
->inq_vid
[0] = '\0';
1863 TPMapData
->inq_pid
[0] = '\0';
1864 TPMapData
->inq_dtype
= DTYPE_UNKNOWN
;
1865 /* indicate that inquiry for this lun is failed */
1866 TPMapData
->inquiryFailed
= B_TRUE
;
1868 (void *) memcpy(TPMapData
->inq_vid
, inq
.inq_vid
,
1869 sizeof (TPMapData
->inq_vid
));
1870 (void *) memcpy(TPMapData
->inq_pid
, inq
.inq_pid
,
1871 sizeof (TPMapData
->inq_pid
));
1872 TPMapData
->inq_dtype
= inq
.inq_dtype
;
1876 for (count
= 0; count
< map
->NumberOfEntries
; count
++) {
1877 if ((memcmp(map
->entry
[count
].PortLun
.
1878 PortWWN
.wwn
, sasattr
->LocalSASAddress
.wwn
,
1879 sizeof (HBA_WWN
)) == 0) &&
1880 (memcmp(&(map
->entry
[count
].PortLun
.
1881 TargetLun
), &smhbaLUN
,
1882 sizeof (SMHBA_SCSILUN
))
1884 TPMapData
->mappingExist
= B_TRUE
;
1886 map
->entry
[count
].ScsiId
.ScsiOSLun
;
1887 (void) strlcpy(TPMapData
->osDeviceName
,
1888 map
->entry
[count
].ScsiId
.
1890 sizeof (TPMapData
->osDeviceName
));
1894 if (count
== map
->NumberOfEntries
) {
1895 TPMapData
->osDeviceName
[0] = '\0';
1896 lun_string
= lun_resp
->lun
[lunCount
].val
;
1897 lunNum
= ((lun_string
[0] & 0x3F) << 8) |
1899 TPMapData
->osLUN
= lunNum
;
1902 /* Not able to get any target mapping information */
1903 TPMapData
->osDeviceName
[0] = '\0';
1904 lun_string
= lun_resp
->lun
[lunCount
].val
;
1905 lunNum
= ((lun_string
[0] & 0x3F) << 8) |
1907 TPMapData
->osLUN
= lunNum
;
1910 if (configData
->map
== NULL
) {
1911 configData
->map
= TPMapData
;
1913 TPMapData
->next
= configData
->map
->next
;
1914 configData
->map
= TPMapData
;
1922 * Search the discovered LUs and construct the global LU list.
1925 * handle - handle to hba port.
1926 * portIndex - hba port index
1927 * port - hba port attributes.
1928 * targetattr - target port attributes.
1929 * sasattr - target port SAS attributes.
1930 * pflag - options the user specified.
1933 * 0 sucessfully processed handle
1934 * >0 error has occured
1937 searchTargetPort(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
1938 SMHBA_PORTATTRIBUTES
*port
, SMHBA_PORTATTRIBUTES
*targetattr
,
1939 SMHBA_SAS_PORT
*sasattr
, int pflag
)
1943 HBA_WWN domainPortWWN
;
1944 targetPortList_t
*discoveredTP
, *newTP
;
1945 targetPortConfig_t
*TPConfig
, *newConfig
, *prevConfig
;
1946 boolean_t foundTP
= B_FALSE
;
1947 boolean_t foundConfig
= B_FALSE
;
1949 SMHBA_PORTATTRIBUTES tgtattr
;
1950 SMHBA_SAS_PORT tgtsasport
;
1951 int expanderValid
= 0;
1953 status
= get_domainPort(handle
, portIndex
, port
, &domainPortWWN
);
1957 case HBA_STATUS_ERROR_NOT_SUPPORTED
:
1958 /* don't increase error flag for no phy configuration */
1960 case HBA_STATUS_ERROR
:
1966 * First, we will iterate the already constructed target port
1967 * list to see whether there is a target port already exist with
1968 * matching target port SAS address.
1970 for (discoveredTP
= gTargetPortList
; discoveredTP
!= NULL
;
1971 discoveredTP
= discoveredTP
->next
) {
1972 if (memcmp((void *)sasattr
->LocalSASAddress
.wwn
,
1973 (void *)discoveredTP
->sasattr
.LocalSASAddress
.wwn
,
1974 sizeof (HBA_WWN
)) == 0) {
1976 * if the target port exist and
1977 * verbose is not set, just return
1979 if (((pflag
& PRINT_VERBOSE
) == 0) &&
1980 ((pflag
& PRINT_TARGET_SCSI
) == 0)) {
1988 if (foundTP
== B_TRUE
) {
1990 * If there is a target port already exist, we should
1991 * add more information on the target port to construct the
1993 * Here we will check whether the current hba port name
1994 * has already been added.
1996 /* first get the expander SAS address compare */
1997 if (memcmp((void *)port
->PortSpecificAttribute
.SASPort
->
1998 LocalSASAddress
.wwn
, (void *)sasattr
->
1999 AttachedSASAddress
.wwn
, sizeof (HBA_WWN
)) == 0) {
2001 (void) memset(expander
.wwn
, 0,
2005 if (wwnConversion(sasattr
->AttachedSASAddress
.wwn
)
2007 /* expander exist. We should verify it. */
2008 (void) memcpy((void *)expander
.wwn
,
2009 (void *)sasattr
->AttachedSASAddress
.wwn
,
2012 memset(&tgtattr
, 0, sizeof (tgtattr
));
2013 memset(&tgtsasport
, 0,
2014 sizeof (tgtsasport
));
2015 tgtattr
.PortSpecificAttribute
.SASPort
2017 status
= SMHBA_GetPortAttributesByWWN(handle
,
2018 sasattr
->AttachedSASAddress
, domainPortWWN
,
2020 if (status
== HBA_STATUS_OK
&& tgtattr
.PortType
2021 == HBA_PORTTYPE_SASEXPANDER
) {
2027 for (TPConfig
= discoveredTP
->configEntry
,
2028 foundConfig
= B_FALSE
; TPConfig
!= NULL
;
2029 TPConfig
= TPConfig
->next
) {
2030 if ((strcmp(TPConfig
->hbaPortName
,
2031 port
->OSDeviceName
) == 0) &&
2032 (memcmp((void *)expander
.wwn
, (void *)TPConfig
->
2033 expanderSASAddr
.wwn
,
2034 sizeof (HBA_WWN
)) == 0)) {
2035 foundConfig
= B_TRUE
;
2041 * If we get here, it means that it is a new hba port/exapnder
2042 * sas address for this discovered target port.
2044 if (foundConfig
== B_FALSE
) {
2045 newConfig
= (targetPortConfig_t
*)calloc(1,
2046 sizeof (targetPortConfig_t
));
2047 if (newConfig
== NULL
) {
2048 (void *) fprintf(stderr
,
2049 "%s\n", strerror(errno
));
2053 (void) strlcpy(newConfig
->hbaPortName
, port
->
2054 OSDeviceName
, sizeof (newConfig
->hbaPortName
));
2055 (void) memcpy((void *)newConfig
->expanderSASAddr
.wwn
,
2056 (void *)expander
.wwn
, sizeof (HBA_WWN
));
2057 newConfig
->expanderValid
= expanderValid
;
2058 if (discoveredTP
->configEntry
== NULL
) {
2059 discoveredTP
->configEntry
= newConfig
;
2061 TPConfig
= discoveredTP
->configEntry
;
2062 prevConfig
= TPConfig
;
2063 while (TPConfig
!= NULL
&&
2064 sas_name_comp(newConfig
->hbaPortName
,
2065 TPConfig
->hbaPortName
) > 0) {
2066 prevConfig
= TPConfig
;
2067 TPConfig
= TPConfig
->next
;
2069 if (TPConfig
== prevConfig
) {
2070 /* Should be inserted in the head. */
2071 newConfig
->next
= TPConfig
;
2072 discoveredTP
->configEntry
= newConfig
;
2074 newConfig
->next
= TPConfig
;
2075 prevConfig
->next
= newConfig
;
2078 /* if scsi option is not set return */
2079 if ((pflag
& PRINT_TARGET_SCSI
) == 0) {
2082 return (searchTargetPortMappingData(
2083 handle
, portIndex
, port
,
2084 sasattr
, newConfig
));
2089 * Here we got a new target port which has not ever exist
2090 * in our global target port list. So add it to the list.
2093 newTP
= (targetPortList_t
*)calloc(1,
2094 sizeof (targetPortList_t
));
2096 if (newTP
== NULL
) {
2097 (void *) fprintf(stderr
, "%s\n", strerror(errno
));
2101 (void) memcpy((void *)&newTP
->targetattr
, (void *)targetattr
,
2102 sizeof (SMHBA_PORTATTRIBUTES
));
2103 (void) memcpy((void *)&newTP
->sasattr
, (void *)sasattr
,
2104 sizeof (SMHBA_SAS_PORT
));
2106 newConfig
= (targetPortConfig_t
*)calloc(1,
2107 sizeof (targetPortConfig_t
));
2109 if (newConfig
== NULL
) {
2110 (void *) fprintf(stderr
, "%s\n", strerror(errno
));
2115 (void) strlcpy(newConfig
->hbaPortName
, port
->OSDeviceName
,
2116 sizeof (newConfig
->hbaPortName
));
2117 if (memcmp((void *)port
->PortSpecificAttribute
.SASPort
->
2118 LocalSASAddress
.wwn
, (void *)sasattr
->
2119 AttachedSASAddress
.wwn
, sizeof (HBA_WWN
)) == 0) {
2121 (void) memset(newConfig
->expanderSASAddr
.wwn
,
2122 0, sizeof (HBA_WWN
));
2124 /* expander exist. We should verify it. */
2125 (void) memcpy((void *)newConfig
->expanderSASAddr
.wwn
,
2126 (void *)sasattr
->AttachedSASAddress
.wwn
,
2129 memset(&tgtattr
, 0, sizeof (tgtattr
));
2130 memset(&tgtsasport
, 0, sizeof (tgtsasport
));
2131 tgtattr
.PortSpecificAttribute
.SASPort
= &tgtsasport
;
2132 status
= SMHBA_GetPortAttributesByWWN(handle
,
2133 sasattr
->AttachedSASAddress
, domainPortWWN
,
2135 if (status
== HBA_STATUS_OK
&& tgtattr
.PortType
==
2136 HBA_PORTTYPE_SASEXPANDER
) {
2139 newConfig
->expanderValid
= expanderValid
;
2142 newTP
->configEntry
= newConfig
;
2144 newTP
->next
= gTargetPortList
; /* insert at head */
2145 gTargetPortList
= newTP
; /* set new head */
2147 /* if scsi option is not set return */
2148 if ((pflag
& PRINT_TARGET_SCSI
) == 0) {
2151 return (searchTargetPortMappingData(
2152 handle
, portIndex
, port
, sasattr
, newConfig
));
2159 * Search the discovered LUs and construct the global LU list.
2162 * entryP - one of the target mapping data.
2163 * handle - handle to hba port.
2164 * hbaPortWWN - hba port sas address.
2165 * domainPortWWN - domain port WWN for this sas domain.
2166 * portName - HBA port OS Device Name.
2167 * pflag - options the user specified.
2170 * 0 sucessfully processed handle
2171 * >0 error has occured
2174 searchDevice(PSMHBA_SCSIENTRY entryP
,
2175 HBA_HANDLE handle
, HBA_WWN hbaPortWWN
, HBA_WWN domainPortWWN
,
2176 char *portName
, int pflag
)
2180 discoveredDevice
*discoveredLU
, *newDevice
;
2181 portList
*portElem
, *newPort
, *prevElem
;
2182 tgtPortWWNList
*newTgtWWN
, *TgtWWNList
;
2183 boolean_t foundDevice
= B_FALSE
;
2184 boolean_t foundPort
= B_FALSE
;
2185 struct scsi_inquiry inq
;
2186 HBA_UINT32 responseSize
, senseSize
= 0;
2187 HBA_UINT8 inq_status
;
2188 SMHBA_SCSILUN smhbaLUN
;
2189 struct scsi_extended_sense sense
;
2191 /* if OSDeviceName is not set, we don't need to search */
2192 if (entryP
->ScsiId
.OSDeviceName
[0] == '\0') {
2197 * First, we will iterate the already constructed discovered LU
2198 * list to see whether there is a LU already exist with the same OS
2199 * device name as current target mapping data entry.
2201 for (discoveredLU
= LUList
; discoveredLU
!= NULL
;
2202 discoveredLU
= discoveredLU
->next
) {
2203 if (strcmp(entryP
->ScsiId
.OSDeviceName
,
2204 discoveredLU
->OSDeviceName
) == 0) {
2206 * if there is existing OS Device Name and
2207 * verbose is not set, just return
2209 if ((pflag
& PRINT_VERBOSE
) == 0) {
2212 foundDevice
= B_TRUE
;
2217 if (foundDevice
== B_TRUE
) {
2219 * If there is a discovered LU already exist, we should
2220 * add more information on this LU to construct the whole
2222 * Here we will check whether the current hba port has
2223 * already been added.
2225 for (portElem
= discoveredLU
->HBAPortList
,
2226 foundPort
= B_FALSE
; portElem
!= NULL
;
2227 portElem
= portElem
->next
) {
2228 if (strcmp(portElem
->portName
,
2236 * If we get here, it means that it is a new hba port name
2237 * for this discovered LU.
2239 if (foundPort
== B_FALSE
) {
2240 newPort
= (portList
*)calloc(1, sizeof (portList
));
2241 if (newPort
== NULL
) {
2242 (void *) fprintf(stderr
,
2243 "%s\n", strerror(errno
));
2246 (void) strlcpy(newPort
->portName
, portName
,
2247 sizeof (newPort
->portName
));
2249 portElem
= discoveredLU
->HBAPortList
;
2250 prevElem
= portElem
;
2251 while (portElem
!= NULL
&&
2252 sas_name_comp(newPort
->portName
, portElem
->portName
)
2254 prevElem
= portElem
;
2255 portElem
= portElem
->next
;
2257 if (portElem
== prevElem
) {
2258 /* Insert in the head of list. */
2259 newPort
->next
= portElem
;
2260 discoveredLU
->HBAPortList
= newPort
;
2262 newPort
->next
= portElem
;
2263 prevElem
->next
= newPort
;
2265 /* add Target Port */
2266 newPort
->tgtPortWWN
= (tgtPortWWNList
*)calloc(1,
2267 sizeof (tgtPortWWNList
));
2268 if (newPort
->tgtPortWWN
== NULL
) {
2269 (void *) fprintf(stderr
,
2270 "%s\n", strerror(errno
));
2273 (void *) memcpy((void *)&(newPort
->tgtPortWWN
->portWWN
),
2274 (void *)&(entryP
->PortLun
.PortWWN
),
2277 newPort
->tgtPortWWN
->scsiOSLun
=
2278 entryP
->ScsiId
.ScsiOSLun
;
2281 * Otherwise, we just need to add the target port
2282 * sas address information.
2284 for (TgtWWNList
= portElem
->tgtPortWWN
;
2286 TgtWWNList
= TgtWWNList
->next
) {
2287 if (memcmp(&TgtWWNList
->portWWN
,
2288 &entryP
->PortLun
.PortWWN
,
2289 sizeof (HBA_WWN
)) == 0)
2292 /* add it to existing */
2293 newTgtWWN
= (tgtPortWWNList
*)calloc(1,
2294 sizeof (tgtPortWWNList
));
2295 if (newTgtWWN
== NULL
) {
2296 (void *) fprintf(stderr
,
2297 "%s\n", strerror(errno
));
2300 /* insert at head */
2301 newTgtWWN
->next
= portElem
->tgtPortWWN
;
2302 portElem
->tgtPortWWN
= newTgtWWN
;
2303 (void *) memcpy((void *)&(newTgtWWN
->portWWN
),
2304 (void *)&(entryP
->PortLun
.PortWWN
),
2307 newTgtWWN
->scsiOSLun
=
2308 entryP
->ScsiId
.ScsiOSLun
;
2312 * Here we got a new discovered LU which has not ever exist
2313 * in our global LU list. So add it into our global LU
2316 newDevice
= (discoveredDevice
*)calloc(1,
2317 sizeof (discoveredDevice
));
2319 if (newDevice
== NULL
) {
2320 (void *) fprintf(stderr
, "%s\n", strerror(errno
));
2323 newDevice
->next
= LUList
; /* insert at head */
2324 LUList
= newDevice
; /* set new head */
2326 /* copy device name */
2327 (void *) strlcpy(newDevice
->OSDeviceName
,
2328 entryP
->ScsiId
.OSDeviceName
,
2329 sizeof (newDevice
->OSDeviceName
));
2331 /* if verbose is not set return */
2332 if ((pflag
& PRINT_VERBOSE
) == 0) {
2337 newDevice
->HBAPortList
= (portList
*)calloc(1,
2339 if (newDevice
->HBAPortList
== NULL
) {
2340 (void *) fprintf(stderr
, "%s\n", strerror(errno
));
2343 (void) strlcpy(newDevice
->HBAPortList
->portName
,
2344 portName
, sizeof (newDevice
->HBAPortList
->portName
));
2346 newDevice
->HBAPortList
->tgtPortWWN
=
2347 (tgtPortWWNList
*)calloc(1, sizeof (tgtPortWWNList
));
2348 if (newDevice
->HBAPortList
->tgtPortWWN
== NULL
) {
2349 (void *) fprintf(stderr
, "%s\n", strerror(errno
));
2353 (void *) memcpy((void *)&(newDevice
->HBAPortList
->\
2354 tgtPortWWN
->portWWN
),
2355 (void *)&(entryP
->PortLun
.PortWWN
),
2357 newDevice
->HBAPortList
->tgtPortWWN
->scsiOSLun
=
2358 entryP
->ScsiId
.ScsiOSLun
;
2360 responseSize
= sizeof (struct scsi_inquiry
);
2361 senseSize
= sizeof (struct scsi_extended_sense
);
2362 memset(&inq
, 0, sizeof (struct scsi_inquiry
));
2363 memset(&sense
, 0, sizeof (sense
));
2364 (void *) memcpy(&smhbaLUN
, &entryP
->PortLun
.TargetLun
,
2368 * Retrieve the VPD data for the newly found discovered LU.
2370 status
= SMHBA_ScsiInquiry(
2373 entryP
->PortLun
.PortWWN
,
2378 (void *) &inq
, &responseSize
,
2380 (void *) &sense
, &senseSize
);
2382 if (status
!= HBA_STATUS_OK
) {
2383 /* init VID/PID/dType as '\0' */
2384 newDevice
->VID
[0] = '\0';
2385 newDevice
->PID
[0] = '\0';
2386 newDevice
->dType
= DTYPE_UNKNOWN
;
2387 /* initialize inq status */
2388 newDevice
->inquiryFailed
= B_TRUE
;
2391 (void *) memcpy(newDevice
->VID
, inq
.inq_vid
,
2392 sizeof (newDevice
->VID
));
2393 (void *) memcpy(newDevice
->PID
, inq
.inq_pid
,
2394 sizeof (newDevice
->PID
));
2395 newDevice
->dType
= inq
.inq_dtype
;
2396 /* initialize inq status */
2397 newDevice
->inquiryFailed
= B_FALSE
;
2404 * Function we use to insert a newly discovered port.
2410 sas_rp_tree_insert(rp_tree_t
**rproot
,
2413 HBA_UINT8
*wwn1
, *wwn2
, *wwn3
;
2414 rp_tree_t
*node_ptr
;
2417 if (rproot
== NULL
) {
2418 (void *) fprintf(stderr
, "%s\n",
2419 gettext("Error: NULL rproot"));
2423 if (rpnode
== NULL
) {
2424 (void *) fprintf(stderr
, "%s\n",
2425 gettext("Error: NULL rpnode"));
2429 if (*rproot
== NULL
) {
2434 wwn1
= (*rproot
)->sasattr
.LocalSASAddress
.wwn
;
2435 wwn2
= (*rproot
)->sasattr
.AttachedSASAddress
.wwn
;
2436 wwn3
= rpnode
->sasattr
.AttachedSASAddress
.wwn
;
2439 * If the attched sas address is equal to the local sas address,
2440 * then this should be a child node of current root node.
2442 if (memcmp(wwn1
, wwn3
, sizeof (HBA_WWN
)) == 0) {
2443 (void) sas_rp_tree_insert(&(*rproot
)->child
, rpnode
);
2444 rpnode
->parent
= *rproot
;
2445 } else if (memcmp(wwn2
, wwn3
, sizeof (HBA_WWN
)) == 0) {
2447 * If the attached sas address is equal to the attached sas
2448 * address of current root node, then this should be a
2450 * Insert the SAS/SATA Device at the head of sibling list.
2452 if (rpnode
->portattr
.PortType
!= HBA_PORTTYPE_SASEXPANDER
) {
2453 rpnode
->sibling
= *rproot
;
2457 * Insert the SAS Expander at the tail of sibling
2461 while (node_ptr
->sibling
!= NULL
)
2462 node_ptr
= node_ptr
->sibling
;
2463 node_ptr
->sibling
= rpnode
;
2465 rpnode
->parent
= (*rproot
)->parent
;
2468 * If enter here, we should first try to insert the discovered
2469 * port node into the child sub-tree, then try to insert to the
2470 * sibling sub-trees. If we failed to insert the discovered
2471 * port node, return 1. The caller will queue this node
2472 * up and retry insertion later.
2474 if ((*rproot
)->child
) {
2475 ret
= sas_rp_tree_insert(&(*rproot
)->child
, rpnode
);
2477 if ((*rproot
)->child
== NULL
|| ret
!= 0) {
2478 if ((*rproot
)->sibling
) {
2479 ret
= sas_rp_tree_insert(&(*rproot
)->sibling
,
2490 * Function which will print out the whole disocvered port topology.
2491 * Here we use the Preorder Traversal algorithm.
2492 * The indentation rules are:
2493 * 1 * TABLEN - for attributes
2494 * 2 * TABLEN - for next tier target port/expander
2497 sas_rp_tree_print(HBA_HANDLE handle
, char *adapterName
,
2498 HBA_UINT32 portIndex
, SMHBA_PORTATTRIBUTES
*port
,
2499 rp_tree_t
*rpnode
, inputArg_t
*input
,
2500 int gident
, int *printPort
)
2502 int ret
= 0, lident
;
2509 * We assume that all the nodes are disocvered ports(sas device or
2512 if (input
->wwnCount
> 0) {
2513 /* Adjust local indentation if a discovered port specified. */
2514 lident
= 2 * TABLEN
;
2516 * Check whether current node match one of the specified
2519 if ((rpnode
->portattr
.PortType
!= HBA_PORTTYPE_SASEXPANDER
) ||
2520 !isPortWWNInArgv(input
,
2521 &rpnode
->sasattr
.LocalSASAddress
)) {
2523 * Step down to child tree first.
2525 ret
+= sas_rp_tree_print(handle
, adapterName
,
2526 portIndex
, port
, rpnode
->child
, input
,
2527 gident
+ 2 * TABLEN
, printPort
);
2529 * Then check the sibling tree.
2531 ret
+= sas_rp_tree_print(handle
, adapterName
,
2532 portIndex
, port
, rpnode
->sibling
, input
,
2538 if ((rpnode
->portattr
.PortType
== HBA_PORTTYPE_SASEXPANDER
) ||
2539 (input
->pflag
& PRINT_TARGET_PORT
)) {
2541 * We should print the header(HBA Name + HBA Port Name)
2542 * on-demand. It means that, if we have expander device
2543 * address specified on the command line, we should print
2544 * the header once we find a matching one. Or we will
2545 * print the header from the beginning of the output.
2547 if (g_printHBA
== 0) {
2548 (void *) fprintf(stdout
, "%s %s\n",
2549 "HBA Name:", adapterName
);
2553 if (*printPort
== 0) {
2554 (void *) fprintf(stdout
, "%s%s %s\n",
2555 getIndentSpaces(TABLEN
),
2556 "HBA Port Name:", port
->OSDeviceName
);
2559 ret
+= sas_print_rpnode(input
, rpnode
, lident
, gident
);
2563 * If operands provided with "-t" option specified, we will print
2564 * the immediate child nodes information under the expander.
2566 if (input
->pflag
& PRINT_TARGET_PORT
) {
2567 /* no operand. ignore the option. */
2568 if (input
->wwnCount
> 0) {
2569 if (rpnode
->portattr
.PortType
==
2570 HBA_PORTTYPE_SASEXPANDER
) {
2571 ret
+= sas_rp_tree_print_desc(handle
,
2572 portIndex
, port
, rpnode
->child
,
2574 lident
+ 2 * TABLEN
,
2575 gident
+ 2 * TABLEN
);
2581 * Here we use DFS(Depth First Search) algorithm to traverse the
2584 ret
+= sas_rp_tree_print(handle
, adapterName
,
2585 portIndex
, port
, rpnode
->child
, input
,
2586 gident
+ 2 * TABLEN
, printPort
);
2587 ret
+= sas_rp_tree_print(handle
, adapterName
,
2588 portIndex
, port
, rpnode
->sibling
, input
,
2594 * Function which will destroy the whole discovered port tree.
2595 * Here we use the Postorder Traversal algorithm.
2597 static void sas_rp_tree_free(rp_tree_t
*rproot
)
2599 tgt_mapping
*cur
, *next
;
2605 * Free child tree first.
2607 if (rproot
->child
) {
2608 sas_rp_tree_free(rproot
->child
);
2612 * Free sibling trees then.
2614 if (rproot
->sibling
) {
2615 sas_rp_tree_free(rproot
->sibling
);
2619 * Free root node at last.
2621 cur
= rproot
->first_entry
;
2622 while (cur
!= NULL
) {
2631 * Function used to print out all the descendant nodes.
2632 * handle - handle to HBA.
2633 * port - port attributes of current HBA port.
2634 * desc - the root node of a subtree which will be processed.
2635 * input - input argument.
2636 * lident - local indentation for shifting indentation.
2637 * gident - global indentation, can also be used to obtain Tier number.
2641 sas_rp_tree_print_desc(HBA_HANDLE handle
, HBA_UINT32 portIndex
,
2642 SMHBA_PORTATTRIBUTES
*port
, rp_tree_t
*desc
,
2643 inputArg_t
*input
, int lident
, int gident
)
2651 * Walk through the subtree of desc by Pre-Order Traversal Algo.
2653 for (rp_node
= desc
; rp_node
!= NULL
; rp_node
= rp_node
->sibling
) {
2654 ret
+= sas_print_rpnode(input
, rp_node
, lident
, gident
);
2661 * Function used to print the information of specified SAS address.
2662 * handle - handle to a HBA.
2663 * port - port attributes of a HBA port.
2664 * rpnode - discovered port which will be processed.
2665 * lident - local indentation used for shifting indentation.
2666 * gident - global indentation used for calculating "Tier" number.
2669 sas_print_rpnode(inputArg_t
*input
,
2670 rp_tree_t
*rpnode
, int lident
, int gident
)
2674 if (rpnode
->portattr
.PortType
== HBA_PORTTYPE_SASEXPANDER
) {
2675 (void *) fprintf(stdout
, "%s%s(Tier %d): %016llx\n",
2676 getIndentSpaces(lident
),
2677 "Expander SAS Address",
2678 gident
/ (2 * TABLEN
),
2679 wwnConversion(rpnode
->sasattr
.LocalSASAddress
.wwn
));
2681 (void *) fprintf(stdout
, "%s%s %016llx\n",
2682 getIndentSpaces(lident
),
2683 "Target Port SAS Address:",
2684 wwnConversion(rpnode
->sasattr
.LocalSASAddress
.wwn
));
2686 if (input
->pflag
& PRINT_VERBOSE
) {
2687 if (rpnode
->portattr
.PortType
!= HBA_PORTTYPE_SASEXPANDER
) {
2688 (void *) fprintf(stdout
, "%s%s %s\n",
2689 getIndentSpaces(TABLEN
+ lident
),
2691 getStateString(rpnode
->portattr
.PortType
,
2694 (void *) fprintf(stdout
, "%s%s %s\n",
2695 getIndentSpaces(TABLEN
+ lident
),
2697 rpnode
->portattr
.OSDeviceName
);
2698 (void *) fprintf(stdout
, "%s%s %s\n",
2699 getIndentSpaces(TABLEN
+ lident
),
2701 getStateString(rpnode
->portattr
.PortState
,
2705 rpnode
->printed
= 1;
2710 * Function used to get the correct domainPortWWN as needed by some of the
2712 * handle - handle to a HBA.
2713 * portIndex - index to locate the port.
2714 * port - pointer to the structure holding port attributes.
2715 * pdomainPort - pointer to the buffer holding domainPortWWN.
2718 get_domainPort(HBA_HANDLE handle
,
2719 int portIndex
, PSMHBA_PORTATTRIBUTES port
,
2720 HBA_WWN
*pdomainPort
)
2723 PSMHBA_SAS_PORT sasport
;
2724 SMHBA_SAS_PHY phyattr
;
2726 sasport
= port
->PortSpecificAttribute
.SASPort
;
2727 memset(pdomainPort
, 0, sizeof (HBA_WWN
));
2729 * Since iport can exist without any phys,
2730 * sasinfo hba-port -v has indicated numberOfPhys;
2731 * if there is no phys within the hba, just return OK.
2733 if (sasport
->NumberofPhys
> 0) {
2734 status
= SMHBA_GetSASPhyAttributes(handle
, portIndex
,
2736 if (status
!= HBA_STATUS_OK
)
2738 (void *) memcpy(pdomainPort
, &phyattr
.domainPortWWN
,
2741 /* return not supported for no phy configured */
2742 return (HBA_STATUS_ERROR_NOT_SUPPORTED
);
2744 return (HBA_STATUS_OK
);
2748 * Comparison function for comparing names possibly ending with digits.
2750 * <0 - name1 is less than name2.
2751 * 0 - name1 is equal with name2.
2752 * >0 - name1 is more than name2.
2755 sas_name_comp(const char *name1
, const char *name2
)
2762 while ((name1
[i
] == name2
[i
]) && (name1
[i
] != '\0'))
2765 /* If neither of name1[i] and name2[i] is '\0'. */
2766 if (isdigit(name1
[i
]) && isdigit(name2
[i
]))
2767 return (atoi(&name1
[i
]) - atoi(&name2
[i
]));
2769 /* One of name1[i] and name2[i] is not digit. */
2770 return (name1
[i
] - name2
[i
]);
2773 * Comparison function for sorting HBA/HBA Port.
2774 * arg1 - first argument of type sas_elem_t.
2775 * arg2 - second argument of type sas_elem_t.
2777 * <0 - arg1 is less than arg2.
2778 * 0 - arg1 is equal with arg2.
2779 * >0 - arg1 is more than arg2.
2782 sas_elem_compare(const void *arg1
, const void *arg2
)
2784 sas_elem_t
*p1
, *p2
;
2785 p1
= (sas_elem_t
*)arg1
;
2786 p2
= (sas_elem_t
*)arg2
;
2787 return (sas_name_comp(p1
->name
, p2
->name
));
2791 * Sorting function for HBA/HBA Port output.
2792 * array - elements array of type sas_elem_t.
2793 * nelem - number of elements in array of type sas_elem_t.
2796 sas_elem_sort(sas_elem_t
*array
, int nelem
)
2798 qsort((void *)array
, nelem
, sizeof (sas_elem_t
), sas_elem_compare
);