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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 28 #include <hbaapi.h> 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <ctype.h> 38 #include <sys/scsi/generic/sense.h> 39 #include <sys/scsi/generic/mode.h> 40 #include <sys/scsi/generic/inquiry.h> 41 #include <errno.h> 42 #include <libdevice.h> 43 #include <config_admin.h> 44 #include <sys/byteorder.h> 45 #include <sys/fibre-channel/fcio.h> 46 #include "common.h" 47 #include "sun_fc_version.h" 48 49 #define DEFAULT_LUN_COUNT 1024 50 #define LUN_SIZE 8 51 #define LUN_HEADER_SIZE 8 52 #define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \ 53 LUN_SIZE + \ 54 LUN_HEADER_SIZE 55 struct lun_val { 56 uchar_t val[8]; 57 }; 58 struct rep_luns_rsp { 59 uint32_t length; 60 uint32_t rsrvd; 61 struct lun_val lun[1]; 62 }; 63 64 /* Extracted from the old scsi.h file */ 65 struct capacity_data_struct { 66 uint_t last_block_addr; 67 uint_t block_size; 68 }; 69 70 71 /* Structure to handle the inq. page 0x80 serial number */ 72 struct page80 { 73 uchar_t inq_dtype; 74 uchar_t inq_page_code; 75 uchar_t reserved; 76 uchar_t inq_page_len; 77 uchar_t inq_serial[251]; 78 }; 79 80 extern char *dtype[]; 81 extern int Options; 82 extern const int OPTION_P; 83 84 int skip_hba(int i); 85 int find_supported_inq_page(HBA_HANDLE handle, HBA_WWN hwwn, HBA_WWN pwwn, 86 uint64_t lun, int page_num); 87 /* 88 * The routines within this file operate against the T11 89 * HBA API interface. In some cases, proprietary Sun driver 90 * interface are also called to add additional information 91 * above what the standard library supports. 92 */ 93 94 uint64_t 95 wwnConversion(uchar_t *wwn) { 96 uint64_t tmp; 97 (void) memcpy(&tmp, wwn, sizeof (uint64_t)); 98 return (ntohll(tmp)); 99 } 100 101 void printStatus(HBA_STATUS status) { 102 switch (status) { 103 case HBA_STATUS_OK: 104 printf(MSGSTR(2410, "OK")); 105 return; 106 case HBA_STATUS_ERROR: 107 printf(MSGSTR(2411, "ERROR")); 108 return; 109 case HBA_STATUS_ERROR_NOT_SUPPORTED: 110 printf(MSGSTR(2412, "NOT SUPPORTED")); 111 return; 112 case HBA_STATUS_ERROR_INVALID_HANDLE: 113 printf(MSGSTR(2413, "INVALID HANDLE")); 114 return; 115 case HBA_STATUS_ERROR_ARG: 116 printf(MSGSTR(2414, "ERROR ARG")); 117 return; 118 case HBA_STATUS_ERROR_ILLEGAL_WWN: 119 printf(MSGSTR(2415, "ILLEGAL WWN")); 120 return; 121 case HBA_STATUS_ERROR_ILLEGAL_INDEX: 122 printf(MSGSTR(2416, "ILLEGAL INDEX")); 123 return; 124 case HBA_STATUS_ERROR_MORE_DATA: 125 printf(MSGSTR(2417, "MORE DATA")); 126 return; 127 case HBA_STATUS_ERROR_STALE_DATA: 128 printf(MSGSTR(2418, "STALE DATA")); 129 return; 130 case HBA_STATUS_SCSI_CHECK_CONDITION: 131 printf(MSGSTR(2419, "SCSI CHECK CONDITION")); 132 return; 133 case HBA_STATUS_ERROR_BUSY: 134 printf(MSGSTR(2420, "BUSY")); 135 return; 136 case HBA_STATUS_ERROR_TRY_AGAIN: 137 printf(MSGSTR(2421, "TRY AGAIN")); 138 return; 139 case HBA_STATUS_ERROR_UNAVAILABLE: 140 printf(MSGSTR(2422, "UNAVAILABLE")); 141 return; 142 default: 143 printf(MSGSTR(2423, "UNKNOWN ERROR TYPE %d"), status); 144 return; 145 } 146 } 147 148 uint32_t 149 getNumberOfAdapters() { 150 uint32_t count = HBA_GetNumberOfAdapters(); 151 if (count == 0) { 152 fprintf(stderr, MSGSTR(2405, 153 "\nERROR: No Fibre Channel Adapters found.\n")); 154 } 155 return (count); 156 } 157 158 #define MAX_RETRIES 10 159 160 /* 161 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 162 * Will handle retries if applicable. 163 */ 164 int 165 getAdapterAttrs(HBA_HANDLE handle, char *name, HBA_ADAPTERATTRIBUTES *attrs) { 166 int count = 0; 167 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 168 169 /* Loop as long as we have a retryable error */ 170 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 171 status == HBA_STATUS_ERROR_BUSY) && count++ < MAX_RETRIES) { 172 status = HBA_GetAdapterAttributes(handle, attrs); 173 if (status == HBA_STATUS_OK) { 174 break; 175 } 176 (void) sleep(1); 177 } 178 if (status != HBA_STATUS_OK) { 179 /* We encountered a non-retryable error */ 180 fprintf(stderr, MSGSTR(2501, 181 "\nERROR: Unable to retrieve adapter port details (%s)"), 182 name); 183 printStatus(status); 184 fprintf(stderr, "\n"); 185 } 186 return (status); 187 } 188 189 /* 190 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 191 * Will handle retries if applicable. 192 */ 193 int 194 getAdapterPortAttrs(HBA_HANDLE handle, char *name, int portIndex, 195 HBA_PORTATTRIBUTES *attrs) { 196 int count = 0; 197 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 198 199 /* Loop as long as we have a retryable error */ 200 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 201 status == HBA_STATUS_ERROR_BUSY) && count++ < MAX_RETRIES) { 202 status = HBA_GetAdapterPortAttributes(handle, portIndex, attrs); 203 if (status == HBA_STATUS_OK) { 204 break; 205 } 206 207 /* The odds of this occuring are very slim, but possible. */ 208 if (status == HBA_STATUS_ERROR_STALE_DATA) { 209 /* 210 * If we hit a stale data scenario, 211 * we'll just tell the user to try again. 212 */ 213 status = HBA_STATUS_ERROR_TRY_AGAIN; 214 break; 215 } 216 sleep(1); 217 } 218 if (status != HBA_STATUS_OK) { 219 /* We encountered a non-retryable error */ 220 fprintf(stderr, MSGSTR(2501, 221 "\nERROR: Unable to retrieve adapter port details (%s)"), 222 name); 223 printStatus(status); 224 fprintf(stderr, "\n"); 225 } 226 return (status); 227 } 228 229 /* 230 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* 231 * Will handle retries if applicable. 232 */ 233 int 234 getDiscPortAttrs(HBA_HANDLE handle, char *name, int portIndex, int discIndex, 235 HBA_PORTATTRIBUTES *attrs) { 236 int count = 0; 237 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 238 239 /* Loop as long as we have a retryable error */ 240 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 241 status == HBA_STATUS_ERROR_BUSY) && count++ < MAX_RETRIES) { 242 status = HBA_GetDiscoveredPortAttributes(handle, portIndex, 243 discIndex, attrs); 244 if (status == HBA_STATUS_OK) { 245 break; 246 } 247 248 /* The odds of this occuring are very slim, but possible. */ 249 if (status == HBA_STATUS_ERROR_STALE_DATA) { 250 /* 251 * If we hit a stale data scenario, we'll just tell the 252 * user to try again. 253 */ 254 status = HBA_STATUS_ERROR_TRY_AGAIN; 255 break; 256 } 257 sleep(1); 258 } 259 if (status != HBA_STATUS_OK) { 260 /* We encountered a non-retryable error */ 261 fprintf(stderr, MSGSTR(2504, 262 "\nERROR: Unable to retrieve target port details (%s)"), 263 name); 264 printStatus(status); 265 fprintf(stderr, "\n"); 266 } 267 return (status); 268 } 269 270 271 /*ARGSUSED*/ 272 int 273 fchba_display_port(int verbose) 274 { 275 int retval = 0; 276 HBA_HANDLE handle; 277 HBA_ADAPTERATTRIBUTES hbaAttrs; 278 HBA_PORTATTRIBUTES portAttrs; 279 HBA_STATUS status; 280 int count, adapterIndex, portIndex; 281 char name[256]; 282 char *physical = NULL; 283 char path[MAXPATHLEN]; 284 285 if ((retval = loadLibrary())) { 286 return (retval); 287 } 288 289 count = getNumberOfAdapters(); 290 291 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 292 if (skip_hba(adapterIndex)) { 293 continue; 294 } 295 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 296 if (status != HBA_STATUS_OK) { 297 /* Just skip it, maybe it was DR'd */ 298 continue; 299 } 300 handle = HBA_OpenAdapter(name); 301 if (handle == 0) { 302 /* Just skip it, maybe it was DR'd */ 303 continue; 304 } 305 306 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 307 /* This should never happen, we'll just skip the adapter */ 308 HBA_CloseAdapter(handle); 309 continue; 310 } 311 312 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; 313 portIndex++) { 314 if (getAdapterPortAttrs(handle, name, portIndex, 315 &portAttrs)) { 316 continue; 317 } 318 physical = get_slash_devices_from_osDevName( 319 portAttrs.OSDeviceName, 320 STANDARD_DEVNAME_HANDLING); 321 if (physical) { 322 char *tmp = strstr(physical, ":fc"); 323 if (tmp) { 324 *tmp = '\0'; 325 (void) snprintf(path, MAXPATHLEN, "%s:devctl", 326 physical); 327 } else { 328 (void) snprintf(path, MAXPATHLEN, "%s", 329 physical); 330 } 331 free(physical); 332 physical = NULL; 333 (void) printf("%-65s ", path); 334 } else { 335 (void) printf("%-65s ", portAttrs.OSDeviceName); 336 } 337 if (portAttrs.NumberofDiscoveredPorts > 0) { 338 printf(MSGSTR(2233, "CONNECTED\n")); 339 } else { 340 printf(MSGSTR(2234, "NOT CONNECTED\n")); 341 } 342 } 343 } 344 (void) HBA_FreeLibrary(); 345 return (retval); 346 } 347 348 /* 349 * Internal routines/structure to deal with a path list 350 * so we can ensure uniqueness 351 */ 352 struct path_entry { 353 char path[MAXPATHLEN]; 354 HBA_UINT8 wwn[8]; 355 uchar_t dtype; 356 struct path_entry *next; 357 }; 358 void add_path(struct path_entry *head, struct path_entry *cur) { 359 struct path_entry *tmp; 360 for (tmp = head; tmp->next != NULL; tmp = tmp->next) { } 361 tmp->next = cur; 362 } 363 struct path_entry *is_duplicate_path(struct path_entry *head, char *path) { 364 struct path_entry *tmp; 365 for (tmp = head; tmp != NULL; tmp = tmp->next) { 366 if (strncmp(tmp->path, path, sizeof (tmp->path)) == 0) { 367 return (tmp); 368 } 369 } 370 return (NULL); 371 } 372 void free_path_list(struct path_entry *head) { 373 struct path_entry *tmp; 374 struct path_entry *tmp2; 375 for (tmp = head; tmp != NULL; ) { 376 tmp2 = tmp->next; 377 free(tmp); 378 tmp = tmp2; 379 } 380 } 381 382 383 int 384 is_wwn(char *arg) { 385 int i; 386 if (strlen(arg) == 16) { 387 for (i = 0; i < 16; i++) { 388 if (!isxdigit(arg[i])) { 389 return (0); 390 } 391 } 392 return (1); 393 } 394 return (0); 395 } 396 397 int 398 is_path(char *arg) { 399 struct stat buf; 400 if (stat(arg, &buf)) { 401 return (0); 402 } 403 return (1); 404 } 405 406 /* We take a wild guess for our first get target mappings call */ 407 #define MAP_GUESS 50 408 409 HBA_STATUS 410 fetch_mappings(HBA_HANDLE handle, HBA_WWN pwwn, HBA_FCPTARGETMAPPINGV2 **map) { 411 int loop = 0; 412 int count = 0; 413 HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ 414 *map = (HBA_FCPTARGETMAPPINGV2 *) calloc(1, 415 (sizeof (HBA_FCPSCSIENTRYV2)* (MAP_GUESS-1)) + 416 sizeof (HBA_FCPTARGETMAPPINGV2)); 417 418 /* Loop as long as we have a retryable error */ 419 while ((status == HBA_STATUS_ERROR_TRY_AGAIN || 420 status == HBA_STATUS_ERROR_BUSY || 421 status == HBA_STATUS_ERROR_MORE_DATA) && loop++ < MAX_RETRIES) { 422 status = HBA_GetFcpTargetMappingV2(handle, pwwn, *map); 423 if (status == HBA_STATUS_OK) { 424 break; 425 } else if (status == HBA_STATUS_ERROR_MORE_DATA) { 426 count = (*map)->NumberOfEntries; 427 free(*map); 428 *map = (HBA_FCPTARGETMAPPINGV2 *) calloc(1, 429 (sizeof (HBA_FCPSCSIENTRYV2)* (count-1)) + 430 sizeof (HBA_FCPTARGETMAPPINGV2)); 431 (*map)->NumberOfEntries = count; 432 continue; 433 } 434 sleep(1); 435 } 436 if (status != HBA_STATUS_OK) { 437 /* We encountered a non-retryable error */ 438 fprintf(stderr, MSGSTR(2502, 439 "\nERROR: Unable to retrieve SCSI device paths " 440 "(HBA Port WWN %016llx)"), 441 wwnConversion(pwwn.wwn)); 442 printStatus(status); 443 fprintf(stderr, "\n"); 444 } 445 return (status); 446 } 447 448 /* 449 * Returns the index of the first match, or -1 if no match 450 */ 451 int 452 match_mappings(char *compare, HBA_FCPTARGETMAPPINGV2 *map) { 453 int mapIndex; 454 char *physical = NULL; 455 char *tmp; 456 int wwnCompare = 0; 457 uint64_t wwn; 458 459 if (map == NULL || compare == NULL) { 460 return (-1); 461 } 462 463 if (is_wwn(compare)) { 464 wwnCompare = 1; 465 (void) sscanf(compare, "%016llx", &wwn); 466 } else { 467 /* Convert the paths to phsyical paths */ 468 physical = get_slash_devices_from_osDevName(compare, 469 STANDARD_DEVNAME_HANDLING); 470 } 471 472 for (mapIndex = 0; mapIndex < map->NumberOfEntries; mapIndex ++) { 473 if (wwnCompare) { 474 if (wwn == wwnConversion( 475 map->entry[mapIndex].FcpId.NodeWWN.wwn) || 476 wwn == wwnConversion( 477 map->entry[mapIndex].FcpId.PortWWN.wwn)) { 478 return (mapIndex); 479 } 480 } else { 481 if (physical != NULL) { 482 tmp = get_slash_devices_from_osDevName( 483 map->entry[mapIndex].ScsiId.OSDeviceName, 484 STANDARD_DEVNAME_HANDLING); 485 if ((tmp != NULL) && 486 strncmp(physical, tmp, MAXPATHLEN) == 0) { 487 free(physical); 488 return (mapIndex); 489 } 490 } 491 } 492 } 493 if (physical) { 494 free(physical); 495 } 496 return (-1); 497 } 498 499 500 /* 501 * returns non-zero on failure (aka HBA_STATUS_ERROR_* 502 */ 503 int 504 loadLibrary() { 505 int status = HBA_LoadLibrary(); 506 if (status != HBA_STATUS_OK) { 507 fprintf(stderr, MSGSTR(2505, 508 "ERROR: Unable to load HBA API library: ")); 509 printStatus(status); 510 fprintf(stderr, "\n"); 511 } 512 return (status); 513 } 514 515 int 516 fchba_non_encl_probe() { 517 HBA_HANDLE handle; 518 HBA_ADAPTERATTRIBUTES hbaAttrs; 519 HBA_PORTATTRIBUTES portAttrs; 520 HBA_FCPTARGETMAPPINGV2 *map; 521 HBA_STATUS status; 522 int count, adapterIndex, portIndex, mapIndex; 523 char name[256]; 524 struct path_entry *head = NULL; 525 uint64_t lun = 0; 526 L_inquiry inq; 527 struct scsi_extended_sense sense; 528 HBA_UINT8 scsiStatus; 529 uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); 530 531 if (loadLibrary()) { 532 return (-1); 533 } 534 535 count = getNumberOfAdapters(); 536 537 /* Loop over all HBAs */ 538 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 539 if (skip_hba(adapterIndex)) { 540 continue; 541 } 542 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 543 if (status != HBA_STATUS_OK) { 544 /* May have been DR'd */ 545 continue; 546 } 547 handle = HBA_OpenAdapter(name); 548 if (handle == 0) { 549 /* May have been DR'd */ 550 continue; 551 } 552 553 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 554 /* Should not happen, just skip it */ 555 HBA_CloseAdapter(handle); 556 continue; 557 } 558 559 560 /* Loop over all HBA Ports */ 561 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; 562 portIndex++) { 563 if (getAdapterPortAttrs(handle, name, portIndex, 564 &portAttrs)) { 565 continue; 566 } 567 568 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { 569 continue; 570 } 571 572 /* Loop over all target Mapping entries */ 573 for (mapIndex = 0; mapIndex < map->NumberOfEntries; 574 mapIndex ++) { 575 struct path_entry *tmpPath = NULL; 576 int doInquiry = 0; 577 if (!head) { 578 head = (struct path_entry *)calloc(1, 579 sizeof (struct path_entry)); 580 tmpPath = head; 581 strncpy(head->path, 582 map->entry[mapIndex].ScsiId.OSDeviceName, 583 sizeof (map->entry[mapIndex].ScsiId.OSDeviceName)); 584 (void) memcpy(tmpPath->wwn, 585 map->entry[mapIndex].FcpId.NodeWWN.wwn, 586 sizeof (HBA_UINT8) * 8); 587 doInquiry = 1; 588 } else if (tmpPath = is_duplicate_path(head, 589 map->entry[mapIndex].ScsiId.OSDeviceName)) { 590 if (tmpPath->dtype != 0x1f) { 591 doInquiry = 0; 592 } else { 593 doInquiry = 1; 594 } 595 } else { 596 tmpPath = (struct path_entry *) 597 calloc(1, sizeof (struct path_entry)); 598 strncpy(tmpPath->path, 599 map->entry[mapIndex].ScsiId.OSDeviceName, 600 sizeof (map->entry[mapIndex].ScsiId.OSDeviceName)); 601 (void) memcpy(tmpPath->wwn, 602 map->entry[mapIndex].FcpId.NodeWWN.wwn, 603 sizeof (HBA_UINT8) * 8); 604 add_path(head, tmpPath); 605 doInquiry = 1; 606 } 607 608 if (doInquiry) { 609 lun = map->entry[mapIndex].FcpId.FcpLun; 610 memset(&inq, 0, sizeof (inq)); 611 memset(&sense, 0, sizeof (sense)); 612 status = HBA_ScsiInquiryV2(handle, 613 portAttrs.PortWWN, 614 map->entry[mapIndex].FcpId.PortWWN, 615 lun, 0, 0, 616 &inq, &inquirySize, 617 &scsiStatus, 618 &sense, &senseSize); 619 if (status != HBA_STATUS_OK) { 620 inq.inq_dtype = 0x1f; 621 } 622 tmpPath->dtype = inq.inq_dtype; 623 } 624 } 625 } 626 } 627 if (head) { 628 struct path_entry *tmp; 629 printf(MSGSTR(2098, "\nFound Fibre Channel device(s):\n")); 630 for (tmp = head; tmp != NULL; tmp = tmp->next) { 631 printf(" "); 632 printf(MSGSTR(90, "Node WWN:")); 633 printf("%016llx ", wwnConversion(tmp->wwn)); 634 fprintf(stdout, MSGSTR(35, "Device Type:")); 635 (void) fflush(stdout); 636 637 if ((tmp->dtype & DTYPE_MASK) < 0x10) { 638 fprintf(stdout, "%s", 639 dtype[tmp->dtype & DTYPE_MASK]); 640 } else if ((tmp->dtype & DTYPE_MASK) < 0x1f) { 641 fprintf(stdout, MSGSTR(2406, 642 "Reserved")); 643 } else { 644 fprintf(stdout, MSGSTR(2407, 645 "Unknown")); 646 } 647 648 printf("\n "); 649 printf(MSGSTR(31, "Logical Path:%s"), tmp->path); 650 printf("\n"); 651 652 /* We probably shouldn't be using a g_fc interface here */ 653 if (Options & OPTION_P) { 654 char *phys_path = 655 get_slash_devices_from_osDevName( 656 tmp->path, 657 STANDARD_DEVNAME_HANDLING); 658 if (phys_path != NULL) { 659 fprintf(stdout, " "); 660 fprintf(stdout, MSGSTR(5, "Physical Path:")); 661 fprintf(stdout, "\n %s\n", phys_path); 662 free(phys_path); 663 } 664 } 665 } 666 free_path_list(head); 667 } 668 HBA_FreeLibrary(); 669 return (0); 670 } 671 672 673 int 674 fchba_inquiry(char **argv) 675 { 676 int path_index = 0, found = 0; 677 uint64_t wwn; 678 uint64_t lun = 0; 679 HBA_HANDLE handle; 680 HBA_ADAPTERATTRIBUTES hbaAttrs; 681 HBA_PORTATTRIBUTES portAttrs; 682 HBA_FCPTARGETMAPPINGV2 *map; 683 HBA_STATUS status; 684 int count, adapterIndex, portIndex, mapIndex; 685 char name[256]; 686 L_inquiry inq; 687 struct page80 serial; 688 uint32_t serialSize = sizeof (serial); 689 struct scsi_extended_sense sense; 690 HBA_UINT8 scsiStatus; 691 uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); 692 boolean_t goodPath = B_FALSE; 693 int matched = 0, wwnCompare = 0; 694 char *tmp, *physical = NULL; 695 int ret = 0; 696 697 if (loadLibrary()) { 698 return (-1); 699 } 700 for (path_index = 0; argv[path_index] != NULL; path_index++) { 701 goodPath = B_FALSE; 702 found = 0; 703 704 if (is_wwn(argv[path_index])) { 705 (void) sscanf(argv[path_index], "%016llx", &wwn); 706 wwnCompare = 1; 707 } else if (!is_path(argv[path_index])) { 708 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 709 argv[path_index]); 710 fprintf(stderr, "\n"); 711 ret = -1; 712 continue; 713 } 714 if (!wwnCompare) { 715 /* Convert the paths to phsyical paths */ 716 physical = get_slash_devices_from_osDevName(argv[path_index], 717 STANDARD_DEVNAME_HANDLING); 718 if (!physical) { 719 fprintf(stderr, MSGSTR(112, 720 "Error: Invalid pathname (%s)"), 721 argv[path_index]); 722 fprintf(stderr, "\n"); 723 ret = -1; 724 continue; 725 } 726 } 727 728 count = getNumberOfAdapters(); 729 730 /* Loop over all HBAs */ 731 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 732 if (skip_hba(adapterIndex)) { 733 continue; 734 } 735 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 736 if (status != HBA_STATUS_OK) { 737 /* May have been DR'd */ 738 continue; 739 } 740 handle = HBA_OpenAdapter(name); 741 if (handle == 0) { 742 /* May have been DR'd */ 743 continue; 744 } 745 746 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 747 /* Should never happen */ 748 HBA_CloseAdapter(handle); 749 continue; 750 } 751 752 753 /* Loop over all HBA Ports */ 754 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; 755 portIndex++) { 756 if (getAdapterPortAttrs(handle, name, portIndex, 757 &portAttrs)) { 758 continue; 759 } 760 761 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { 762 continue; 763 } 764 765 for (mapIndex = 0; mapIndex < map->NumberOfEntries; 766 mapIndex ++) { 767 matched = 0; 768 if (wwnCompare) { 769 if (wwn == wwnConversion( 770 map->entry[mapIndex].FcpId.NodeWWN.wwn) || 771 wwn == wwnConversion( 772 map->entry[mapIndex].FcpId.PortWWN.wwn)) { 773 lun = map->entry[mapIndex].FcpId.FcpLun; 774 matched = 1; 775 } 776 } else { 777 tmp = get_slash_devices_from_osDevName( 778 map->entry[mapIndex].ScsiId.OSDeviceName, 779 STANDARD_DEVNAME_HANDLING); 780 if ((tmp != NULL) && (strncmp(physical, tmp, 781 MAXPATHLEN) == 0)) { 782 lun = map->entry[mapIndex].FcpId.FcpLun; 783 matched = 1; 784 free(tmp); 785 } 786 } 787 788 if (matched) { 789 memset(&inq, 0, sizeof (inq)); 790 memset(&sense, 0, sizeof (sense)); 791 status = HBA_ScsiInquiryV2(handle, 792 portAttrs.PortWWN, 793 map->entry[mapIndex].FcpId.PortWWN, 794 lun, 0, 0, 795 &inq, &inquirySize, 796 &scsiStatus, 797 &sense, &senseSize); 798 if (status == HBA_STATUS_OK) { 799 goodPath = B_TRUE; 800 /* 801 * Call the inquiry cmd on page 0x80 only if 802 * the vendor supports page 0x80 803 */ 804 memset(&serial, 0, sizeof (serial)); 805 if ((find_supported_inq_page(handle, 806 portAttrs.PortWWN, 807 map->entry[mapIndex].FcpId.PortWWN, 808 lun, 0x80))) { 809 status = HBA_ScsiInquiryV2(handle, 810 portAttrs.PortWWN, 811 map->entry[mapIndex].FcpId.PortWWN, 812 lun, 1, 0x80, 813 &serial, &serialSize, 814 &scsiStatus, 815 &sense, &senseSize); 816 if (status != HBA_STATUS_OK) { 817 strncpy( 818 (char *)serial.inq_serial, 819 "Unavailable", 820 sizeof (serial.inq_serial)); 821 } 822 } else { 823 strncpy((char *)serial.inq_serial, 824 "Unsupported", 825 sizeof (serial.inq_serial)); 826 } 827 /* 828 * we are adding serial number information 829 * from 0x80. If length is less than 39, 830 * then we want to increase length to 52 to 831 * reflect the fact that we have serial number 832 * information 833 */ 834 if (inq.inq_len < 39) { 835 inq.inq_len = 52; 836 } 837 print_inq_data(argv[path_index], 838 map->entry[mapIndex].ScsiId.OSDeviceName, 839 inq, serial.inq_serial, 840 sizeof (serial.inq_serial)); 841 if (! wwnCompare) { 842 found = 1; 843 break; 844 } 845 } else { 846 fprintf(stderr, MSGSTR(2430, 847 "Error: I/O failure communicating with %s "), 848 map->entry[mapIndex].ScsiId.OSDeviceName); 849 printStatus(status); 850 fprintf(stderr, "\n"); 851 } 852 } 853 } 854 if (found == 1) { 855 break; 856 } 857 } 858 if (found == 1) { 859 break; 860 } 861 } 862 863 if (physical) { 864 free(physical); 865 } 866 867 if (!goodPath) { 868 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 869 argv[path_index]); 870 fprintf(stderr, "\n"); 871 ret = -1; 872 } 873 } 874 return (ret); 875 } 876 877 878 879 int 880 fchba_dump_map(char **argv) 881 { 882 int path_index = 0; 883 uint64_t wwn; 884 uint64_t lun = 0; 885 HBA_HANDLE handle; 886 HBA_ADAPTERATTRIBUTES hbaAttrs; 887 HBA_PORTATTRIBUTES portAttrs; 888 HBA_PORTATTRIBUTES discPortAttrs; 889 HBA_FCPTARGETMAPPINGV2 *map; 890 HBA_STATUS status; 891 int count, adapterIndex, portIndex, mapIndex, discIndex; 892 char name[256], *physical = NULL, *comp_phys = NULL; 893 L_inquiry inq; 894 struct scsi_extended_sense sense; 895 HBA_UINT8 scsiStatus; 896 int matched; 897 int done; 898 uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); 899 boolean_t goodPath = B_FALSE; 900 int ret = 0; 901 uint32_t responseSize = DEFAULT_LUN_LENGTH; 902 uchar_t raw_luns[DEFAULT_LUN_LENGTH]; 903 struct rep_luns_rsp *lun_resp; 904 905 906 if (loadLibrary()) { 907 return (-1); 908 } 909 for (path_index = 0; argv[path_index] != NULL; path_index++) { 910 goodPath = B_FALSE; 911 912 if (is_wwn(argv[path_index])) { 913 (void) sscanf(argv[path_index], "%016llx", &wwn); 914 } else if (!is_path(argv[path_index])) { 915 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 916 argv[path_index]); 917 fprintf(stderr, "\n"); 918 ret = -1; 919 continue; 920 } 921 922 count = getNumberOfAdapters(); 923 924 done = 0; 925 /* Loop over all HBAs */ 926 for (adapterIndex = 0; adapterIndex < count && !done; 927 adapterIndex ++) { 928 if (skip_hba(adapterIndex)) { 929 continue; 930 } 931 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 932 if (status != HBA_STATUS_OK) { 933 /* May have been DR'd */ 934 continue; 935 } 936 handle = HBA_OpenAdapter(name); 937 if (handle == 0) { 938 /* May have been DR'd */ 939 continue; 940 } 941 942 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 943 /* Should never happen */ 944 HBA_CloseAdapter(handle); 945 continue; 946 } 947 948 949 /* Loop over all HBA Ports */ 950 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts && !done; 951 portIndex++) { 952 if (getAdapterPortAttrs(handle, name, portIndex, 953 &portAttrs)) { 954 continue; 955 } 956 957 958 matched = 0; 959 if (is_wwn(argv[path_index])) { 960 if (wwn == wwnConversion( 961 portAttrs.NodeWWN.wwn) || 962 wwn == wwnConversion( 963 portAttrs.PortWWN.wwn)) { 964 matched = 1; 965 } 966 } else { 967 if (is_path(argv[path_index]) && 968 ((physical = get_slash_devices_from_osDevName( 969 argv[path_index], 970 STANDARD_DEVNAME_HANDLING)) != NULL) && 971 ((comp_phys = get_slash_devices_from_osDevName( 972 portAttrs.OSDeviceName, 973 STANDARD_DEVNAME_HANDLING)) != NULL)) { 974 char *tmp = strstr(physical, ":devctl"); 975 if (tmp) { 976 *tmp = '\0'; 977 } else { 978 tmp = strstr(physical, ":fc"); 979 if (tmp) { 980 *tmp = '\0'; 981 } 982 } 983 if (strstr(comp_phys, physical)) { 984 matched = 1; 985 } 986 } 987 if (physical) { 988 free(physical); 989 physical = NULL; 990 } 991 if (comp_phys) { 992 free(comp_phys); 993 comp_phys = NULL; 994 } 995 } 996 997 if (!fetch_mappings(handle, portAttrs.PortWWN, &map)) { 998 mapIndex = match_mappings(argv[path_index], map); 999 if (mapIndex >= 0) { 1000 matched = 1; 1001 } 1002 } else { 1003 continue; 1004 } 1005 1006 if (matched) { 1007 goodPath = B_TRUE; 1008 printf(MSGSTR(2095, 1009 "Pos Port_ID Hard_Addr Port WWN" 1010 " Node WWN Type\n")); 1011 for (discIndex = 0; 1012 discIndex < portAttrs.NumberofDiscoveredPorts; 1013 discIndex++) { 1014 if (getDiscPortAttrs(handle, name, portIndex, 1015 discIndex, &discPortAttrs)) { 1016 /* Move on to the next target */ 1017 continue; 1018 } 1019 1020 printf("%-4d %-6x %-6x %016llx %016llx", 1021 discIndex, 1022 discPortAttrs.PortFcId, 0, 1023 wwnConversion(discPortAttrs.PortWWN.wwn), 1024 wwnConversion(discPortAttrs.NodeWWN.wwn)); 1025 1026 /* 1027 * devices are not all required to respond to 1028 * Scsi Inquiry calls sent to LUN 0. We must 1029 * fisrt issue a ReportLUN and then send the 1030 * SCSI Inquiry call to the first LUN Returned 1031 * from the ReportLUN call 1032 */ 1033 memset(&sense, 0, sizeof (sense)); 1034 status = HBA_ScsiReportLUNsV2(handle, 1035 portAttrs.PortWWN, 1036 discPortAttrs.PortWWN, 1037 (void *)raw_luns, &responseSize, &scsiStatus, 1038 (void *)&sense, &senseSize); 1039 if (status == HBA_STATUS_OK) { 1040 lun_resp = 1041 (struct rep_luns_rsp *) 1042 (unsigned long)raw_luns; 1043 lun = ntohll( 1044 wwnConversion(lun_resp->lun[0].val)); 1045 } else { 1046 /* 1047 * in case we are unable to retrieve report 1048 * LUN data, we will blindly try sending the 1049 * INQUIRY to lun 0. 1050 */ 1051 lun = 0; 1052 } 1053 memset(&sense, 0, sizeof (sense)); 1054 status = HBA_ScsiInquiryV2(handle, 1055 portAttrs.PortWWN, 1056 discPortAttrs.PortWWN, 1057 lun, 0, 0, 1058 &inq, &inquirySize, 1059 &scsiStatus, 1060 &sense, &senseSize); 1061 if (status != HBA_STATUS_OK) { 1062 inq.inq_dtype = 0x1f; 1063 } 1064 print_fabric_dtype_prop(portAttrs.PortWWN.wwn, 1065 map->entry[mapIndex].FcpId.PortWWN.wwn, 1066 inq.inq_dtype); 1067 } 1068 /* Now dump this HBA's stats */ 1069 printf("%-4d %-6x %-6x %016llx %016llx", 1070 discIndex, 1071 portAttrs.PortFcId, 0, 1072 wwnConversion(portAttrs.PortWWN.wwn), 1073 wwnConversion(portAttrs.NodeWWN.wwn)); 1074 print_fabric_dtype_prop(portAttrs.PortWWN.wwn, 1075 portAttrs.PortWWN.wwn, 0x1f); 1076 done = 1; 1077 } 1078 } 1079 } 1080 if (!goodPath) { 1081 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 1082 argv[path_index]); 1083 fprintf(stderr, "\n"); 1084 ret = -1; 1085 } 1086 } 1087 return (ret); 1088 } 1089 1090 int 1091 fchba_display_link_status(char **argv) 1092 { 1093 int path_index = 0; 1094 uint64_t wwn; 1095 HBA_HANDLE handle; 1096 HBA_ADAPTERATTRIBUTES hbaAttrs; 1097 HBA_PORTATTRIBUTES portAttrs; 1098 HBA_PORTATTRIBUTES discPortAttrs; 1099 HBA_FCPTARGETMAPPINGV2 *map; 1100 HBA_STATUS status; 1101 int count, adapterIndex, portIndex, discIndex; 1102 char name[256], *physical = NULL, *comp_phys = NULL; 1103 int matched; 1104 struct fc_rls_acc_params rls; 1105 uint32_t rls_size = sizeof (rls); 1106 boolean_t goodPath = B_FALSE; 1107 int ret = 0; 1108 1109 if (loadLibrary()) { 1110 return (-1); 1111 } 1112 for (path_index = 0; argv[path_index] != NULL; path_index++) { 1113 goodPath = B_FALSE; 1114 1115 if (is_wwn(argv[path_index])) { 1116 (void) sscanf(argv[path_index], "%016llx", &wwn); 1117 } else if (!is_path(argv[path_index])) { 1118 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 1119 argv[path_index]); 1120 fprintf(stderr, "\n"); 1121 ret = -1; 1122 continue; 1123 } 1124 1125 count = getNumberOfAdapters(); 1126 1127 /* Loop over all HBAs */ 1128 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 1129 if (skip_hba(adapterIndex)) { 1130 continue; 1131 } 1132 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 1133 if (status != HBA_STATUS_OK) { 1134 /* May have been DR'd */ 1135 continue; 1136 } 1137 handle = HBA_OpenAdapter(name); 1138 if (handle == 0) { 1139 /* May have been DR'd */ 1140 continue; 1141 } 1142 1143 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 1144 /* Should never happen */ 1145 HBA_CloseAdapter(handle); 1146 continue; 1147 } 1148 1149 1150 /* Loop over all HBA Ports */ 1151 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; 1152 portIndex++) { 1153 if (getAdapterPortAttrs(handle, name, portIndex, 1154 &portAttrs)) { 1155 continue; 1156 } 1157 1158 matched = 0; 1159 if (is_wwn(argv[path_index])) { 1160 if (wwn == wwnConversion( 1161 portAttrs.NodeWWN.wwn) || 1162 wwn == wwnConversion( 1163 portAttrs.PortWWN.wwn)) { 1164 matched = 1; 1165 } 1166 } else { 1167 if (is_path(argv[path_index]) && 1168 ((physical = get_slash_devices_from_osDevName( 1169 argv[path_index], 1170 STANDARD_DEVNAME_HANDLING)) != NULL) && 1171 ((comp_phys = get_slash_devices_from_osDevName( 1172 portAttrs.OSDeviceName, 1173 STANDARD_DEVNAME_HANDLING)) != NULL)) { 1174 char *tmp = strstr(physical, ":devctl"); 1175 if (tmp) { 1176 *tmp = '\0'; 1177 } else { 1178 tmp = strstr(physical, ":fc"); 1179 if (tmp) { 1180 *tmp = '\0'; 1181 } 1182 } 1183 if (strstr(comp_phys, physical)) { 1184 matched = 1; 1185 } 1186 } 1187 if (physical) { 1188 free(physical); 1189 physical = NULL; 1190 } 1191 if (comp_phys) { 1192 free(comp_phys); 1193 comp_phys = NULL; 1194 } 1195 } 1196 1197 if (!matched) { 1198 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { 1199 continue; 1200 } 1201 } 1202 1203 if (matched || match_mappings(argv[path_index], map) >= 0) { 1204 goodPath = B_TRUE; 1205 fprintf(stdout, 1206 MSGSTR(2007, "\nLink Error Status " 1207 "information for loop:%s\n"), argv[path_index]); 1208 fprintf(stdout, MSGSTR(2008, "al_pa lnk fail " 1209 " sync loss signal loss sequence err" 1210 " invalid word CRC\n")); 1211 1212 for (discIndex = 0; 1213 discIndex < portAttrs.NumberofDiscoveredPorts; 1214 discIndex++) { 1215 1216 1217 if (getDiscPortAttrs(handle, name, portIndex, 1218 discIndex, &discPortAttrs)) { 1219 continue; 1220 } 1221 1222 status = HBA_SendRLS(handle, portAttrs.PortWWN, 1223 discPortAttrs.PortWWN, 1224 &rls, &rls_size); 1225 if (status != HBA_STATUS_OK) { 1226 memset(&rls, 0xff, sizeof (rls)); 1227 } 1228 1229 if ((rls.rls_link_fail == 0xffffffff) && 1230 (rls.rls_sync_loss == 0xffffffff) && 1231 (rls.rls_sig_loss == 0xffffffff) && 1232 (rls.rls_prim_seq_err == 0xffffffff) && 1233 (rls.rls_invalid_word == 0xffffffff) && 1234 (rls.rls_invalid_crc == 0xffffffff)) { 1235 fprintf(stdout, 1236 "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n", 1237 discPortAttrs.PortFcId, 1238 rls.rls_link_fail, 1239 rls.rls_sync_loss, 1240 rls.rls_sig_loss, 1241 rls.rls_prim_seq_err, 1242 rls.rls_invalid_word, 1243 rls.rls_invalid_crc); 1244 } else { 1245 fprintf(stdout, 1246 "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n", 1247 discPortAttrs.PortFcId, 1248 rls.rls_link_fail, 1249 rls.rls_sync_loss, 1250 rls.rls_sig_loss, 1251 rls.rls_prim_seq_err, 1252 rls.rls_invalid_word, 1253 rls.rls_invalid_crc); 1254 } 1255 1256 1257 } 1258 /* Now dump this HBA's stats */ 1259 status = HBA_SendRLS(handle, portAttrs.PortWWN, 1260 portAttrs.PortWWN, 1261 &rls, &rls_size); 1262 if (status != HBA_STATUS_OK) { 1263 memset(&rls, 0xff, sizeof (rls)); 1264 } 1265 1266 if ((rls.rls_link_fail == 0xffffffff) && 1267 (rls.rls_sync_loss == 0xffffffff) && 1268 (rls.rls_sig_loss == 0xffffffff) && 1269 (rls.rls_prim_seq_err == 0xffffffff) && 1270 (rls.rls_invalid_word == 0xffffffff) && 1271 (rls.rls_invalid_crc == 0xffffffff)) { 1272 fprintf(stdout, 1273 "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n", 1274 portAttrs.PortFcId, 1275 rls.rls_link_fail, 1276 rls.rls_sync_loss, 1277 rls.rls_sig_loss, 1278 rls.rls_prim_seq_err, 1279 rls.rls_invalid_word, 1280 rls.rls_invalid_crc); 1281 } else { 1282 fprintf(stdout, 1283 "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n", 1284 portAttrs.PortFcId, 1285 rls.rls_link_fail, 1286 rls.rls_sync_loss, 1287 rls.rls_sig_loss, 1288 rls.rls_prim_seq_err, 1289 rls.rls_invalid_word, 1290 rls.rls_invalid_crc); 1291 } 1292 } 1293 } 1294 } 1295 if (!goodPath) { 1296 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 1297 argv[path_index]); 1298 fprintf(stderr, "\n"); 1299 ret = -1; 1300 } 1301 } 1302 (void) fprintf(stdout, 1303 MSGSTR(2009, "NOTE: These LESB counts are not" 1304 " cleared by a reset, only power cycles.\n" 1305 "These counts must be compared" 1306 " to previously read counts.\n")); 1307 return (ret); 1308 } 1309 1310 typedef struct _PathInformation { 1311 char pathClass[MAXPATHLEN]; 1312 char pathState[MAXPATHLEN]; 1313 int32_t pathInfoState; 1314 int32_t pathInfoExternalState; 1315 } PathInformation; 1316 1317 struct lun_tracking { 1318 HBA_FCPSCSIENTRYV2 map; 1319 HBA_WWN hba_pwwn; 1320 char hba_path[MAXPATHLEN]; 1321 PathInformation info; 1322 1323 /* Points to another lun_tracking instance with the same map->LUID */ 1324 struct lun_tracking *next_path; 1325 1326 /* Points to next lun_tracking with a different map->LUID */ 1327 struct lun_tracking *next_lun; 1328 }; 1329 1330 1331 static const char VHCI_COMPONENT[] = "scsi_vhci"; 1332 static void 1333 scsi_vhci_details(struct lun_tracking *lun) 1334 { 1335 HBA_FCPSCSIENTRYV2 entry = lun->map; 1336 int retval = 0; 1337 int pathcnt, i, count, found = 0; 1338 char temppath[MAXPATHLEN]; 1339 char buf[MAXPATHLEN]; 1340 char *path_state[5]; 1341 1342 char *phys_path = get_slash_devices_from_osDevName( 1343 entry.ScsiId.OSDeviceName, 1344 STANDARD_DEVNAME_HANDLING); 1345 char *devPath = NULL; 1346 char *trailingCruft = NULL; 1347 char devaddr[MAXPATHLEN]; 1348 sv_iocdata_t ioc; 1349 int prop_buf_size = SV_PROP_MAX_BUF_SIZE; 1350 char *path_class_val = NULL; 1351 char client_path[MAXPATHLEN]; 1352 char phci_path[MAXPATHLEN]; 1353 1354 /* Only proceed if we are an mpxio path */ 1355 if (phys_path == NULL || strstr(phys_path, VHCI_COMPONENT) == NULL) { 1356 return; 1357 } 1358 1359 path_state[0] = MSGSTR(2400, "INIT"); 1360 path_state[1] = MSGSTR(2401, "ONLINE"); 1361 path_state[2] = MSGSTR(2402, "STANDBY"); 1362 path_state[3] = MSGSTR(2403, "FAULT"); 1363 path_state[4] = MSGSTR(2404, "OFFLINE"); 1364 1365 sprintf(devaddr, "%016llx,%x", wwnConversion( 1366 entry.FcpId.PortWWN.wwn), 1367 entry.ScsiId.ScsiOSLun); 1368 1369 /* First get the controller path */ 1370 sprintf(temppath, "/dev/cfg/c%d", entry.ScsiId.ScsiBusNumber); 1371 if ((count = readlink(temppath, buf, sizeof (buf)))) { 1372 buf[count] = '\0'; 1373 /* Now skip over the leading "../.." */ 1374 devPath = strstr(buf, "/devices/"); 1375 if (devPath == NULL) { 1376 strcpy(lun->info.pathClass, "Unavailable"); 1377 strcpy(lun->info.pathState, "Unavailable"); 1378 free(phys_path); 1379 return; 1380 } 1381 1382 /* Now chop off the trailing ":xxx" portion if present */ 1383 trailingCruft = strrchr(buf, ':'); 1384 if (trailingCruft) { 1385 trailingCruft[0] = '\0'; 1386 } 1387 } else { 1388 strcpy(lun->info.pathClass, "Unavailable"); 1389 strcpy(lun->info.pathState, "Unavailable"); 1390 free(phys_path); 1391 return; 1392 } 1393 1394 ioc.client = client_path; 1395 ioc.phci = phci_path; 1396 1397 retval = get_scsi_vhci_pathinfo(phys_path, &ioc, &pathcnt); 1398 if (retval != 0) { 1399 print_errString(retval, NULL); 1400 exit(-1); 1401 } 1402 1403 for (i = 0; i < pathcnt; i++) { 1404 nvlist_t *nvl; 1405 if (strstr(devPath, ioc.ret_buf[i].device.ret_phci)) { 1406 /* This could break someday if MPxIO changes devaddr */ 1407 if (strstr(ioc.ret_buf[i].ret_addr, devaddr)) { 1408 retval = nvlist_unpack(ioc.ret_buf[i].ret_prop.buf, 1409 prop_buf_size, &nvl, 0); 1410 if (retval != 0) { 1411 strcpy(lun->info.pathClass, 1412 "UNKNOWN PROB"); 1413 } else { 1414 strcpy(lun->info.pathState, 1415 path_state[ioc.ret_buf[i].ret_state]); 1416 lun->info.pathInfoState = ioc.ret_buf[i].ret_state; 1417 lun->info.pathInfoExternalState = 1418 ioc.ret_buf[i].ret_ext_state; 1419 if (nvlist_lookup_string(nvl, "path-class", 1420 &path_class_val) == 0) { 1421 strcpy(lun->info.pathClass, path_class_val); 1422 } else { 1423 strcpy(lun->info.pathClass, "UNKNOWN"); 1424 } 1425 } 1426 nvlist_free(nvl); 1427 found++; 1428 break; 1429 } 1430 } 1431 1432 } 1433 1434 if (!found) { 1435 strcpy(lun->info.pathClass, "Unavailable"); 1436 strcpy(lun->info.pathState, "Unavailable"); 1437 } 1438 free(phys_path); 1439 1440 /* free everything we alloced */ 1441 for (i = 0; i < ioc.buf_elem; i++) { 1442 free(ioc.ret_buf[i].ret_prop.buf); 1443 free(ioc.ret_buf[i].ret_prop.ret_buf_size); 1444 } 1445 free(ioc.ret_buf); 1446 1447 } 1448 1449 /* Utility routine to add new entries to the list (ignores dups) */ 1450 static void 1451 add_lun_path(struct lun_tracking *head, HBA_FCPSCSIENTRYV2 *map, 1452 HBA_WWN pwwn, char *path) 1453 { 1454 struct lun_tracking *tmp = NULL, *cmp = NULL; 1455 1456 for (tmp = head; tmp != NULL; tmp = tmp->next_lun) { 1457 if (memcmp(&tmp->map.LUID, &map->LUID, 1458 sizeof (HBA_LUID)) == 0) { 1459 1460 /* Ensure this isn't a duplicate */ 1461 for (cmp = tmp; cmp->next_path != NULL; 1462 cmp = cmp->next_path) { 1463 if (memcmp(&cmp->map, map, sizeof (cmp->map)) == 0) { 1464 return; 1465 } 1466 } 1467 if (memcmp(&cmp->map, map, sizeof (cmp->map)) == 0) { 1468 return; 1469 } 1470 1471 /* We have a new entry to add */ 1472 cmp->next_path = (struct lun_tracking *)calloc(1, 1473 sizeof (struct lun_tracking)); 1474 cmp = cmp->next_path; 1475 (void) memcpy(&cmp->map, map, 1476 sizeof (cmp->map)); 1477 (void) memcpy(&cmp->hba_pwwn, &pwwn, 1478 sizeof (cmp->hba_pwwn)); 1479 (void) snprintf(cmp->hba_path, MAXPATHLEN, 1480 path); 1481 scsi_vhci_details(cmp); 1482 return; 1483 } 1484 } 1485 /* Append a new LUN at the end of the list */ 1486 for (tmp = head; tmp->next_lun != NULL; tmp = tmp->next_lun) {} 1487 tmp->next_lun = (struct lun_tracking *)calloc(1, 1488 sizeof (struct lun_tracking)); 1489 tmp = tmp->next_lun; 1490 (void) memcpy(&tmp->map, map, 1491 sizeof (tmp->map)); 1492 (void) memcpy(&tmp->hba_pwwn, &pwwn, 1493 sizeof (tmp->hba_pwwn)); 1494 (void) snprintf(tmp->hba_path, MAXPATHLEN, 1495 path); 1496 scsi_vhci_details(tmp); 1497 } 1498 1499 /*ARGSUSED*/ 1500 int 1501 fchba_display_config(char **argv, int option_t_input, int argc) 1502 { 1503 int path_index = 0; 1504 uint64_t wwn; 1505 uint64_t lun = 0; 1506 HBA_HANDLE handle; 1507 HBA_ADAPTERATTRIBUTES hbaAttrs; 1508 HBA_PORTATTRIBUTES portAttrs; 1509 HBA_FCPTARGETMAPPINGV2 *map; 1510 HBA_STATUS status; 1511 int count, adapterIndex, portIndex; 1512 char name[256]; 1513 L_inquiry inq; 1514 struct scsi_extended_sense sense; 1515 struct page80 serial; 1516 HBA_UINT8 scsiStatus; 1517 uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); 1518 uint32_t serialSize = sizeof (serial); 1519 struct mode_page *pg_hdr; 1520 uchar_t *pg_buf; 1521 float lunMbytes; 1522 struct capacity_data_struct cap_data; 1523 uint32_t cap_data_size = sizeof (cap_data); 1524 struct mode_header_g1 *mode_header_ptr; 1525 int offset; 1526 char *phys_path = NULL; 1527 int mpxio = 0; 1528 int wwnCompare = 0; 1529 char *physical = NULL; 1530 struct lun_tracking *head = NULL; 1531 boolean_t goodPath = B_FALSE; 1532 int ret = 0; 1533 1534 1535 1536 if ((status = loadLibrary())) { 1537 return (-1); 1538 } 1539 for (path_index = 0; argv[path_index] != NULL; path_index++) { 1540 goodPath = B_FALSE; 1541 1542 if (is_wwn(argv[path_index])) { 1543 (void) sscanf(argv[path_index], "%016llx", &wwn); 1544 wwnCompare = 1; 1545 } else if (!is_path(argv[path_index])) { 1546 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 1547 argv[path_index]); 1548 fprintf(stderr, "\n"); 1549 ret = -1; 1550 continue; 1551 } 1552 if (!wwnCompare) { 1553 /* Convert the paths to phsyical paths */ 1554 physical = get_slash_devices_from_osDevName(argv[path_index], 1555 STANDARD_DEVNAME_HANDLING); 1556 if (!physical) { 1557 fprintf(stderr, MSGSTR(112, 1558 "Error: Invalid pathname (%s)"), 1559 argv[path_index]); 1560 fprintf(stderr, "\n"); 1561 ret = -1; 1562 continue; 1563 } 1564 } 1565 1566 count = getNumberOfAdapters(); 1567 1568 1569 /* 1570 * We have to loop twice to ensure we don't miss any 1571 * extra paths for other targets in a multi-target device 1572 */ 1573 1574 /* First check WWN/path comparisons */ 1575 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 1576 if (skip_hba(adapterIndex)) { 1577 continue; 1578 } 1579 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 1580 if (status != HBA_STATUS_OK) { 1581 /* May have been DR'd */ 1582 continue; 1583 } 1584 handle = HBA_OpenAdapter(name); 1585 if (handle == 0) { 1586 /* May have been DR'd */ 1587 continue; 1588 } 1589 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 1590 /* Should never happen */ 1591 HBA_CloseAdapter(handle); 1592 continue; 1593 } 1594 1595 /* Loop over all HBA Ports */ 1596 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; 1597 portIndex++) { 1598 int matched = 0; 1599 int mapIndex; 1600 char *tmp; 1601 if (getAdapterPortAttrs(handle, name, portIndex, 1602 &portAttrs)) { 1603 continue; 1604 } 1605 1606 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { 1607 continue; 1608 } 1609 1610 1611 1612 for (mapIndex = 0; mapIndex < map->NumberOfEntries; 1613 mapIndex ++) { 1614 matched = 0; 1615 if (wwnCompare) { 1616 if (wwn == wwnConversion( 1617 map->entry[mapIndex].FcpId.NodeWWN.wwn) || 1618 wwn == wwnConversion( 1619 map->entry[mapIndex].FcpId.PortWWN.wwn)) { 1620 matched = 1; 1621 } 1622 } else { 1623 tmp = get_slash_devices_from_osDevName( 1624 map->entry[mapIndex].ScsiId.OSDeviceName, 1625 STANDARD_DEVNAME_HANDLING); 1626 if ((tmp != NULL) && (strncmp(physical, tmp, 1627 MAXPATHLEN) == 0)) { 1628 matched = 1; 1629 free(tmp); 1630 } 1631 } 1632 if (matched && head == NULL) { 1633 goodPath = B_TRUE; 1634 head = (struct lun_tracking *)calloc(1, 1635 sizeof (struct lun_tracking)); 1636 (void) memcpy(&head->map, &map->entry[mapIndex], 1637 sizeof (head->map)); 1638 (void) memcpy(&head->hba_pwwn, &portAttrs.PortWWN, 1639 sizeof (head->hba_pwwn)); 1640 (void) snprintf(head->hba_path, MAXPATHLEN, 1641 portAttrs.OSDeviceName); 1642 scsi_vhci_details(head); 1643 } else if (matched) { 1644 goodPath = B_TRUE; 1645 add_lun_path(head, &map->entry[mapIndex], 1646 portAttrs.PortWWN, portAttrs.OSDeviceName); 1647 } 1648 } 1649 } 1650 } 1651 1652 if (physical) { 1653 free(physical); 1654 } 1655 1656 /* Now do it again and look for matching LUIDs (aka GUIDs) */ 1657 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { 1658 if (skip_hba(adapterIndex)) { 1659 continue; 1660 } 1661 status = HBA_GetAdapterName(adapterIndex, (char *)&name); 1662 if (status != HBA_STATUS_OK) { 1663 /* May have been DR'd */ 1664 continue; 1665 } 1666 handle = HBA_OpenAdapter(name); 1667 if (handle == 0) { 1668 /* May have been DR'd */ 1669 continue; 1670 } 1671 1672 if (getAdapterAttrs(handle, name, &hbaAttrs)) { 1673 /* Should never happen */ 1674 HBA_CloseAdapter(handle); 1675 continue; 1676 } 1677 1678 1679 /* Loop over all HBA Ports */ 1680 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; 1681 portIndex++) { 1682 int matched = 0; 1683 int mapIndex; 1684 if (getAdapterPortAttrs(handle, name, portIndex, 1685 &portAttrs)) { 1686 continue; 1687 } 1688 1689 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { 1690 continue; 1691 } 1692 1693 1694 for (mapIndex = 0; mapIndex < map->NumberOfEntries; 1695 mapIndex ++) { 1696 struct lun_tracking *outer; 1697 matched = 0; 1698 for (outer = head; outer != NULL; 1699 outer = outer->next_lun) { 1700 struct lun_tracking *inner; 1701 for (inner = outer; inner != NULL; 1702 inner = inner->next_path) { 1703 if (memcmp(&inner->map.LUID, 1704 &map->entry[mapIndex].LUID, 1705 sizeof (HBA_LUID)) == 0) { 1706 matched = 1; 1707 break; 1708 } 1709 } 1710 if (matched) { 1711 break; 1712 } 1713 } 1714 if (matched && head == NULL) { 1715 goodPath = B_TRUE; 1716 head = (struct lun_tracking *)calloc(1, 1717 sizeof (struct lun_tracking)); 1718 (void) memcpy(&head->map, &map->entry[mapIndex], 1719 sizeof (head->map)); 1720 (void) memcpy(&head->hba_pwwn, &portAttrs.PortWWN, 1721 sizeof (head->hba_pwwn)); 1722 (void) snprintf(head->hba_path, MAXPATHLEN, 1723 portAttrs.OSDeviceName); 1724 scsi_vhci_details(head); 1725 } else if (matched) { 1726 goodPath = B_TRUE; 1727 add_lun_path(head, &map->entry[mapIndex], 1728 portAttrs.PortWWN, portAttrs.OSDeviceName); 1729 } 1730 } 1731 } 1732 } 1733 if (!goodPath) { 1734 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), 1735 argv[path_index]); 1736 fprintf(stderr, "\n"); 1737 ret = -1; 1738 /* Just bomb out instead of going on */ 1739 return (ret); 1740 } 1741 } 1742 1743 /* Now display all the LUNs that we found that matched */ 1744 { 1745 struct lun_tracking *first_time; 1746 struct lun_tracking *tmp_path; 1747 for (first_time = head; first_time != NULL; 1748 first_time = first_time->next_lun) { 1749 struct lun_tracking *path; 1750 phys_path = get_slash_devices_from_osDevName( 1751 first_time->map.ScsiId.OSDeviceName, 1752 STANDARD_DEVNAME_HANDLING); 1753 /* Change behavior if this is an MPxIO device */ 1754 if (phys_path != NULL) { 1755 if (strstr(phys_path, VHCI_COMPONENT) != NULL) { 1756 mpxio = 1; 1757 } 1758 } 1759 1760 for (tmp_path = first_time; tmp_path != NULL; 1761 tmp_path = tmp_path->next_path) { 1762 if (mpxio && (strncmp(tmp_path->info.pathState, 1763 "ONLINE", strlen(tmp_path->info.pathState)))) { 1764 /* continue to next online path */ 1765 continue; 1766 } 1767 status = HBA_OpenAdapterByWWN(&handle, 1768 tmp_path->hba_pwwn); 1769 if (status != HBA_STATUS_OK) { 1770 fprintf(stderr, MSGSTR(2431, 1771 "Error: Failed to get handle for %s "), 1772 tmp_path->hba_path); 1773 printStatus(status); 1774 fprintf(stderr, "\n"); 1775 /* continue to next path */ 1776 continue; 1777 } 1778 1779 lun = tmp_path->map.FcpId.FcpLun; 1780 memset(&inq, 0, sizeof (inq)); 1781 memset(&sense, 0, sizeof (sense)); 1782 1783 status = HBA_ScsiInquiryV2(handle, 1784 tmp_path->hba_pwwn, 1785 tmp_path->map.FcpId.PortWWN, 1786 lun, 0, 0, 1787 &inq, &inquirySize, 1788 &scsiStatus, 1789 &sense, &senseSize); 1790 1791 if (status == HBA_STATUS_OK) { 1792 break; 1793 } 1794 HBA_CloseAdapter(handle); 1795 } 1796 1797 if (tmp_path == NULL) { 1798 fprintf(stderr, MSGSTR(2430, 1799 "Error: I/O failure communicating with %s "), 1800 first_time->map.ScsiId.OSDeviceName); 1801 printStatus(status); 1802 fprintf(stderr, "\n"); 1803 continue; 1804 } 1805 1806 switch ((inq.inq_dtype & DTYPE_MASK)) { 1807 case DTYPE_DIRECT: 1808 fprintf(stdout, MSGSTR(121, 1809 "DEVICE PROPERTIES for disk: %s\n"), 1810 first_time->map.ScsiId.OSDeviceName); 1811 break; 1812 case DTYPE_SEQUENTIAL: /* Tape */ 1813 fprintf(stdout, MSGSTR(2249, 1814 "DEVICE PROPERTIES for tape: %s\n"), 1815 first_time->map.ScsiId.OSDeviceName); 1816 break; 1817 default: 1818 fprintf(stdout, MSGSTR(2250, 1819 "DEVICE PROPERTIES for: %s\n"), 1820 first_time->map.ScsiId.OSDeviceName); 1821 break; 1822 } 1823 fprintf(stdout, " "); 1824 fprintf(stdout, MSGSTR(3, "Vendor:")); 1825 fprintf(stdout, "\t\t"); 1826 print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); 1827 fprintf(stdout, MSGSTR(2115, "\n Product ID:\t\t")); 1828 print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); 1829 1830 fprintf(stdout, "\n "); 1831 fprintf(stdout, MSGSTR(2119, "Revision:")); 1832 fprintf(stdout, "\t\t"); 1833 print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); 1834 1835 fprintf(stdout, "\n "); 1836 fprintf(stdout, MSGSTR(17, "Serial Num:")); 1837 fprintf(stdout, "\t\t"); 1838 (void) fflush(stdout); 1839 /* 1840 * Call the inquiry cmd on page 0x80 only if the vendor 1841 * supports page 0x80. 1842 */ 1843 if ((find_supported_inq_page(handle, first_time->hba_pwwn, 1844 first_time->map.FcpId.PortWWN, lun, 0x80))) { 1845 memset(&serial, 0, sizeof (serial)); 1846 status = HBA_ScsiInquiryV2(handle, 1847 first_time->hba_pwwn, 1848 first_time->map.FcpId.PortWWN, 1849 lun, 1, 0x80, 1850 &serial, &serialSize, 1851 &scsiStatus, 1852 &sense, &senseSize); 1853 if (status == HBA_STATUS_OK) { 1854 print_chars(serial.inq_serial, 1855 sizeof (serial.inq_serial), 0); 1856 } else { 1857 fprintf(stdout, MSGSTR(2506, "Unsupported")); 1858 } 1859 } else { 1860 fprintf(stdout, MSGSTR(2506, "Unsupported")); 1861 } 1862 HBA_CloseAdapter(handle); 1863 if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) { 1864 /* Read capacity wont work on standby paths, so try till OK */ 1865 for (tmp_path = first_time; tmp_path != NULL; 1866 tmp_path = tmp_path->next_path) { 1867 if (mpxio && (strncmp(tmp_path->info.pathState, 1868 "ONLINE", strlen(tmp_path->info.pathState)))) { 1869 /* continue to next online path */ 1870 continue; 1871 } 1872 status = HBA_OpenAdapterByWWN(&handle, 1873 tmp_path->hba_pwwn); 1874 if (status != HBA_STATUS_OK) { 1875 /* continue to next path */ 1876 continue; 1877 } 1878 1879 status = HBA_ScsiReadCapacityV2(handle, 1880 tmp_path->hba_pwwn, 1881 tmp_path->map.FcpId.PortWWN, 1882 tmp_path->map.FcpId.FcpLun, 1883 &cap_data, &cap_data_size, 1884 &scsiStatus, 1885 &sense, &senseSize); 1886 if (status == HBA_STATUS_OK) { 1887 break; 1888 } else if (status == HBA_STATUS_SCSI_CHECK_CONDITION && 1889 sense.es_key == KEY_UNIT_ATTENTION) { 1890 /* 1891 * retry for check-condition state when unit attention 1892 * condition has been established 1893 */ 1894 status = HBA_ScsiReadCapacityV2(handle, 1895 tmp_path->hba_pwwn, 1896 tmp_path->map.FcpId.PortWWN, 1897 tmp_path->map.FcpId.FcpLun, 1898 &cap_data, &cap_data_size, 1899 &scsiStatus, 1900 &sense, &senseSize); 1901 if (status == HBA_STATUS_OK) { 1902 break; 1903 } 1904 } 1905 HBA_CloseAdapter(handle); 1906 } 1907 } 1908 if (handle != HBA_HANDLE_INVALID) { 1909 HBA_CloseAdapter(handle); 1910 } 1911 if (status != HBA_STATUS_OK) { 1912 /* Make sure we don't display garbage */ 1913 cap_data.block_size = 0; 1914 cap_data.last_block_addr = 0; 1915 } 1916 1917 if (cap_data.block_size > 0 && 1918 cap_data.last_block_addr > 0) { 1919 lunMbytes = ntohl(cap_data.last_block_addr) + 1; 1920 lunMbytes *= ntohl(cap_data.block_size); 1921 lunMbytes /= (float)(1024*1024); 1922 fprintf(stdout, "\n "); 1923 fprintf(stdout, MSGSTR(60, 1924 "Unformatted capacity:\t%6.3f MBytes"), lunMbytes); 1925 } 1926 fprintf(stdout, "\n"); 1927 1928 /* 1929 * get mode page information for FC device. 1930 * do not do mode sense if this is a tape device. 1931 * mode sense will rewind the tape 1932 */ 1933 if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_SEQUENTIAL) { 1934 if (get_mode_page(first_time->map.ScsiId.OSDeviceName, 1935 &pg_buf) == 0) { 1936 mode_header_ptr = (struct mode_header_g1 *) 1937 (void *)pg_buf; 1938 offset = sizeof (struct mode_header_g1) + 1939 ntohs(mode_header_ptr->bdesc_length); 1940 pg_hdr = (struct mode_page *)&pg_buf[offset]; 1941 1942 while (offset < (ntohs(mode_header_ptr->length) + 1943 sizeof (mode_header_ptr->length))) { 1944 if (pg_hdr->code == MODEPAGE_CACHING) { 1945 struct mode_caching *pg8_buf; 1946 pg8_buf = (struct mode_caching *) 1947 (void *)pg_hdr; 1948 if (pg8_buf->wce) { 1949 fprintf(stdout, MSGSTR(2122, 1950 " Write Cache:\t\t" 1951 "Enabled\n")); 1952 } 1953 if (pg8_buf->rcd == 0) { 1954 fprintf(stdout, MSGSTR(2123, 1955 " Read Cache:\t\t" 1956 "Enabled\n")); 1957 fprintf(stdout, MSGSTR(2509, 1958 " Minimum prefetch:\t0x%x\n" 1959 " Maximum prefetch:\t0x%x\n"), 1960 pg8_buf->min_prefetch, 1961 pg8_buf->max_prefetch); 1962 } 1963 break; 1964 } 1965 offset += pg_hdr->length + 1966 sizeof (struct mode_page); 1967 pg_hdr = (struct mode_page *)&pg_buf[offset]; 1968 } 1969 } 1970 } 1971 1972 fprintf(stdout, " %s\t\t", MSGSTR(35, "Device Type:")); 1973 if ((inq.inq_dtype & DTYPE_MASK) < 0x10) { 1974 fprintf(stdout, "%s\n", 1975 dtype[inq.inq_dtype & DTYPE_MASK]); 1976 } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) { 1977 fprintf(stdout, MSGSTR(2432, "Reserved")); 1978 } else { 1979 /* dtype of 0x1f is returned */ 1980 fprintf(stdout, MSGSTR(2433, "Unknown")); 1981 } 1982 1983 fprintf(stdout, MSGSTR(2128, " Path(s):\n")); 1984 fprintf(stdout, "\n"); 1985 fprintf(stdout, " %s\n", 1986 first_time->map.ScsiId.OSDeviceName); 1987 if (phys_path != NULL) { 1988 fprintf(stdout, " %s\n", phys_path); 1989 } 1990 1991 /* Now display all paths to this LUN */ 1992 for (path = first_time; path != NULL; 1993 path = path->next_path) { 1994 /* Display the controller information */ 1995 fprintf(stdout, MSGSTR(2303, " Controller \t%s\n"), 1996 path->hba_path); 1997 1998 fprintf(stdout, MSGSTR(2507, 1999 " Device Address\t\t%016llx,%x\n"), 2000 wwnConversion( 2001 path->map.FcpId.PortWWN.wwn), 2002 path->map.ScsiId.ScsiOSLun); 2003 2004 fprintf(stdout, MSGSTR(2508, 2005 " Host controller port WWN\t%016llx\n"), 2006 wwnConversion(path->hba_pwwn.wwn)); 2007 2008 if (mpxio) { 2009 fprintf(stdout, MSGSTR(2305, 2010 " Class\t\t\t%s\n"), path->info.pathClass); 2011 fprintf(stdout, MSGSTR(2306, 2012 " State\t\t\t%s\n"), path->info.pathState); 2013 } 2014 if (phys_path != NULL) { 2015 free(phys_path); 2016 phys_path = NULL; 2017 } 2018 } 2019 printf("\n"); 2020 } 2021 } 2022 return (ret); 2023 } 2024 2025 /* 2026 * handle expert-mode hotplug commands 2027 * 2028 * return 0 iff all is okay 2029 */ 2030 int 2031 fchba_hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) 2032 { 2033 char *path_phys = NULL; 2034 int exit_code; 2035 devctl_hdl_t dcp; 2036 2037 if (todo != DEV_ONLINE && 2038 todo != DEV_OFFLINE) { 2039 fprintf(stderr, "%s\n", strerror(ENOTSUP)); 2040 return (-1); 2041 } 2042 2043 /* Convert the paths to phsyical paths */ 2044 path_phys = get_slash_devices_from_osDevName(argv[0], 2045 NOT_IGNORE_DANGLING_LINK); 2046 if (!path_phys) { 2047 fprintf(stderr, MSGSTR(112, 2048 "Error: Invalid pathname (%s)"), 2049 argv[0]); 2050 fprintf(stderr, "\n"); 2051 return (-1); 2052 } 2053 if (verbose_flag) { 2054 (void) fprintf(stdout, 2055 MSGSTR(5516, 2056 "phys path = \"%s\"\n"), 2057 path_phys); 2058 } 2059 /* acquire rights to hack on device */ 2060 if ((dcp = devctl_device_acquire(path_phys, 2061 force_flag ? 0 : DC_EXCL)) == NULL) { 2062 2063 (void) fprintf(stderr, MSGSTR(5517, 2064 "Error: can't acquire \"%s\": %s\n"), 2065 path_phys, strerror(errno)); 2066 return (1); 2067 } 2068 2069 switch (todo) { 2070 case DEV_ONLINE: 2071 exit_code = devctl_device_online(dcp); 2072 break; 2073 case DEV_OFFLINE: 2074 exit_code = devctl_device_offline(dcp); 2075 break; 2076 default: 2077 exit_code = 0; 2078 } 2079 2080 if (exit_code != 0) { 2081 perror(MSGSTR(5518, "devctl")); 2082 } 2083 2084 /* all done now -- release device */ 2085 devctl_release(dcp); 2086 2087 if (path_phys) { 2088 free(path_phys); 2089 } 2090 2091 return (exit_code); 2092 } 2093 2094 /* 2095 * Returns non zero if we should use FC-HBA. 2096 * For x86, luxadm uses FC-HBA. 2097 */ 2098 int 2099 use_fchba() 2100 { 2101 2102 #ifdef __x86 2103 return (1); 2104 #else 2105 return (0); 2106 #endif 2107 2108 } 2109 2110 /* 2111 * Returns non-zero if we should skip the HBA at index "i" 2112 */ 2113 int 2114 skip_hba(int i) { 2115 HBA_LIBRARYATTRIBUTES lib_attrs; 2116 (void) HBA_GetVendorLibraryAttributes(i, &lib_attrs); 2117 if (strncmp(lib_attrs.VName, VSL_NAME, 2118 sizeof (lib_attrs.VName)) == 0) { 2119 return (0); 2120 } 2121 return (1); 2122 } 2123 2124 /* 2125 * Function to determine if the given page is supported by vendor. 2126 */ 2127 int 2128 find_supported_inq_page(HBA_HANDLE handle, HBA_WWN hwwn, HBA_WWN pwwn, 2129 uint64_t lun, int page_num) 2130 { 2131 struct scsi_extended_sense sense; 2132 L_inquiry00 inq00; 2133 uchar_t *data; 2134 HBA_STATUS status = HBA_STATUS_ERROR; 2135 int index; 2136 HBA_UINT8 scsiStatus; 2137 uint32_t inqSize = sizeof (inq00); 2138 uint32_t senseSize = sizeof (sense); 2139 2140 status = HBA_ScsiInquiryV2(handle, hwwn, pwwn, lun, 1, 0x00, 2141 &inq00, &inqSize, &scsiStatus, &sense, &senseSize); 2142 2143 if (status == HBA_STATUS_OK) { 2144 data = (uchar_t *)&inq00; 2145 for (index = 4; (index <= inq00.len+3)&& 2146 (data[index] <= page_num); index ++) { 2147 if (data[index] == page_num) { 2148 return (1); 2149 } 2150 } 2151 } 2152 return (0); 2153 } 2154