comm: add -Wall
[unleashed.git] / usr / src / cmd / luxadm / fchba.c
blobb353532d102654def81bb3b5acafd2ab404e75d1
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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"
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];
58 struct rep_luns_rsp {
59 uint32_t length;
60 uint32_t rsrvd;
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;
67 uint_t block_size;
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];
80 extern char *dtype[];
81 extern int Options;
82 extern const int OPTION_P;
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);
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.
94 uint64_t
95 wwnConversion(uchar_t *wwn) {
96 uint64_t tmp;
97 (void) memcpy(&tmp, wwn, sizeof (uint64_t));
98 return (ntohll(tmp));
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;
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"));
155 return (count);
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) {
166 int count = 0;
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) {
174 break;
176 (void) sleep(1);
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");
186 return (status);
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) {
196 int count = 0;
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) {
204 break;
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;
214 break;
216 sleep(1);
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");
226 return (status);
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) {
236 int count = 0;
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,
243 discIndex, attrs);
244 if (status == HBA_STATUS_OK) {
245 break;
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
252 * user to try again.
254 status = HBA_STATUS_ERROR_TRY_AGAIN;
255 break;
257 sleep(1);
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");
267 return (status);
271 /*ARGSUSED*/
273 fchba_display_port(int verbose)
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];
285 if ((retval = loadLibrary())) {
286 return (retval);
289 count = getNumberOfAdapters();
291 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) {
292 if (skip_hba(adapterIndex)) {
293 continue;
295 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
296 if (status != HBA_STATUS_OK) {
297 /* Just skip it, maybe it was DR'd */
298 continue;
300 handle = HBA_OpenAdapter(name);
301 if (handle == 0) {
302 /* Just skip it, maybe it was DR'd */
303 continue;
306 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
307 /* This should never happen, we'll just skip the adapter */
308 HBA_CloseAdapter(handle);
309 continue;
312 for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts;
313 portIndex++) {
314 if (getAdapterPortAttrs(handle, name, portIndex,
315 &portAttrs)) {
316 continue;
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);
331 free(physical);
332 physical = NULL;
333 (void) printf("%-65s ", path);
334 } else {
335 (void) printf("%-65s ", portAttrs.OSDeviceName);
337 if (portAttrs.NumberofDiscoveredPorts > 0) {
338 printf(MSGSTR(2233, "CONNECTED\n"));
339 } else {
340 printf(MSGSTR(2234, "NOT CONNECTED\n"));
344 (void) HBA_FreeLibrary();
345 return (retval);
349 * Internal routines/structure to deal with a path list
350 * so we can ensure uniqueness
352 struct path_entry {
353 char path[MAXPATHLEN];
354 HBA_UINT8 wwn[8];
355 uchar_t dtype;
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) { }
361 tmp->next = cur;
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);
370 return (NULL);
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;
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);
392 return (1);
394 return (0);
398 is_path(char *arg) {
399 struct stat buf;
400 if (stat(arg, &buf)) {
401 return (0);
403 return (1);
406 /* We take a wild guess for our first get target mappings call */
407 #define MAP_GUESS 50
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));
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;
434 sleep(1);
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");
445 return (status);
449 * Returns the index of the first match, or -1 if no match
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;
459 if (map == NULL || compare == NULL) {
460 return (-1);
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);
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);
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);
493 if (physical) {
494 free(physical);
496 return (-1);
501 * returns non-zero on failure (aka HBA_STATUS_ERROR_*
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");
512 return (status);
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);
531 if (loadLibrary()) {
532 return (-1);
535 count = getNumberOfAdapters();
537 /* Loop over all HBAs */
538 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) {
539 if (skip_hba(adapterIndex)) {
540 continue;
542 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
543 if (status != HBA_STATUS_OK) {
544 /* May have been DR'd */
545 continue;
547 handle = HBA_OpenAdapter(name);
548 if (handle == 0) {
549 /* May have been DR'd */
550 continue;
553 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
554 /* Should not happen, just skip it */
555 HBA_CloseAdapter(handle);
556 continue;
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;
568 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) {
569 continue;
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;
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;
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;
622 tmpPath->dtype = inq.inq_dtype;
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);
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"));
648 printf("\n ");
649 printf(MSGSTR(31, "Logical Path:%s"), tmp->path);
650 printf("\n");
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);
666 free_path_list(head);
668 HBA_FreeLibrary();
669 return (0);
674 fchba_inquiry(char **argv)
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;
697 if (loadLibrary()) {
698 return (-1);
700 for (path_index = 0; argv[path_index] != NULL; path_index++) {
701 goodPath = B_FALSE;
702 found = 0;
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;
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;
728 count = getNumberOfAdapters();
730 /* Loop over all HBAs */
731 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) {
732 if (skip_hba(adapterIndex)) {
733 continue;
735 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
736 if (status != HBA_STATUS_OK) {
737 /* May have been DR'd */
738 continue;
740 handle = HBA_OpenAdapter(name);
741 if (handle == 0) {
742 /* May have been DR'd */
743 continue;
746 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
747 /* Should never happen */
748 HBA_CloseAdapter(handle);
749 continue;
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;
761 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) {
762 continue;
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;
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);
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;
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,
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));
822 } else {
823 strncpy((char *)serial.inq_serial,
824 "Unsupported",
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
832 * information
834 if (inq.inq_len < 39) {
835 inq.inq_len = 52;
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;
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");
854 if (found == 1) {
855 break;
858 if (found == 1) {
859 break;
863 if (physical) {
864 free(physical);
867 if (!goodPath) {
868 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"),
869 argv[path_index]);
870 fprintf(stderr, "\n");
871 ret = -1;
874 return (ret);
880 fchba_dump_map(char **argv)
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, *comp_phys;
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;
906 if (loadLibrary()) {
907 return (-1);
909 for (path_index = 0; argv[path_index] != NULL; path_index++) {
910 goodPath = B_FALSE;
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;
922 count = getNumberOfAdapters();
924 done = 0;
925 /* Loop over all HBAs */
926 for (adapterIndex = 0; adapterIndex < count && !done;
927 adapterIndex ++) {
928 if (skip_hba(adapterIndex)) {
929 continue;
931 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
932 if (status != HBA_STATUS_OK) {
933 /* May have been DR'd */
934 continue;
936 handle = HBA_OpenAdapter(name);
937 if (handle == 0) {
938 /* May have been DR'd */
939 continue;
942 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
943 /* Should never happen */
944 HBA_CloseAdapter(handle);
945 continue;
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;
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;
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';
983 if (strstr(comp_phys, physical)) {
984 matched = 1;
987 if (physical) {
988 free(physical);
989 physical = NULL;
991 if (comp_phys) {
992 free(comp_phys);
993 comp_phys = NULL;
997 if (!fetch_mappings(handle, portAttrs.PortWWN, &map)) {
998 mapIndex = match_mappings(argv[path_index], map);
999 if (mapIndex >= 0) {
1000 matched = 1;
1002 } else {
1003 continue;
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;
1020 printf("%-4d %-6x %-6x %016llx %016llx",
1021 discIndex,
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,
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 {
1047 * in case we are unable to retrieve report
1048 * LUN data, we will blindly try sending the
1049 * INQUIRY to lun 0.
1051 lun = 0;
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;
1064 print_fabric_dtype_prop(portAttrs.PortWWN.wwn,
1065 map->entry[mapIndex].FcpId.PortWWN.wwn,
1066 inq.inq_dtype);
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;
1080 if (!goodPath) {
1081 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"),
1082 argv[path_index]);
1083 fprintf(stderr, "\n");
1084 ret = -1;
1087 return (ret);
1091 fchba_display_link_status(char **argv)
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, *comp_phys;
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;
1109 if (loadLibrary()) {
1110 return (-1);
1112 for (path_index = 0; argv[path_index] != NULL; path_index++) {
1113 goodPath = B_FALSE;
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;
1125 count = getNumberOfAdapters();
1127 /* Loop over all HBAs */
1128 for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) {
1129 if (skip_hba(adapterIndex)) {
1130 continue;
1132 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
1133 if (status != HBA_STATUS_OK) {
1134 /* May have been DR'd */
1135 continue;
1137 handle = HBA_OpenAdapter(name);
1138 if (handle == 0) {
1139 /* May have been DR'd */
1140 continue;
1143 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
1144 /* Should never happen */
1145 HBA_CloseAdapter(handle);
1146 continue;
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;
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;
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';
1183 if (strstr(comp_phys, physical)) {
1184 matched = 1;
1187 if (physical) {
1188 free(physical);
1189 physical = NULL;
1191 if (comp_phys) {
1192 free(comp_phys);
1193 comp_phys = NULL;
1197 if (!matched) {
1198 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) {
1199 continue;
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"));
1212 for (discIndex = 0;
1213 discIndex < portAttrs.NumberofDiscoveredPorts;
1214 discIndex++) {
1217 if (getDiscPortAttrs(handle, name, portIndex,
1218 discIndex, &discPortAttrs)) {
1219 continue;
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));
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);
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));
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);
1295 if (!goodPath) {
1296 fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"),
1297 argv[path_index]);
1298 fprintf(stderr, "\n");
1299 ret = -1;
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);
1310 typedef struct _PathInformation {
1311 char pathClass[MAXPATHLEN];
1312 char pathState[MAXPATHLEN];
1313 int32_t pathInfoState;
1314 int32_t pathInfoExternalState;
1315 } PathInformation;
1317 struct lun_tracking {
1318 HBA_FCPSCSIENTRYV2 map;
1319 HBA_WWN hba_pwwn;
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";
1332 static void
1333 scsi_vhci_details(struct lun_tracking *lun)
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];
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];
1354 /* Only proceed if we are an mpxio path */
1355 if (phys_path == NULL || strstr(phys_path, VHCI_COMPONENT) == NULL) {
1356 return;
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)))) {
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;
1382 /* Now chop off the trailing ":xxx" portion if present */
1383 trailingCruft = strrchr(buf, ':');
1384 if (trailingCruft) {
1385 trailingCruft[0] = '\0';
1387 } else {
1388 strcpy(lun->info.pathClass, "Unavailable");
1389 strcpy(lun->info.pathState, "Unavailable");
1390 free(phys_path);
1391 return;
1394 ioc.client = client_path;
1395 ioc.phci = phci_path;
1397 retval = get_scsi_vhci_pathinfo(phys_path, &ioc, &pathcnt);
1398 if (retval != 0) {
1399 print_errString(retval, NULL);
1400 exit(-1);
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");
1426 nvlist_free(nvl);
1427 found++;
1428 break;
1434 if (!found) {
1435 strcpy(lun->info.pathClass, "Unavailable");
1436 strcpy(lun->info.pathState, "Unavailable");
1438 free(phys_path);
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);
1445 free(ioc.ret_buf);
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)
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) {
1464 return;
1467 if (memcmp(&cmp->map, map, sizeof (cmp->map)) == 0) {
1468 return;
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;
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);
1499 /*ARGSUSED*/
1501 fchba_display_config(char **argv, int option_t_input, int argc)
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;
1536 if ((status = loadLibrary())) {
1537 return (-1);
1539 for (path_index = 0; argv[path_index] != NULL; path_index++) {
1540 goodPath = B_FALSE;
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;
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;
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)) {
1577 continue;
1579 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
1580 if (status != HBA_STATUS_OK) {
1581 /* May have been DR'd */
1582 continue;
1584 handle = HBA_OpenAdapter(name);
1585 if (handle == 0) {
1586 /* May have been DR'd */
1587 continue;
1589 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
1590 /* Should never happen */
1591 HBA_CloseAdapter(handle);
1592 continue;
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;
1606 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) {
1607 continue;
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;
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);
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);
1652 if (physical) {
1653 free(physical);
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;
1661 status = HBA_GetAdapterName(adapterIndex, (char *)&name);
1662 if (status != HBA_STATUS_OK) {
1663 /* May have been DR'd */
1664 continue;
1666 handle = HBA_OpenAdapter(name);
1667 if (handle == 0) {
1668 /* May have been DR'd */
1669 continue;
1672 if (getAdapterAttrs(handle, name, &hbaAttrs)) {
1673 /* Should never happen */
1674 HBA_CloseAdapter(handle);
1675 continue;
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;
1689 if (fetch_mappings(handle, portAttrs.PortWWN, &map)) {
1690 continue;
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;
1710 if (matched) {
1711 break;
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);
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);
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) {
1756 mpxio = 1;
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;
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;
1779 lun = tmp_path->map.FcpId.FcpLun;
1780 memset(&inq, 0, sizeof (inq));
1781 memset(&sense, 0, sizeof (sense));
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);
1791 if (status == HBA_STATUS_OK) {
1792 break;
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");
1803 continue;
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;
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,
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"));
1859 } else {
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 */
1870 continue;
1872 status = HBA_OpenAdapterByWWN(&handle,
1873 tmp_path->hba_pwwn);
1874 if (status != HBA_STATUS_OK) {
1875 /* continue to next path */
1876 continue;
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) {
1891 * retry for check-condition state when unit attention
1892 * condition has been established
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;
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,
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];
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"));
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);
1963 break;
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"));
1978 } else {
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"),
1996 path->hba_path);
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);
2004 fprintf(stdout, MSGSTR(2508,
2005 " Host controller port WWN\t%016llx\n"),
2006 wwnConversion(path->hba_pwwn.wwn));
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);
2014 if (phys_path != NULL) {
2015 free(phys_path);
2016 phys_path = NULL;
2019 printf("\n");
2022 return (ret);
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;
2034 int exit_code;
2035 devctl_hdl_t dcp;
2037 if (todo != DEV_ONLINE &&
2038 todo != DEV_OFFLINE) {
2039 fprintf(stderr, "%s\n", strerror(ENOTSUP));
2040 return (-1);
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);
2053 if (verbose_flag) {
2054 (void) fprintf(stdout,
2055 MSGSTR(5516,
2056 "phys path = \"%s\"\n"),
2057 path_phys);
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));
2066 return (1);
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;
2078 if (exit_code != 0) {
2079 perror(MSGSTR(5518, "devctl"));
2082 /* all done now -- release device */
2083 devctl_release(dcp);
2085 if (path_phys) {
2086 free(path_phys);
2089 return (exit_code);
2093 * Returns non zero if we should use FC-HBA.
2094 * For x86, luxadm uses FC-HBA.
2097 use_fchba()
2100 #ifdef __x86
2101 return (1);
2102 #else
2103 return (0);
2104 #endif
2109 * Returns non-zero if we should skip the HBA at index "i"
2112 skip_hba(int 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) {
2117 return (0);
2119 return (1);
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;
2130 L_inquiry00 inq00;
2131 uchar_t *data;
2132 HBA_STATUS status = HBA_STATUS_ERROR;
2133 int index;
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) {
2146 return (1);
2150 return (0);