4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
32 #include <sys/param.h>
33 #include <sys/types.h>
38 #include <sys/scsi/generic/sense.h>
39 #include <sys/scsi/generic/mode.h>
40 #include <sys/scsi/generic/inquiry.h>
42 #include <libdevice.h>
43 #include <config_admin.h>
44 #include <sys/byteorder.h>
45 #include <sys/fibre-channel/fcio.h>
47 #include "sun_fc_version.h"
49 #define DEFAULT_LUN_COUNT 1024
51 #define LUN_HEADER_SIZE 8
52 #define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \
61 struct lun_val lun
[1];
64 /* Extracted from the old scsi.h file */
65 struct capacity_data_struct
{
66 uint_t last_block_addr
;
71 /* Structure to handle the inq. page 0x80 serial number */
74 uchar_t inq_page_code
;
77 uchar_t inq_serial
[251];
82 extern const int OPTION_P
;
85 int find_supported_inq_page(HBA_HANDLE handle
, HBA_WWN hwwn
, HBA_WWN pwwn
,
86 uint64_t lun
, int page_num
);
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.
95 wwnConversion(uchar_t
*wwn
) {
97 (void) memcpy(&tmp
, wwn
, sizeof (uint64_t));
101 void printStatus(HBA_STATUS status
) {
104 printf(MSGSTR(2410, "OK"));
106 case HBA_STATUS_ERROR
:
107 printf(MSGSTR(2411, "ERROR"));
109 case HBA_STATUS_ERROR_NOT_SUPPORTED
:
110 printf(MSGSTR(2412, "NOT SUPPORTED"));
112 case HBA_STATUS_ERROR_INVALID_HANDLE
:
113 printf(MSGSTR(2413, "INVALID HANDLE"));
115 case HBA_STATUS_ERROR_ARG
:
116 printf(MSGSTR(2414, "ERROR ARG"));
118 case HBA_STATUS_ERROR_ILLEGAL_WWN
:
119 printf(MSGSTR(2415, "ILLEGAL WWN"));
121 case HBA_STATUS_ERROR_ILLEGAL_INDEX
:
122 printf(MSGSTR(2416, "ILLEGAL INDEX"));
124 case HBA_STATUS_ERROR_MORE_DATA
:
125 printf(MSGSTR(2417, "MORE DATA"));
127 case HBA_STATUS_ERROR_STALE_DATA
:
128 printf(MSGSTR(2418, "STALE DATA"));
130 case HBA_STATUS_SCSI_CHECK_CONDITION
:
131 printf(MSGSTR(2419, "SCSI CHECK CONDITION"));
133 case HBA_STATUS_ERROR_BUSY
:
134 printf(MSGSTR(2420, "BUSY"));
136 case HBA_STATUS_ERROR_TRY_AGAIN
:
137 printf(MSGSTR(2421, "TRY AGAIN"));
139 case HBA_STATUS_ERROR_UNAVAILABLE
:
140 printf(MSGSTR(2422, "UNAVAILABLE"));
143 printf(MSGSTR(2423, "UNKNOWN ERROR TYPE %d"), status
);
149 getNumberOfAdapters() {
150 uint32_t count
= HBA_GetNumberOfAdapters();
152 fprintf(stderr
, MSGSTR(2405,
153 "\nERROR: No Fibre Channel Adapters found.\n"));
158 #define MAX_RETRIES 10
161 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
162 * Will handle retries if applicable.
165 getAdapterAttrs(HBA_HANDLE handle
, char *name
, HBA_ADAPTERATTRIBUTES
*attrs
) {
167 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
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
) {
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)"),
184 fprintf(stderr
, "\n");
190 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
191 * Will handle retries if applicable.
194 getAdapterPortAttrs(HBA_HANDLE handle
, char *name
, int portIndex
,
195 HBA_PORTATTRIBUTES
*attrs
) {
197 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
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
) {
207 /* The odds of this occuring are very slim, but possible. */
208 if (status
== HBA_STATUS_ERROR_STALE_DATA
) {
210 * If we hit a stale data scenario,
211 * we'll just tell the user to try again.
213 status
= HBA_STATUS_ERROR_TRY_AGAIN
;
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)"),
224 fprintf(stderr
, "\n");
230 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
231 * Will handle retries if applicable.
234 getDiscPortAttrs(HBA_HANDLE handle
, char *name
, int portIndex
, int discIndex
,
235 HBA_PORTATTRIBUTES
*attrs
) {
237 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
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
,
244 if (status
== HBA_STATUS_OK
) {
248 /* The odds of this occuring are very slim, but possible. */
249 if (status
== HBA_STATUS_ERROR_STALE_DATA
) {
251 * If we hit a stale data scenario, we'll just tell the
254 status
= HBA_STATUS_ERROR_TRY_AGAIN
;
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)"),
265 fprintf(stderr
, "\n");
273 fchba_display_port(int verbose
)
277 HBA_ADAPTERATTRIBUTES hbaAttrs
;
278 HBA_PORTATTRIBUTES portAttrs
;
280 int count
, adapterIndex
, portIndex
;
282 char *physical
= NULL
;
283 char path
[MAXPATHLEN
];
285 if ((retval
= loadLibrary())) {
289 count
= getNumberOfAdapters();
291 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
292 if (skip_hba(adapterIndex
)) {
295 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
296 if (status
!= HBA_STATUS_OK
) {
297 /* Just skip it, maybe it was DR'd */
300 handle
= HBA_OpenAdapter(name
);
302 /* Just skip it, maybe it was DR'd */
306 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
307 /* This should never happen, we'll just skip the adapter */
308 HBA_CloseAdapter(handle
);
312 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
;
314 if (getAdapterPortAttrs(handle
, name
, portIndex
,
318 physical
= get_slash_devices_from_osDevName(
319 portAttrs
.OSDeviceName
,
320 STANDARD_DEVNAME_HANDLING
);
322 char *tmp
= strstr(physical
, ":fc");
325 (void) snprintf(path
, MAXPATHLEN
, "%s:devctl",
328 (void) snprintf(path
, MAXPATHLEN
, "%s",
333 (void) printf("%-65s ", path
);
335 (void) printf("%-65s ", portAttrs
.OSDeviceName
);
337 if (portAttrs
.NumberofDiscoveredPorts
> 0) {
338 printf(MSGSTR(2233, "CONNECTED\n"));
340 printf(MSGSTR(2234, "NOT CONNECTED\n"));
344 (void) HBA_FreeLibrary();
349 * Internal routines/structure to deal with a path list
350 * so we can ensure uniqueness
353 char path
[MAXPATHLEN
];
356 struct path_entry
*next
;
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
) { }
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) {
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
; ) {
386 if (strlen(arg
) == 16) {
387 for (i
= 0; i
< 16; i
++) {
388 if (!isxdigit(arg
[i
])) {
400 if (stat(arg
, &buf
)) {
406 /* We take a wild guess for our first get target mappings call */
410 fetch_mappings(HBA_HANDLE handle
, HBA_WWN pwwn
, HBA_FCPTARGETMAPPINGV2
**map
) {
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
));
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
) {
425 } else if (status
== HBA_STATUS_ERROR_MORE_DATA
) {
426 count
= (*map
)->NumberOfEntries
;
428 *map
= (HBA_FCPTARGETMAPPINGV2
*) calloc(1,
429 (sizeof (HBA_FCPSCSIENTRYV2
)* (count
-1)) +
430 sizeof (HBA_FCPTARGETMAPPINGV2
));
431 (*map
)->NumberOfEntries
= count
;
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
));
443 fprintf(stderr
, "\n");
449 * Returns the index of the first match, or -1 if no match
452 match_mappings(char *compare
, HBA_FCPTARGETMAPPINGV2
*map
) {
454 char *physical
= NULL
;
459 if (map
== NULL
|| compare
== NULL
) {
463 if (is_wwn(compare
)) {
465 (void) sscanf(compare
, "%016llx", &wwn
);
467 /* Convert the paths to phsyical paths */
468 physical
= get_slash_devices_from_osDevName(compare
,
469 STANDARD_DEVNAME_HANDLING
);
472 for (mapIndex
= 0; mapIndex
< map
->NumberOfEntries
; mapIndex
++) {
474 if (wwn
== wwnConversion(
475 map
->entry
[mapIndex
].FcpId
.NodeWWN
.wwn
) ||
476 wwn
== wwnConversion(
477 map
->entry
[mapIndex
].FcpId
.PortWWN
.wwn
)) {
481 if (physical
!= NULL
) {
482 tmp
= get_slash_devices_from_osDevName(
483 map
->entry
[mapIndex
].ScsiId
.OSDeviceName
,
484 STANDARD_DEVNAME_HANDLING
);
486 strncmp(physical
, tmp
, MAXPATHLEN
) == 0) {
501 * returns non-zero on failure (aka HBA_STATUS_ERROR_*
505 int status
= HBA_LoadLibrary();
506 if (status
!= HBA_STATUS_OK
) {
507 fprintf(stderr
, MSGSTR(2505,
508 "ERROR: Unable to load HBA API library: "));
510 fprintf(stderr
, "\n");
516 fchba_non_encl_probe() {
518 HBA_ADAPTERATTRIBUTES hbaAttrs
;
519 HBA_PORTATTRIBUTES portAttrs
;
520 HBA_FCPTARGETMAPPINGV2
*map
;
522 int count
, adapterIndex
, portIndex
, mapIndex
;
524 struct path_entry
*head
= NULL
;
527 struct scsi_extended_sense sense
;
528 HBA_UINT8 scsiStatus
;
529 uint32_t inquirySize
= sizeof (inq
), senseSize
= sizeof (sense
);
535 count
= getNumberOfAdapters();
537 /* Loop over all HBAs */
538 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
539 if (skip_hba(adapterIndex
)) {
542 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
543 if (status
!= HBA_STATUS_OK
) {
544 /* May have been DR'd */
547 handle
= HBA_OpenAdapter(name
);
549 /* May have been DR'd */
553 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
554 /* Should not happen, just skip it */
555 HBA_CloseAdapter(handle
);
560 /* Loop over all HBA Ports */
561 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
;
563 if (getAdapterPortAttrs(handle
, name
, portIndex
,
568 if (fetch_mappings(handle
, portAttrs
.PortWWN
, &map
)) {
572 /* Loop over all target Mapping entries */
573 for (mapIndex
= 0; mapIndex
< map
->NumberOfEntries
;
575 struct path_entry
*tmpPath
= NULL
;
578 head
= (struct path_entry
*)calloc(1,
579 sizeof (struct path_entry
));
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);
588 } else if (tmpPath
= is_duplicate_path(head
,
589 map
->entry
[mapIndex
].ScsiId
.OSDeviceName
)) {
590 if (tmpPath
->dtype
!= 0x1f) {
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
);
609 lun
= map
->entry
[mapIndex
].FcpId
.FcpLun
;
610 memset(&inq
, 0, sizeof (inq
));
611 memset(&sense
, 0, sizeof (sense
));
612 status
= HBA_ScsiInquiryV2(handle
,
614 map
->entry
[mapIndex
].FcpId
.PortWWN
,
619 if (status
!= HBA_STATUS_OK
) {
620 inq
.inq_dtype
= 0x1f;
622 tmpPath
->dtype
= inq
.inq_dtype
;
628 struct path_entry
*tmp
;
629 printf(MSGSTR(2098, "\nFound Fibre Channel device(s):\n"));
630 for (tmp
= head
; tmp
!= NULL
; tmp
= tmp
->next
) {
632 printf(MSGSTR(90, "Node WWN:"));
633 printf("%016llx ", wwnConversion(tmp
->wwn
));
634 fprintf(stdout
, MSGSTR(35, "Device Type:"));
635 (void) fflush(stdout
);
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,
644 fprintf(stdout
, MSGSTR(2407,
649 printf(MSGSTR(31, "Logical Path:%s"), tmp
->path
);
652 /* We probably shouldn't be using a g_fc interface here */
653 if (Options
& OPTION_P
) {
655 get_slash_devices_from_osDevName(
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
);
666 free_path_list(head
);
674 fchba_inquiry(char **argv
)
676 int path_index
= 0, found
= 0;
680 HBA_ADAPTERATTRIBUTES hbaAttrs
;
681 HBA_PORTATTRIBUTES portAttrs
;
682 HBA_FCPTARGETMAPPINGV2
*map
;
684 int count
, adapterIndex
, portIndex
, mapIndex
;
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
;
700 for (path_index
= 0; argv
[path_index
] != NULL
; path_index
++) {
704 if (is_wwn(argv
[path_index
])) {
705 (void) sscanf(argv
[path_index
], "%016llx", &wwn
);
707 } else if (!is_path(argv
[path_index
])) {
708 fprintf(stderr
, MSGSTR(112, "Error: Invalid pathname (%s)"),
710 fprintf(stderr
, "\n");
715 /* Convert the paths to phsyical paths */
716 physical
= get_slash_devices_from_osDevName(argv
[path_index
],
717 STANDARD_DEVNAME_HANDLING
);
719 fprintf(stderr
, MSGSTR(112,
720 "Error: Invalid pathname (%s)"),
722 fprintf(stderr
, "\n");
728 count
= getNumberOfAdapters();
730 /* Loop over all HBAs */
731 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
732 if (skip_hba(adapterIndex
)) {
735 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
736 if (status
!= HBA_STATUS_OK
) {
737 /* May have been DR'd */
740 handle
= HBA_OpenAdapter(name
);
742 /* May have been DR'd */
746 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
747 /* Should never happen */
748 HBA_CloseAdapter(handle
);
753 /* Loop over all HBA Ports */
754 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
;
756 if (getAdapterPortAttrs(handle
, name
, portIndex
,
761 if (fetch_mappings(handle
, portAttrs
.PortWWN
, &map
)) {
765 for (mapIndex
= 0; mapIndex
< map
->NumberOfEntries
;
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
;
777 tmp
= get_slash_devices_from_osDevName(
778 map
->entry
[mapIndex
].ScsiId
.OSDeviceName
,
779 STANDARD_DEVNAME_HANDLING
);
780 if ((tmp
!= NULL
) && (strncmp(physical
, tmp
,
782 lun
= map
->entry
[mapIndex
].FcpId
.FcpLun
;
789 memset(&inq
, 0, sizeof (inq
));
790 memset(&sense
, 0, sizeof (sense
));
791 status
= HBA_ScsiInquiryV2(handle
,
793 map
->entry
[mapIndex
].FcpId
.PortWWN
,
798 if (status
== HBA_STATUS_OK
) {
801 * Call the inquiry cmd on page 0x80 only if
802 * the vendor supports page 0x80
804 memset(&serial
, 0, sizeof (serial
));
805 if ((find_supported_inq_page(handle
,
807 map
->entry
[mapIndex
].FcpId
.PortWWN
,
809 status
= HBA_ScsiInquiryV2(handle
,
811 map
->entry
[mapIndex
].FcpId
.PortWWN
,
813 &serial
, &serialSize
,
816 if (status
!= HBA_STATUS_OK
) {
818 (char *)serial
.inq_serial
,
820 sizeof (serial
.inq_serial
));
823 strncpy((char *)serial
.inq_serial
,
825 sizeof (serial
.inq_serial
));
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
834 if (inq
.inq_len
< 39) {
837 print_inq_data(argv
[path_index
],
838 map
->entry
[mapIndex
].ScsiId
.OSDeviceName
,
839 inq
, serial
.inq_serial
,
840 sizeof (serial
.inq_serial
));
846 fprintf(stderr
, MSGSTR(2430,
847 "Error: I/O failure communicating with %s "),
848 map
->entry
[mapIndex
].ScsiId
.OSDeviceName
);
850 fprintf(stderr
, "\n");
868 fprintf(stderr
, MSGSTR(112, "Error: Invalid pathname (%s)"),
870 fprintf(stderr
, "\n");
880 fchba_dump_map(char **argv
)
886 HBA_ADAPTERATTRIBUTES hbaAttrs
;
887 HBA_PORTATTRIBUTES portAttrs
;
888 HBA_PORTATTRIBUTES discPortAttrs
;
889 HBA_FCPTARGETMAPPINGV2
*map
;
891 int count
, adapterIndex
, portIndex
, mapIndex
, discIndex
;
892 char name
[256], *physical
, *comp_phys
;
894 struct scsi_extended_sense sense
;
895 HBA_UINT8 scsiStatus
;
898 uint32_t inquirySize
= sizeof (inq
), senseSize
= sizeof (sense
);
899 boolean_t goodPath
= B_FALSE
;
901 uint32_t responseSize
= DEFAULT_LUN_LENGTH
;
902 uchar_t raw_luns
[DEFAULT_LUN_LENGTH
];
903 struct rep_luns_rsp
*lun_resp
;
909 for (path_index
= 0; argv
[path_index
] != NULL
; path_index
++) {
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)"),
917 fprintf(stderr
, "\n");
922 count
= getNumberOfAdapters();
925 /* Loop over all HBAs */
926 for (adapterIndex
= 0; adapterIndex
< count
&& !done
;
928 if (skip_hba(adapterIndex
)) {
931 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
932 if (status
!= HBA_STATUS_OK
) {
933 /* May have been DR'd */
936 handle
= HBA_OpenAdapter(name
);
938 /* May have been DR'd */
942 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
943 /* Should never happen */
944 HBA_CloseAdapter(handle
);
949 /* Loop over all HBA Ports */
950 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
&& !done
;
952 if (getAdapterPortAttrs(handle
, name
, portIndex
,
959 if (is_wwn(argv
[path_index
])) {
960 if (wwn
== wwnConversion(
961 portAttrs
.NodeWWN
.wwn
) ||
962 wwn
== wwnConversion(
963 portAttrs
.PortWWN
.wwn
)) {
967 if (is_path(argv
[path_index
]) &&
968 ((physical
= get_slash_devices_from_osDevName(
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");
978 tmp
= strstr(physical
, ":fc");
983 if (strstr(comp_phys
, physical
)) {
997 if (!fetch_mappings(handle
, portAttrs
.PortWWN
, &map
)) {
998 mapIndex
= match_mappings(argv
[path_index
], map
);
1009 "Pos Port_ID Hard_Addr Port WWN"
1010 " Node WWN Type\n"));
1012 discIndex
< portAttrs
.NumberofDiscoveredPorts
;
1014 if (getDiscPortAttrs(handle
, name
, portIndex
,
1015 discIndex
, &discPortAttrs
)) {
1016 /* Move on to the next target */
1020 printf("%-4d %-6x %-6x %016llx %016llx",
1022 discPortAttrs
.PortFcId
, 0,
1023 wwnConversion(discPortAttrs
.PortWWN
.wwn
),
1024 wwnConversion(discPortAttrs
.NodeWWN
.wwn
));
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
1033 memset(&sense
, 0, sizeof (sense
));
1034 status
= HBA_ScsiReportLUNsV2(handle
,
1036 discPortAttrs
.PortWWN
,
1037 (void *)raw_luns
, &responseSize
, &scsiStatus
,
1038 (void *)&sense
, &senseSize
);
1039 if (status
== HBA_STATUS_OK
) {
1041 (struct rep_luns_rsp
*)
1042 (unsigned long)raw_luns
;
1044 wwnConversion(lun_resp
->lun
[0].val
));
1047 * in case we are unable to retrieve report
1048 * LUN data, we will blindly try sending the
1053 memset(&sense
, 0, sizeof (sense
));
1054 status
= HBA_ScsiInquiryV2(handle
,
1056 discPortAttrs
.PortWWN
,
1060 &sense
, &senseSize
);
1061 if (status
!= HBA_STATUS_OK
) {
1062 inq
.inq_dtype
= 0x1f;
1064 print_fabric_dtype_prop(portAttrs
.PortWWN
.wwn
,
1065 map
->entry
[mapIndex
].FcpId
.PortWWN
.wwn
,
1068 /* Now dump this HBA's stats */
1069 printf("%-4d %-6x %-6x %016llx %016llx",
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);
1081 fprintf(stderr
, MSGSTR(112, "Error: Invalid pathname (%s)"),
1083 fprintf(stderr
, "\n");
1091 fchba_display_link_status(char **argv
)
1096 HBA_ADAPTERATTRIBUTES hbaAttrs
;
1097 HBA_PORTATTRIBUTES portAttrs
;
1098 HBA_PORTATTRIBUTES discPortAttrs
;
1099 HBA_FCPTARGETMAPPINGV2
*map
;
1101 int count
, adapterIndex
, portIndex
, discIndex
;
1102 char name
[256], *physical
, *comp_phys
;
1104 struct fc_rls_acc_params rls
;
1105 uint32_t rls_size
= sizeof (rls
);
1106 boolean_t goodPath
= B_FALSE
;
1109 if (loadLibrary()) {
1112 for (path_index
= 0; argv
[path_index
] != NULL
; path_index
++) {
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)"),
1120 fprintf(stderr
, "\n");
1125 count
= getNumberOfAdapters();
1127 /* Loop over all HBAs */
1128 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
1129 if (skip_hba(adapterIndex
)) {
1132 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
1133 if (status
!= HBA_STATUS_OK
) {
1134 /* May have been DR'd */
1137 handle
= HBA_OpenAdapter(name
);
1139 /* May have been DR'd */
1143 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
1144 /* Should never happen */
1145 HBA_CloseAdapter(handle
);
1150 /* Loop over all HBA Ports */
1151 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
;
1153 if (getAdapterPortAttrs(handle
, name
, portIndex
,
1159 if (is_wwn(argv
[path_index
])) {
1160 if (wwn
== wwnConversion(
1161 portAttrs
.NodeWWN
.wwn
) ||
1162 wwn
== wwnConversion(
1163 portAttrs
.PortWWN
.wwn
)) {
1167 if (is_path(argv
[path_index
]) &&
1168 ((physical
= get_slash_devices_from_osDevName(
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");
1178 tmp
= strstr(physical
, ":fc");
1183 if (strstr(comp_phys
, physical
)) {
1198 if (fetch_mappings(handle
, portAttrs
.PortWWN
, &map
)) {
1203 if (matched
|| match_mappings(argv
[path_index
], map
) >= 0) {
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"));
1213 discIndex
< portAttrs
.NumberofDiscoveredPorts
;
1217 if (getDiscPortAttrs(handle
, name
, portIndex
,
1218 discIndex
, &discPortAttrs
)) {
1222 status
= HBA_SendRLS(handle
, portAttrs
.PortWWN
,
1223 discPortAttrs
.PortWWN
,
1225 if (status
!= HBA_STATUS_OK
) {
1226 memset(&rls
, 0xff, sizeof (rls
));
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)) {
1236 "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n",
1237 discPortAttrs
.PortFcId
,
1241 rls
.rls_prim_seq_err
,
1242 rls
.rls_invalid_word
,
1243 rls
.rls_invalid_crc
);
1246 "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n",
1247 discPortAttrs
.PortFcId
,
1251 rls
.rls_prim_seq_err
,
1252 rls
.rls_invalid_word
,
1253 rls
.rls_invalid_crc
);
1258 /* Now dump this HBA's stats */
1259 status
= HBA_SendRLS(handle
, portAttrs
.PortWWN
,
1262 if (status
!= HBA_STATUS_OK
) {
1263 memset(&rls
, 0xff, sizeof (rls
));
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)) {
1273 "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n",
1278 rls
.rls_prim_seq_err
,
1279 rls
.rls_invalid_word
,
1280 rls
.rls_invalid_crc
);
1283 "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n",
1288 rls
.rls_prim_seq_err
,
1289 rls
.rls_invalid_word
,
1290 rls
.rls_invalid_crc
);
1296 fprintf(stderr
, MSGSTR(112, "Error: Invalid pathname (%s)"),
1298 fprintf(stderr
, "\n");
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"));
1310 typedef struct _PathInformation
{
1311 char pathClass
[MAXPATHLEN
];
1312 char pathState
[MAXPATHLEN
];
1313 int32_t pathInfoState
;
1314 int32_t pathInfoExternalState
;
1317 struct lun_tracking
{
1318 HBA_FCPSCSIENTRYV2 map
;
1320 char hba_path
[MAXPATHLEN
];
1321 PathInformation info
;
1323 /* Points to another lun_tracking instance with the same map->LUID */
1324 struct lun_tracking
*next_path
;
1326 /* Points to next lun_tracking with a different map->LUID */
1327 struct lun_tracking
*next_lun
;
1331 static const char VHCI_COMPONENT
[] = "scsi_vhci";
1333 scsi_vhci_details(struct lun_tracking
*lun
)
1335 HBA_FCPSCSIENTRYV2 entry
= lun
->map
;
1337 int pathcnt
, i
, count
, found
= 0;
1338 char temppath
[MAXPATHLEN
];
1339 char buf
[MAXPATHLEN
];
1340 char *path_state
[5];
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
];
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
];
1354 /* Only proceed if we are an mpxio path */
1355 if (phys_path
== NULL
|| strstr(phys_path
, VHCI_COMPONENT
) == NULL
) {
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");
1365 sprintf(devaddr
, "%016llx,%x", wwnConversion(
1366 entry
.FcpId
.PortWWN
.wwn
),
1367 entry
.ScsiId
.ScsiOSLun
);
1369 /* First get the controller path */
1370 sprintf(temppath
, "/dev/cfg/c%d", entry
.ScsiId
.ScsiBusNumber
);
1371 if ((count
= readlink(temppath
, buf
, sizeof (buf
)))) {
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");
1382 /* Now chop off the trailing ":xxx" portion if present */
1383 trailingCruft
= strrchr(buf
, ':');
1384 if (trailingCruft
) {
1385 trailingCruft
[0] = '\0';
1388 strcpy(lun
->info
.pathClass
, "Unavailable");
1389 strcpy(lun
->info
.pathState
, "Unavailable");
1394 ioc
.client
= client_path
;
1395 ioc
.phci
= phci_path
;
1397 retval
= get_scsi_vhci_pathinfo(phys_path
, &ioc
, &pathcnt
);
1399 print_errString(retval
, NULL
);
1403 for (i
= 0; i
< pathcnt
; i
++) {
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);
1411 strcpy(lun
->info
.pathClass
,
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
);
1423 strcpy(lun
->info
.pathClass
, "UNKNOWN");
1435 strcpy(lun
->info
.pathClass
, "Unavailable");
1436 strcpy(lun
->info
.pathState
, "Unavailable");
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
);
1449 /* Utility routine to add new entries to the list (ignores dups) */
1451 add_lun_path(struct lun_tracking
*head
, HBA_FCPSCSIENTRYV2
*map
,
1452 HBA_WWN pwwn
, char *path
)
1454 struct lun_tracking
*tmp
= NULL
, *cmp
= NULL
;
1456 for (tmp
= head
; tmp
!= NULL
; tmp
= tmp
->next_lun
) {
1457 if (memcmp(&tmp
->map
.LUID
, &map
->LUID
,
1458 sizeof (HBA_LUID
)) == 0) {
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) {
1467 if (memcmp(&cmp
->map
, map
, sizeof (cmp
->map
)) == 0) {
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
,
1477 (void) memcpy(&cmp
->hba_pwwn
, &pwwn
,
1478 sizeof (cmp
->hba_pwwn
));
1479 (void) snprintf(cmp
->hba_path
, MAXPATHLEN
,
1481 scsi_vhci_details(cmp
);
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
,
1492 (void) memcpy(&tmp
->hba_pwwn
, &pwwn
,
1493 sizeof (tmp
->hba_pwwn
));
1494 (void) snprintf(tmp
->hba_path
, MAXPATHLEN
,
1496 scsi_vhci_details(tmp
);
1501 fchba_display_config(char **argv
, int option_t_input
, int argc
)
1507 HBA_ADAPTERATTRIBUTES hbaAttrs
;
1508 HBA_PORTATTRIBUTES portAttrs
;
1509 HBA_FCPTARGETMAPPINGV2
*map
;
1511 int count
, adapterIndex
, portIndex
;
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
;
1522 struct capacity_data_struct cap_data
;
1523 uint32_t cap_data_size
= sizeof (cap_data
);
1524 struct mode_header_g1
*mode_header_ptr
;
1526 char *phys_path
= NULL
;
1529 char *physical
= NULL
;
1530 struct lun_tracking
*head
= NULL
;
1531 boolean_t goodPath
= B_FALSE
;
1536 if ((status
= loadLibrary())) {
1539 for (path_index
= 0; argv
[path_index
] != NULL
; path_index
++) {
1542 if (is_wwn(argv
[path_index
])) {
1543 (void) sscanf(argv
[path_index
], "%016llx", &wwn
);
1545 } else if (!is_path(argv
[path_index
])) {
1546 fprintf(stderr
, MSGSTR(112, "Error: Invalid pathname (%s)"),
1548 fprintf(stderr
, "\n");
1553 /* Convert the paths to phsyical paths */
1554 physical
= get_slash_devices_from_osDevName(argv
[path_index
],
1555 STANDARD_DEVNAME_HANDLING
);
1557 fprintf(stderr
, MSGSTR(112,
1558 "Error: Invalid pathname (%s)"),
1560 fprintf(stderr
, "\n");
1566 count
= getNumberOfAdapters();
1570 * We have to loop twice to ensure we don't miss any
1571 * extra paths for other targets in a multi-target device
1574 /* First check WWN/path comparisons */
1575 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
1576 if (skip_hba(adapterIndex
)) {
1579 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
1580 if (status
!= HBA_STATUS_OK
) {
1581 /* May have been DR'd */
1584 handle
= HBA_OpenAdapter(name
);
1586 /* May have been DR'd */
1589 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
1590 /* Should never happen */
1591 HBA_CloseAdapter(handle
);
1595 /* Loop over all HBA Ports */
1596 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
;
1601 if (getAdapterPortAttrs(handle
, name
, portIndex
,
1606 if (fetch_mappings(handle
, portAttrs
.PortWWN
, &map
)) {
1612 for (mapIndex
= 0; mapIndex
< map
->NumberOfEntries
;
1616 if (wwn
== wwnConversion(
1617 map
->entry
[mapIndex
].FcpId
.NodeWWN
.wwn
) ||
1618 wwn
== wwnConversion(
1619 map
->entry
[mapIndex
].FcpId
.PortWWN
.wwn
)) {
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)) {
1632 if (matched
&& head
== NULL
) {
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
) {
1645 add_lun_path(head
, &map
->entry
[mapIndex
],
1646 portAttrs
.PortWWN
, portAttrs
.OSDeviceName
);
1656 /* Now do it again and look for matching LUIDs (aka GUIDs) */
1657 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
1658 if (skip_hba(adapterIndex
)) {
1661 status
= HBA_GetAdapterName(adapterIndex
, (char *)&name
);
1662 if (status
!= HBA_STATUS_OK
) {
1663 /* May have been DR'd */
1666 handle
= HBA_OpenAdapter(name
);
1668 /* May have been DR'd */
1672 if (getAdapterAttrs(handle
, name
, &hbaAttrs
)) {
1673 /* Should never happen */
1674 HBA_CloseAdapter(handle
);
1679 /* Loop over all HBA Ports */
1680 for (portIndex
= 0; portIndex
< hbaAttrs
.NumberOfPorts
;
1684 if (getAdapterPortAttrs(handle
, name
, portIndex
,
1689 if (fetch_mappings(handle
, portAttrs
.PortWWN
, &map
)) {
1694 for (mapIndex
= 0; mapIndex
< map
->NumberOfEntries
;
1696 struct lun_tracking
*outer
;
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) {
1714 if (matched
&& head
== NULL
) {
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
) {
1727 add_lun_path(head
, &map
->entry
[mapIndex
],
1728 portAttrs
.PortWWN
, portAttrs
.OSDeviceName
);
1734 fprintf(stderr
, MSGSTR(112, "Error: Invalid pathname (%s)"),
1736 fprintf(stderr
, "\n");
1738 /* Just bomb out instead of going on */
1743 /* Now display all the LUNs that we found that matched */
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
) {
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 */
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 */
1779 lun
= tmp_path
->map
.FcpId
.FcpLun
;
1780 memset(&inq
, 0, sizeof (inq
));
1781 memset(&sense
, 0, sizeof (sense
));
1783 status
= HBA_ScsiInquiryV2(handle
,
1785 tmp_path
->map
.FcpId
.PortWWN
,
1789 &sense
, &senseSize
);
1791 if (status
== HBA_STATUS_OK
) {
1794 HBA_CloseAdapter(handle
);
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");
1806 switch ((inq
.inq_dtype
& DTYPE_MASK
)) {
1808 fprintf(stdout
, MSGSTR(121,
1809 "DEVICE PROPERTIES for disk: %s\n"),
1810 first_time
->map
.ScsiId
.OSDeviceName
);
1812 case DTYPE_SEQUENTIAL
: /* Tape */
1813 fprintf(stdout
, MSGSTR(2249,
1814 "DEVICE PROPERTIES for tape: %s\n"),
1815 first_time
->map
.ScsiId
.OSDeviceName
);
1818 fprintf(stdout
, MSGSTR(2250,
1819 "DEVICE PROPERTIES for: %s\n"),
1820 first_time
->map
.ScsiId
.OSDeviceName
);
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);
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);
1835 fprintf(stdout
, "\n ");
1836 fprintf(stdout
, MSGSTR(17, "Serial Num:"));
1837 fprintf(stdout
, "\t\t");
1838 (void) fflush(stdout
);
1840 * Call the inquiry cmd on page 0x80 only if the vendor
1841 * supports page 0x80.
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
,
1850 &serial
, &serialSize
,
1852 &sense
, &senseSize
);
1853 if (status
== HBA_STATUS_OK
) {
1854 print_chars(serial
.inq_serial
,
1855 sizeof (serial
.inq_serial
), 0);
1857 fprintf(stdout
, MSGSTR(2506, "Unsupported"));
1860 fprintf(stdout
, MSGSTR(2506, "Unsupported"));
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 */
1872 status
= HBA_OpenAdapterByWWN(&handle
,
1873 tmp_path
->hba_pwwn
);
1874 if (status
!= HBA_STATUS_OK
) {
1875 /* continue to next path */
1879 status
= HBA_ScsiReadCapacityV2(handle
,
1881 tmp_path
->map
.FcpId
.PortWWN
,
1882 tmp_path
->map
.FcpId
.FcpLun
,
1883 &cap_data
, &cap_data_size
,
1885 &sense
, &senseSize
);
1886 if (status
== HBA_STATUS_OK
) {
1888 } else if (status
== HBA_STATUS_SCSI_CHECK_CONDITION
&&
1889 sense
.es_key
== KEY_UNIT_ATTENTION
) {
1891 * retry for check-condition state when unit attention
1892 * condition has been established
1894 status
= HBA_ScsiReadCapacityV2(handle
,
1896 tmp_path
->map
.FcpId
.PortWWN
,
1897 tmp_path
->map
.FcpId
.FcpLun
,
1898 &cap_data
, &cap_data_size
,
1900 &sense
, &senseSize
);
1901 if (status
== HBA_STATUS_OK
) {
1905 HBA_CloseAdapter(handle
);
1908 if (handle
!= HBA_HANDLE_INVALID
) {
1909 HBA_CloseAdapter(handle
);
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;
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
);
1926 fprintf(stdout
, "\n");
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
1933 if ((inq
.inq_dtype
& DTYPE_MASK
) != DTYPE_SEQUENTIAL
) {
1934 if (get_mode_page(first_time
->map
.ScsiId
.OSDeviceName
,
1936 mode_header_ptr
= (struct mode_header_g1
*)
1938 offset
= sizeof (struct mode_header_g1
) +
1939 ntohs(mode_header_ptr
->bdesc_length
);
1940 pg_hdr
= (struct mode_page
*)&pg_buf
[offset
];
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
*)
1949 fprintf(stdout
, MSGSTR(2122,
1953 if (pg8_buf
->rcd
== 0) {
1954 fprintf(stdout
, MSGSTR(2123,
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
);
1965 offset
+= pg_hdr
->length
+
1966 sizeof (struct mode_page
);
1967 pg_hdr
= (struct mode_page
*)&pg_buf
[offset
];
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"));
1979 /* dtype of 0x1f is returned */
1980 fprintf(stdout
, MSGSTR(2433, "Unknown"));
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
);
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"),
1998 fprintf(stdout
, MSGSTR(2507,
1999 " Device Address\t\t%016llx,%x\n"),
2001 path
->map
.FcpId
.PortWWN
.wwn
),
2002 path
->map
.ScsiId
.ScsiOSLun
);
2004 fprintf(stdout
, MSGSTR(2508,
2005 " Host controller port WWN\t%016llx\n"),
2006 wwnConversion(path
->hba_pwwn
.wwn
));
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
);
2014 if (phys_path
!= NULL
) {
2026 * handle expert-mode hotplug commands
2028 * return 0 iff all is okay
2031 fchba_hotplug_e(int todo
, char **argv
, int verbose_flag
, int force_flag
)
2033 char *path_phys
= NULL
;
2037 if (todo
!= DEV_ONLINE
&&
2038 todo
!= DEV_OFFLINE
) {
2039 fprintf(stderr
, "%s\n", strerror(ENOTSUP
));
2043 /* Convert the paths to phsyical paths */
2044 path_phys
= get_slash_devices_from_osDevName(argv
[0],
2045 NOT_IGNORE_DANGLING_LINK
);
2047 fprintf(stderr
, MSGSTR(112,
2048 "Error: Invalid pathname (%s)"),
2050 fprintf(stderr
, "\n");
2054 (void) fprintf(stdout
,
2056 "phys path = \"%s\"\n"),
2059 /* acquire rights to hack on device */
2060 if ((dcp
= devctl_device_acquire(path_phys
,
2061 force_flag
? 0 : DC_EXCL
)) == NULL
) {
2063 (void) fprintf(stderr
, MSGSTR(5517,
2064 "Error: can't acquire \"%s\": %s\n"),
2065 path_phys
, strerror(errno
));
2071 exit_code
= devctl_device_online(dcp
);
2074 exit_code
= devctl_device_offline(dcp
);
2078 if (exit_code
!= 0) {
2079 perror(MSGSTR(5518, "devctl"));
2082 /* all done now -- release device */
2083 devctl_release(dcp
);
2093 * Returns non zero if we should use FC-HBA.
2094 * For x86, luxadm uses FC-HBA.
2109 * Returns non-zero if we should skip the HBA at index "i"
2113 HBA_LIBRARYATTRIBUTES lib_attrs
;
2114 (void) HBA_GetVendorLibraryAttributes(i
, &lib_attrs
);
2115 if (strncmp(lib_attrs
.VName
, VSL_NAME
,
2116 sizeof (lib_attrs
.VName
)) == 0) {
2123 * Function to determine if the given page is supported by vendor.
2126 find_supported_inq_page(HBA_HANDLE handle
, HBA_WWN hwwn
, HBA_WWN pwwn
,
2127 uint64_t lun
, int page_num
)
2129 struct scsi_extended_sense sense
;
2132 HBA_STATUS status
= HBA_STATUS_ERROR
;
2134 HBA_UINT8 scsiStatus
;
2135 uint32_t inqSize
= sizeof (inq00
);
2136 uint32_t senseSize
= sizeof (sense
);
2138 status
= HBA_ScsiInquiryV2(handle
, hwwn
, pwwn
, lun
, 1, 0x00,
2139 &inq00
, &inqSize
, &scsiStatus
, &sense
, &senseSize
);
2141 if (status
== HBA_STATUS_OK
) {
2142 data
= (uchar_t
*)&inq00
;
2143 for (index
= 4; (index
<= inq00
.len
+3)&&
2144 (data
[index
] <= page_num
); index
++) {
2145 if (data
[index
] == page_num
) {