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