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