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