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