xref: /illumos-gate/usr/src/cmd/fcinfo/fcinfo-list.c (revision 48847494)
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 #include "fcinfo.h"
28 #include <libintl.h>
29 
30 struct lun {
31 	uchar_t val[8];
32 };
33 
34 typedef enum {
35     HBA_PORT,
36     REMOTE_PORT,
37     LOGICAL_UNIT
38 } resource_type;
39 
40 typedef struct rep_luns_rsp {
41 	uint32_t    length;
42 	uint32_t    rsrvd;
43 	struct lun  lun[1];
44 } rep_luns_rsp_t;
45 
46 static int getTargetMapping(HBA_HANDLE, HBA_WWN myhbaPortWWN,
47     HBA_FCPTARGETMAPPINGV2 **mapping);
48 static int processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs,
49     int portIndex, HBA_PORTATTRIBUTES port, HBA_FCPTARGETMAPPINGV2 *map,
50     int resourceType, int flags, int mode);
51 static void processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
52     HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags);
53 static void handleRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
54     HBA_WWN myRemotePortWWN, HBA_PORTATTRIBUTES *discPort);
55 static void printLinkStat(HBA_HANDLE handle, HBA_WWN hbaportWWN,
56     HBA_WWN destWWN);
57 static void handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
58     HBA_WWN scsiTargetWWN, HBA_FCPTARGETMAPPINGV2 *map);
59 static int retrieveAttrs(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
60     HBA_ADAPTERATTRIBUTES *attrs, HBA_PORTATTRIBUTES *port, int *portIndex);
61 static void searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry,
62     HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose);
63 
64 /*
65  * This function retrieve the adapater attributes, port attributes, and
66  * portIndex for the given handle and hba port WWN.
67  *
68  * Arguments:
69  *	handle	    an HBA_HANDLE to a adapter
70  *	hbaPortWWN  WWN of the port on the adapter to which to retrieve
71  *			HBA_PORTATTRIBUTES from
72  *	attrs	    pointer to a HBA_ADAPTERATTRIBUTES structure.  Upon
73  *			successful completion, this structure will be filled in
74  *	port	    pointer to a HBA_PORTATTRIBUTES structure.  Upon successful
75  *			completion, this structure will be fill in
76  *	portIndex   the Index count of the port on the adapter that is
77  *			associated with the WWN.
78  *
79  * Returns
80  *	0	    successfully retrieve all information
81  *	>0	    otherwise
82  */
83 static int
84 retrieveAttrs(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
85     HBA_ADAPTERATTRIBUTES *attrs, HBA_PORTATTRIBUTES *port, int *portIndex)
86 {
87 	HBA_STATUS		status;
88 	int			portCtr;
89 	int			times;
90 
91 	/* argument checking */
92 	if (attrs == NULL || port == NULL || portIndex == NULL) {
93 		fprintf(stderr, gettext("Error: Invalid arguments to "
94 			    "retreiveAttrs\n"));
95 		return (1);
96 	}
97 
98 	/* retrieve Adapter attributes */
99 	memset(attrs, 0, sizeof (HBA_ADAPTERATTRIBUTES));
100 	status = HBA_GetAdapterAttributes(handle, attrs);
101 	times = 0;
102 	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
103 	    status == HBA_STATUS_ERROR_BUSY) &&
104 	    times++ < HBA_MAX_RETRIES) {
105 		(void) sleep(1);
106 		status = HBA_GetAdapterAttributes(handle, attrs);
107 		if (status == HBA_STATUS_OK) {
108 			break;
109 		}
110 	}
111 	if (status != HBA_STATUS_OK) {
112 		fprintf(stderr, gettext("Failed to get adapter "
113 		    "attributes handle(%d) Reason: "), handle);
114 		printStatus(status);
115 		fprintf(stderr, "\n");
116 		return (1);
117 	}
118 
119 	/*
120 	 * find the corresponding port on the adapter and retrieve
121 	 * port attributes as well as the port index
122 	 */
123 	memset(port,  0, sizeof (HBA_PORTATTRIBUTES));
124 	for (portCtr = 0; portCtr < attrs->NumberOfPorts; portCtr++) {
125 		if ((status = HBA_GetAdapterPortAttributes(handle,
126 				    portCtr, port)) != HBA_STATUS_OK) {
127 			fprintf(stderr,
128 			    gettext("Error: Failed to get port (%d) "
129 				    "attributes reason: "), portCtr);
130 			printStatus(status);
131 			fprintf(stderr, "\n");
132 			return (1);
133 		}
134 		if (memcmp(hbaPortWWN.wwn, port->PortWWN.wwn,
135 			    sizeof (port->PortWWN.wwn)) == 0) {
136 			break;
137 		}
138 	}
139 	if (portCtr >= attrs->NumberOfPorts) {
140 		/*
141 		 * not able to find corresponding port WWN
142 		 * returning an error
143 		 */
144 		*portIndex = 0;
145 		return (1);
146 	}
147 	*portIndex = portCtr;
148 	return (0);
149 }
150 
151 /*
152  * This function retrieves target mapping information for the HBA port WWN.
153  * This function will allocate space for the mapping structure which the caller
154  * must free when they are finished
155  *
156  * Arguments:
157  *	handle - a handle to a HBA that we will be processing
158  *	hbaPortWWN - the port WWN for the HBA port to retrieve the mappings for
159  *	mapping - a pointer to a pointer for the target mapping structure
160  *	    Upon successful completion of this function, *mapping will contain
161  *	    the target mapping information
162  *
163  * returns:
164  *	0	if successful
165  *	1	otherwise
166  */
167 static int
168 getTargetMapping(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
169     HBA_FCPTARGETMAPPINGV2 **mapping)
170 {
171 	HBA_FCPTARGETMAPPINGV2	*map;
172 	HBA_STATUS		status;
173 	int			count;
174 
175 	/* argument sanity checking */
176 	if (mapping == NULL) {
177 		fprintf(stderr, gettext("Internal Error: mapping is NULL"));
178 		return (1);
179 	}
180 	*mapping = NULL;
181 	if ((map = calloc(1, sizeof (HBA_FCPTARGETMAPPINGV2))) == NULL) {
182 		fprintf(stderr,
183 		    gettext("Internal Error: Unable to calloc map"));
184 		return (1);
185 	}
186 	status = HBA_GetFcpTargetMappingV2(handle, hbaPortWWN, map);
187 	count = map->NumberOfEntries;
188 	if (status == HBA_STATUS_ERROR_MORE_DATA) {
189 		free(map);
190 		if ((map = calloc(1, (sizeof (HBA_FCPSCSIENTRYV2)*(count-1)) +
191 				    sizeof (HBA_FCPTARGETMAPPINGV2))) == NULL) {
192 			fprintf(stderr,
193 			    gettext("Unable to calloc map of size: %d"), count);
194 			return (1);
195 		}
196 		map->NumberOfEntries = count;
197 		status = HBA_GetFcpTargetMappingV2(handle, hbaPortWWN, map);
198 	}
199 	if (status != HBA_STATUS_OK) {
200 		fprintf(stderr,
201 		    gettext("Error: Unable to get Target Mapping\n"));
202 		printStatus(status);
203 		fprintf(stderr, "\n");
204 		free(map);
205 		return (1);
206 	}
207 	*mapping = map;
208 	return (0);
209 }
210 
211 /*
212  * This function handles the remoteport object.  It will issue a report lun
213  * to determine whether it is a scsi-target and then print the information.
214  *
215  * Arguments:
216  *	handle - a handle to a HBA that we will be processing
217  *	portWWN - the port WWN for the HBA port we will be issuing the SCSI
218  *	    ReportLUNS through
219  *	remotePortWWN - the port WWN we will be issuing the report lun call to
220  *	discPort - PORTATTRIBUTES structure for the remotePortWWN
221  */
222 static void
223 handleRemotePort(HBA_HANDLE handle, HBA_WWN portWWN, HBA_WWN remotePortWWN,
224     HBA_PORTATTRIBUTES *discPort)
225 {
226 	HBA_STATUS		status;
227 	int			scsiTargetType;
228 	uchar_t			raw_luns[LUN_LENGTH];
229 	HBA_UINT32		responseSize = LUN_LENGTH;
230 	struct scsi_extended_sense  sense;
231 	HBA_UINT32		senseSize = sizeof (struct scsi_extended_sense);
232 	HBA_UINT8		rep_luns_status;
233 
234 	/* argument checking */
235 	if (discPort == NULL) {
236 		return;
237 	}
238 
239 	memset(raw_luns, 0, sizeof (raw_luns));
240 	/* going to issue a report lun to check if this is a scsi-target */
241 	status = HBA_ScsiReportLUNsV2(handle, portWWN, remotePortWWN,
242 	    (void *)raw_luns, &responseSize, &rep_luns_status,
243 	    (void *)&sense, &senseSize);
244 	if (status == HBA_STATUS_OK) {
245 		scsiTargetType = SCSI_TARGET_TYPE_YES;
246 	} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
247 		scsiTargetType = SCSI_TARGET_TYPE_NO;
248 	} else {
249 		scsiTargetType = SCSI_TARGET_TYPE_UNKNOWN;
250 	}
251 	printDiscoPortInfo(discPort, scsiTargetType);
252 }
253 
254 /*
255  * This function will issue the RLS and print out the port statistics for
256  * the given destWWN
257  *
258  * Arguments
259  *	handle - a handle to a HBA that we will be processing
260  *	hbaPortWWN - the hba port WWN through which the RLS will be sent
261  *	destWWN - the remote port to which the RLS will be sent
262  */
263 static void
264 printLinkStat(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN destWWN)
265 {
266 	HBA_STATUS		status;
267 	fc_rls_acc_t		rls_payload;
268 	uint32_t		rls_payload_size;
269 
270 	memset(&rls_payload, 0, sizeof (rls_payload));
271 	rls_payload_size = sizeof (rls_payload);
272 	status = HBA_SendRLS(handle, hbaPortWWN, destWWN,
273 	    &rls_payload, &rls_payload_size);
274 	if (status != HBA_STATUS_OK) {
275 		fprintf(stderr, gettext("Error: SendRLS failed for %016llx\n"),
276 		    wwnConversion(destWWN.wwn));
277 	} else {
278 		printPortStat(&rls_payload);
279 	}
280 }
281 
282 int
283 printHBANPIVPortInfo(HBA_HANDLE handle, int portindex)
284 {
285 	HBA_PORTNPIVATTRIBUTES	portattrs;
286 	HBA_NPIVATTRIBUTES	npivattrs;
287 	HBA_STATUS		status;
288 	int			index;
289 	int			times = 0;
290 
291 	status = Sun_HBA_GetPortNPIVAttributes(handle, portindex, &portattrs);
292 	while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
293 	    status == HBA_STATUS_ERROR_BUSY) {
294 		(void) sleep(1);
295 		status = Sun_HBA_GetPortNPIVAttributes(
296 		    handle, portindex, &portattrs);
297 		if (times++ > HBA_MAX_RETRIES) {
298 			break;
299 		}
300 	}
301 
302 	if (status == HBA_STATUS_ERROR_NOT_SUPPORTED) {
303 		fprintf(stdout, gettext("\tNPIV Not Supported\n"));
304 		return (0);
305 	}
306 
307 	if (status != HBA_STATUS_OK) {
308 		fprintf(stderr,
309 		    gettext("Error: Failed to get port (%d) "
310 		    "npiv attributes reason: "), portindex);
311 		printStatus(status);
312 		fprintf(stderr, "\n");
313 		return (1);
314 	}
315 	if (portattrs.MaxNumberOfNPIVPorts) {
316 		fprintf(stdout, gettext("\tMax NPIV Ports: %d\n"),
317 		    portattrs.MaxNumberOfNPIVPorts);
318 	} else {
319 		fprintf(stdout, gettext("\tNPIV Not Supported\n"));
320 		return (0);
321 	}
322 	fprintf(stdout, gettext("\tNPIV port list:\n"));
323 	for (index = 0; index < portattrs.NumberOfNPIVPorts; index++) {
324 		int times = 0;
325 		status = Sun_HBA_GetNPIVPortInfo(handle,
326 		    portindex, index, &npivattrs);
327 		while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
328 		    status == HBA_STATUS_ERROR_BUSY) {
329 			(void) sleep(1);
330 			status = Sun_HBA_GetNPIVPortInfo(handle,
331 			    portindex, index, &npivattrs);
332 			if (times++ > HBA_MAX_RETRIES) {
333 				break;
334 			}
335 		}
336 
337 		if (status != HBA_STATUS_OK) {
338 			fprintf(stderr,
339 			    gettext("Error: Failed to get npiv port (%d) "
340 			    "attributes reason: "), index);
341 			printStatus(status);
342 			fprintf(stderr, "\n");
343 			return (1);
344 		} else {
345 			fprintf(stdout,
346 			    gettext("\t  Virtual Port%d:\n"), index+1);
347 			fprintf(stdout, gettext("\t\tNode WWN: %016llx\n"),
348 			    wwnConversion(npivattrs.NodeWWN.wwn));
349 			fprintf(stdout, gettext("\t\tPort WWN: %016llx\n"),
350 			    wwnConversion(npivattrs.PortWWN.wwn));
351 		}
352 	}
353 	return (0);
354 }
355 
356 /*
357  * This function will process hba port, remote port and scsi-target information
358  * for the given handle.
359  *
360  * Arguments:
361  *	handle - a handle to a HBA that we will be processing
362  *	resourceType - resourceType flag
363  *		possible values include: HBA_PORT, REMOTE_PORT
364  *	flags - represents options passed in by the user
365  *
366  *  Return Value:
367  *	    0		sucessfully processed handle
368  *	    1		error has occured
369  */
370 static int
371 processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs, int portIndex,
372     HBA_PORTATTRIBUTES port, HBA_FCPTARGETMAPPINGV2 *map,
373     int resourceType, int flags, int mode)
374 {
375 	HBA_PORTATTRIBUTES	discPort;
376 	HBA_STATUS		status;
377 	int			discPortCount;
378 
379 	if (resourceType == HBA_PORT) {
380 		printHBAPortInfo(&port, &attrs, mode);
381 		if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
382 			printLinkStat(handle, port.PortWWN, port.PortWWN);
383 		}
384 		return (0);
385 	}
386 	/*
387 	 * process each of the remote targets from this hba port
388 	 */
389 	for (discPortCount = 0;
390 	    discPortCount < port.NumberofDiscoveredPorts;
391 	    discPortCount++) {
392 		status = HBA_GetDiscoveredPortAttributes(handle,
393 		    portIndex, discPortCount, &discPort);
394 		if (status != HBA_STATUS_OK) {
395 			fprintf(stderr,
396 			    gettext("Failed to get discovered port (%d)"
397 				    " attributes reason :"), discPortCount);
398 			printStatus(status);
399 			fprintf(stderr, "\n");
400 			continue;
401 		}
402 		if (resourceType == REMOTE_PORT) {
403 			handleRemotePort(handle, port.PortWWN, discPort.PortWWN,
404 			    &discPort);
405 			if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
406 			    printLinkStat(handle, port.PortWWN,
407 				discPort.PortWWN);
408 			}
409 			if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
410 				handleScsiTarget(handle, port.PortWWN,
411 				    discPort.PortWWN, map);
412 			}
413 		}
414 	}
415 	return (0);
416 }
417 
418 /*
419  * This function will process remote port information for the given handle.
420  *
421  * Arguments:
422  *	handle - a handle to a HBA that we will be processing
423  *	portWWN - the port WWN for the HBA port we will be issuing the SCSI
424  *	    ReportLUNS through
425  *	wwnCount - the number of wwns in wwn_argv
426  *	wwn_argv - argument vector of WWNs
427  */
428 static void
429 processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
430     HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags)
431 {
432 	int			remote_wwn_counter;
433 	uint64_t		remotePortWWN;
434 	HBA_WWN			myremotePortWWN;
435 	HBA_PORTATTRIBUTES	discPort;
436 	HBA_STATUS		status;
437 
438 	for (remote_wwn_counter = 0;
439 	    remote_wwn_counter < wwnCount;
440 	    remote_wwn_counter++) {
441 		int times = 0;
442 		sscanf(wwn_argv[remote_wwn_counter], "%016llx",
443 		    &remotePortWWN);
444 		remotePortWWN = htonll(remotePortWWN);
445 		memcpy(myremotePortWWN.wwn, &remotePortWWN,
446 		    sizeof (remotePortWWN));
447 		memset(&discPort, 0, sizeof (discPort));
448 		status = HBA_GetPortAttributesByWWN(handle, myremotePortWWN,
449 		    &discPort);
450 		while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
451 		    status == HBA_STATUS_ERROR_BUSY) {
452 			(void) sleep(1);
453 			status = HBA_GetPortAttributesByWWN(handle,
454 			    myremotePortWWN, &discPort);
455 			if (times++ > HBA_MAX_RETRIES) {
456 				break;
457 			}
458 		}
459 		if (status != HBA_STATUS_OK) {
460 			fprintf(stderr, gettext("HBA_GetPortAttributesByWWN "
461 				    "failed: reason: "));
462 			printStatus(status);
463 			fprintf(stderr, "\n");
464 			continue;
465 		}
466 		handleRemotePort(handle, portWWN, myremotePortWWN, &discPort);
467 		if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
468 			printLinkStat(handle, portWWN, myremotePortWWN);
469 		}
470 		if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
471 			handleScsiTarget(handle, portWWN,
472 			    myremotePortWWN, map);
473 		}
474 	}
475 }
476 
477 /*
478  * This function handles printing Scsi target information for remote ports
479  *
480  * Arguments:
481  *	handle - a handle to a HBA that we will be processing
482  *	hbaPortWWN - the port WWN for the HBA port through which the SCSI call
483  *	    is being sent
484  *	scsiTargetWWN - target port WWN of the remote target the SCSI call is
485  *	    being sent to
486  *	map - a pointer to the target mapping structure for the given HBA port
487  */
488 static void
489 handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN scsiTargetWWN,
490     HBA_FCPTARGETMAPPINGV2 *map)
491 {
492 	HBA_STATUS		    status;
493 	struct scsi_inquiry	    inq;
494 	struct scsi_extended_sense  sense;
495 	HBA_UINT32		    responseSize, senseSize = 0;
496 	HBA_UINT8		    inq_status;
497 	uchar_t			    raw_luns[DEFAULT_LUN_LENGTH], *lun_string;
498 	HBA_UINT8		    rep_luns_status;
499 	rep_luns_rsp_t		    *lun_resp;
500 	uint64_t		    fcLUN;
501 	int			    lunNum, numberOfLun, lunCount, count;
502 	uint32_t		    lunlength, tmp_lunlength;
503 
504 	responseSize = DEFAULT_LUN_LENGTH;
505 	senseSize = sizeof (struct scsi_extended_sense);
506 	memset(&sense, 0, sizeof (sense));
507 	status = HBA_ScsiReportLUNsV2(handle, hbaPortWWN,
508 	    scsiTargetWWN, (void *)raw_luns, &responseSize,
509 	    &rep_luns_status, (void *)&sense, &senseSize);
510 	/*
511 	 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
512 	 * a remote HBA and move on
513 	 */
514 	if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
515 		return;
516 	} else if (status != HBA_STATUS_OK) {
517 		fprintf(stderr, gettext("Error has occured. "
518 			    "HBA_ScsiReportLUNsV2 failed.  reason "));
519 		printStatus(status);
520 		fprintf(stderr, "\n");
521 		return;
522 	}
523 	lun_resp = (rep_luns_rsp_t *)raw_luns;
524 	memcpy(&tmp_lunlength, &(lun_resp->length), sizeof (tmp_lunlength));
525 	lunlength = htonl(tmp_lunlength);
526 	memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
527 	for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
528 		/*
529 		 * now issue standard inquiry to get Vendor
530 		 * and product information
531 		 */
532 		responseSize = sizeof (struct scsi_inquiry);
533 		senseSize = sizeof (struct scsi_extended_sense);
534 		memset(&inq, 0, sizeof (struct scsi_inquiry));
535 		memset(&sense, 0, sizeof (sense));
536 		fcLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
537 		status = HBA_ScsiInquiryV2(
538 			handle,
539 			hbaPortWWN,
540 			scsiTargetWWN,
541 			fcLUN,
542 			0, /* EVPD */
543 			0,
544 			&inq, &responseSize,
545 			&inq_status,
546 			&sense, &senseSize);
547 		if (status != HBA_STATUS_OK) {
548 		    fprintf(stderr, gettext("Not able to issue Inquiry.\n"));
549 		    printStatus(status);
550 		    fprintf(stderr, "\n");
551 		    strcpy(inq.inq_vid, "Unknown");
552 		    strcpy(inq.inq_pid, "Unknown");
553 		}
554 		if (map != NULL) {
555 			for (count = 0; count < map->NumberOfEntries; count++) {
556 			    if ((memcmp(map->entry[count].FcpId.PortWWN.wwn,
557 						    scsiTargetWWN.wwn,
558 						    sizeof (scsiTargetWWN.wwn))
559 					    == 0) &&
560 				    (memcmp(&(map->entry[count].FcpId.FcpLun),
561 					    &fcLUN, sizeof (fcLUN)) == 0)) {
562 				printLUNInfo(&inq,
563 				    map->entry[count].ScsiId.ScsiOSLun,
564 				    map->entry[count].ScsiId.OSDeviceName);
565 				    break;
566 			    }
567 			}
568 			if (count == map->NumberOfEntries) {
569 				lun_string = lun_resp->lun[lunCount].val;
570 				lunNum = ((lun_string[0] & 0x3F) << 8) |
571 				    lun_string[1];
572 				printLUNInfo(&inq, lunNum, "Unknown");
573 			}
574 		} else {
575 			/* Not able to get any target mapping information */
576 			lun_string = lun_resp->lun[lunCount].val;
577 			lunNum = ((lun_string[0] & 0x3F) << 8) |
578 			    lun_string[1];
579 			printLUNInfo(&inq, lunNum, "Unknown");
580 		}
581 	}
582 }
583 
584 /*
585  * function to handle the list remoteport command
586  *
587  * Arguments:
588  *	wwnCount - the number of wwns in wwn_argv
589  *	    if wwnCount == 0, then print information on all
590  *		remote ports.  wwn_argv will not be used in this case
591  *	    if wwnCount > 0, then print information for the WWNs
592  *		given in wwn_argv
593  *	wwn_argv - argument vector of WWNs
594  *	options - any options specified by the caller
595  *
596  * returns:
597  *	0	if successful
598  *	1	otherwise
599  */
600 int
601 fc_util_list_remoteport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
602 {
603 	HBA_STATUS		status;
604 	HBA_FCPTARGETMAPPINGV2	*map = NULL;
605 	HBA_PORTATTRIBUTES	port;
606 	HBA_ADAPTERATTRIBUTES	attrs;
607 	HBA_HANDLE		handle;
608 	uint64_t		hbaPortWWN;
609 	HBA_WWN			myhbaPortWWN;
610 	int			processHBA_flags = 0, portCount = 0;
611 	int			mode;
612 
613 	/* grab the hba port wwn from the -p option */
614 	for (; options->optval; options++) {
615 		if (options->optval == 'p') {
616 			sscanf(options->optarg, "%016llx",
617 			    &hbaPortWWN);
618 		} else if (options->optval == 's') {
619 			processHBA_flags |= PRINT_SCSI_TARGET;
620 		} else if (options->optval == 'l') {
621 			processHBA_flags |= PRINT_LINKSTAT;
622 		} else {
623 			fprintf(stderr, gettext("Error: Illegal option: %c.\n"),
624 			    options->optval);
625 			return (1);
626 		}
627 	}
628 	/*
629 	 * -h option was not specified, this should not happen either.
630 	 * cmdparse should catch this problem, but checking anyways
631 	 */
632 	if (hbaPortWWN == 0) {
633 		fprintf(stderr,
634 		    gettext("Error: -p option was not specified.\n"));
635 		return (1);
636 	}
637 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
638 		fprintf(stderr,
639 		    gettext("Failed to load FC-HBA common library\n"));
640 		printStatus(status);
641 		fprintf(stderr, "\n");
642 		return (1);
643 	}
644 	hbaPortWWN = htonll(hbaPortWWN);
645 	memcpy(myhbaPortWWN.wwn, &hbaPortWWN, sizeof (hbaPortWWN));
646 	if ((status = HBA_OpenAdapterByWWN(&handle, myhbaPortWWN))
647 	    != HBA_STATUS_OK) {
648 		status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myhbaPortWWN);
649 		if (status != HBA_STATUS_OK) {
650 		    fprintf(stderr,
651 			gettext("Error: Failed to open adapter port. Reason "));
652 			printStatus(status);
653 		    fprintf(stderr, "\n");
654 		    HBA_FreeLibrary();
655 		    return (1);
656 		} else {
657 		    if ((processHBA_flags & PRINT_SCSI_TARGET) ==
658 			PRINT_SCSI_TARGET) {
659 			fprintf(stderr, gettext(
660 			    "Error: Unsupported option for target mode: %c.\n"),
661 			    's');
662 			HBA_FreeLibrary();
663 			return (1);
664 		    }
665 		    mode = TARGET_MODE;
666 		}
667 	} else {
668 	    mode = INITIATOR_MODE;
669 	}
670 
671 	if ((processHBA_flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
672 		getTargetMapping(handle, myhbaPortWWN, &map);
673 	}
674 	if (wwnCount == 0) {
675 		/* get adapater attributes for the given handle */
676 		memset(&attrs, 0, sizeof (attrs));
677 		memset(&port, 0, sizeof (port));
678 		if (retrieveAttrs(handle, myhbaPortWWN, &attrs, &port,
679 			    &portCount) != 0) {
680 			if (map != NULL) {
681 				free(map);
682 			}
683 			HBA_CloseAdapter(handle);
684 			HBA_FreeLibrary();
685 			return (1);
686 		}
687 		processHBA(handle, attrs, portCount, port, map, REMOTE_PORT,
688 		    processHBA_flags, mode);
689 	} else {
690 		processRemotePort(handle, myhbaPortWWN, map, wwnCount,
691 		    wwn_argv, processHBA_flags);
692 	}
693 	if (map != NULL) {
694 		free(map);
695 	}
696 	HBA_CloseAdapter(handle);
697 	HBA_FreeLibrary();
698 	return (0);
699 }
700 
701 /*
702  * process the hbaport object
703  *
704  * Arguments:
705  *	wwnCount - count of the number of WWNs in wwn_argv
706  *	    if wwnCount > 0, then we will only print information for
707  *		the hba ports listed in wwn_argv
708  *	    if wwnCount == 0, then we will print information on all hba ports
709  *	wwn_argv - argument array of hba port WWNs
710  *	options - any options specified by the caller
711  *
712  * returns:
713  *	0	if successful
714  *	1	otherwise
715  */
716 int
717 fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
718 {
719 	int	port_wwn_counter, numAdapters = 0, numTgtAdapters = 0, i;
720 	HBA_STATUS		status;
721 	char			adapterName[256];
722 	HBA_HANDLE		handle;
723 	uint64_t		hbaWWN;
724 	HBA_WWN			myWWN;
725 	int			processHBA_flags = 0;
726 	HBA_PORTATTRIBUTES	port;
727 	HBA_ADAPTERATTRIBUTES	attrs;
728 	int			portIndex = 0, err_cnt = 0;
729 	int			mode;
730 
731 	/* process each of the options */
732 	for (; options->optval; options++) {
733 		if (options->optval == 'l') {
734 			processHBA_flags |= PRINT_LINKSTAT;
735 		} else if (options->optval == 'i') {
736 			processHBA_flags |= PRINT_INITIATOR;
737 		} else if (options->optval == 't') {
738 			processHBA_flags |= PRINT_TARGET;
739 		}
740 	}
741 
742 	/*
743 	 * Print both initiator and target if no initiator/target flag
744 	 * specified.
745 	 */
746 	if (((processHBA_flags & PRINT_INITIATOR) == 0) &&
747 	    ((processHBA_flags & PRINT_TARGET) == 0)) {
748 	    processHBA_flags |= PRINT_INITIATOR | PRINT_TARGET;
749 	}
750 
751 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
752 		fprintf(stderr,
753 		    gettext("Failed to load FC-HBA common library\n"));
754 		printStatus(status);
755 		fprintf(stderr, "\n");
756 		return (1);
757 	}
758 	if (wwnCount > 0) {
759 		/* list only ports given in wwn_argv */
760 		for (port_wwn_counter = 0;
761 		    port_wwn_counter < wwnCount;
762 		    port_wwn_counter++) {
763 			sscanf(wwn_argv[port_wwn_counter], "%016llx", &hbaWWN);
764 			hbaWWN = htonll(hbaWWN);
765 			memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN));
766 			/* first check to see if it is an initiator port. */
767 			if ((processHBA_flags & PRINT_INITIATOR) ==
768 			    PRINT_INITIATOR) {
769 			    int times = 0;
770 			    status = HBA_OpenAdapterByWWN(&handle, myWWN);
771 			    while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
772 				status == HBA_STATUS_ERROR_BUSY) {
773 				(void) sleep(1);
774 				status = HBA_OpenAdapterByWWN(&handle, myWWN);
775 				if (times++ > HBA_MAX_RETRIES) {
776 					break;
777 				}
778 			    }
779 			    if (status != HBA_STATUS_OK) {
780 				/* now see if it is a target mode FC port */
781 				if ((processHBA_flags & PRINT_TARGET) ==
782 				    PRINT_TARGET) {
783 				    status =
784 				    Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN);
785 				    if (status != HBA_STATUS_OK) {
786 					fprintf(stderr,
787 					    gettext(
788 					    "Error: HBA port %s: not found\n"),
789 					    wwn_argv[port_wwn_counter]);
790 					    err_cnt++;
791 					continue;
792 				    } else {
793 					/* set the port mode. */
794 					mode = TARGET_MODE;
795 				    }
796 				} else {
797 				    fprintf(stderr,
798 					gettext(
799 					    "Error: HBA port %s: not found\n"),
800 					    wwn_argv[port_wwn_counter]);
801 					    err_cnt++;
802 					continue;
803 				}
804 			    } else {
805 				/* set the port mode. */
806 				mode = INITIATOR_MODE;
807 			    }
808 			/* try target mode discovery if print target is set. */
809 			} else if ((processHBA_flags & PRINT_TARGET) ==
810 				PRINT_TARGET) {
811 			    status =
812 				Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN);
813 			    if (status != HBA_STATUS_OK) {
814 				fprintf(stderr, gettext(
815 				    "Error: HBA port %s: not found\n"),
816 				    wwn_argv[port_wwn_counter]);
817 				    err_cnt++;
818 				continue;
819 			    } else {
820 				/* set the port mode. */
821 				mode = TARGET_MODE;
822 			    }
823 			} else {
824 			    /* should not get here. */
825 			    fprintf(stderr, gettext(
826 				"Error: HBA port %s: not found\n"),
827 				wwn_argv[port_wwn_counter]);
828 			    err_cnt++;
829 			    continue;
830 			}
831 			memset(&attrs, 0, sizeof (attrs));
832 			memset(&port, 0, sizeof (port));
833 			if (retrieveAttrs(handle, myWWN, &attrs, &port,
834 				    &portIndex) != 0) {
835 				HBA_CloseAdapter(handle);
836 				continue;
837 			}
838 			processHBA(handle, attrs, portIndex, port, NULL,
839 			    HBA_PORT, processHBA_flags, mode);
840 			if (printHBANPIVPortInfo(handle, portIndex)
841 			    != 0) {
842 				err_cnt++;
843 			}
844 			HBA_CloseAdapter(handle);
845 		}
846 	} else {
847 		/*
848 		 * if PRINT_INITIATOR is specified, get the list of initiator
849 		 * mod port.
850 		 */
851 		if ((processHBA_flags & PRINT_INITIATOR) == PRINT_INITIATOR) {
852 		    numAdapters = HBA_GetNumberOfAdapters();
853 		    if ((numAdapters == 0) &&
854 			((processHBA_flags & ~PRINT_INITIATOR) == 0)) {
855 			fprintf(stdout, gettext("No Adapters Found.\n"));
856 		    }
857 		    for (i = 0; i < numAdapters; i++) {
858 			int times = 0;
859 			status = HBA_GetAdapterName(i, adapterName);
860 			if (status != HBA_STATUS_OK) {
861 				fprintf(stderr, gettext(
862 				    "failed to get adapter %d. Reason: "), i);
863 				printStatus(status);
864 				fprintf(stderr, "\n");
865 				continue;
866 			}
867 			if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
868 				fprintf(stderr, gettext(
869 					    "Failed to open adapter %s.\n"),
870 				    adapterName);
871 				continue;
872 			}
873 			/* get adapater attributes for the given handle */
874 			memset(&attrs, 0, sizeof (attrs));
875 			status =
876 			    Sun_HBA_NPIVGetAdapterAttributes(handle,
877 			    &attrs);
878 			while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
879 			    status == HBA_STATUS_ERROR_BUSY) &&
880 			    times++ < HBA_MAX_RETRIES) {
881 				(void) sleep(1);
882 				status =
883 				    Sun_HBA_NPIVGetAdapterAttributes(handle,
884 				    &attrs);
885 				if (status == HBA_STATUS_OK) {
886 					break;
887 				}
888 			}
889 			if (status != HBA_STATUS_OK) {
890 				fprintf(stderr,
891 				    gettext("Failed to get adapter attributes "
892 					    "handle(%d) Reason: "), handle);
893 				printStatus(status);
894 				fprintf(stderr, "\n");
895 				HBA_CloseAdapter(handle);
896 				continue;
897 			}
898 
899 			/* process each port on the given adatpter */
900 			for (portIndex = 0;
901 			    portIndex < attrs.NumberOfPorts;
902 			    portIndex++) {
903 				memset(&port, 0, sizeof (port));
904 				if ((status = HBA_GetAdapterPortAttributes(
905 						    handle, portIndex, &port))
906 				    != HBA_STATUS_OK) {
907 					/*
908 					 * not able to get port attributes.
909 					 * print out error * message and move
910 					 * on to the next port
911 					 */
912 					fprintf(stderr,
913 					    gettext("Error: Failed to get port "
914 						    "(%d) attributes reason: "),
915 					    portIndex);
916 					printStatus(status);
917 					fprintf(stderr, "\n");
918 					continue;
919 				}
920 				processHBA(handle, attrs, portIndex, port,
921 				    NULL, HBA_PORT, processHBA_flags,
922 				    INITIATOR_MODE);
923 				if (printHBANPIVPortInfo(handle, portIndex)
924 				    != 0) {
925 					err_cnt++;
926 				}
927 			}
928 			HBA_CloseAdapter(handle);
929 		    }
930 		}
931 
932 		/*
933 		 * Get the info on the target mode FC port if PRINT_TARGET
934 		 * is specified.
935 		 */
936 		if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) {
937 		    numTgtAdapters = Sun_HBA_GetNumberOfTgtAdapters();
938 		    if (numTgtAdapters == 0 && numAdapters == 0) {
939 			fprintf(stdout,
940 			    gettext("No Adapters Found.\n"));
941 		    }
942 		    for (i = 0; i < numTgtAdapters; i++) {
943 			status = Sun_HBA_GetTgtAdapterName(i, adapterName);
944 			if (status != HBA_STATUS_OK) {
945 			    fprintf(stderr, gettext(
946 				"failed to get adapter %d. Reason: "), i);
947 			    printStatus(status);
948 			    fprintf(stderr, "\n");
949 			    continue;
950 			}
951 			if ((handle = Sun_HBA_OpenTgtAdapter(adapterName))
952 			    == 0) {
953 			    fprintf(stderr, gettext(
954 				"Failed to open adapter %s.\n"), adapterName);
955 			    continue;
956 			}
957 			/* get adapater attributes for the given handle */
958 			memset(&attrs, 0, sizeof (attrs));
959 			if ((status = HBA_GetAdapterAttributes(handle, &attrs))
960 			    != HBA_STATUS_OK) {
961 				fprintf(stderr,
962 				    gettext("Failed to get target mode adapter"
963 					"attributes handle(%d) Reason: "),
964 					handle);
965 				printStatus(status);
966 				fprintf(stderr, "\n");
967 				continue;
968 			}
969 
970 			/* process each port on the given adatpter */
971 			for (portIndex = 0;
972 			    portIndex < attrs.NumberOfPorts;
973 			    portIndex++) {
974 				memset(&port, 0, sizeof (port));
975 				if ((status = HBA_GetAdapterPortAttributes(
976 						    handle, portIndex, &port))
977 				    != HBA_STATUS_OK) {
978 					/*
979 					 * not able to get port attributes.
980 					 * print out error * message and move
981 					 * on to the next port
982 					 */
983 					fprintf(stderr,
984 					    gettext("Error: Failed to get port "
985 						    "(%d) attributes reason: "),
986 					    portIndex);
987 					printStatus(status);
988 					fprintf(stderr, "\n");
989 					continue;
990 				}
991 				processHBA(handle, attrs, portIndex, port,
992 				    NULL, HBA_PORT, processHBA_flags,
993 				    TARGET_MODE);
994 			}
995 		    HBA_CloseAdapter(handle);
996 		}
997 	    }
998 	}
999 
1000 	HBA_FreeLibrary();
1001 
1002 	/*
1003 	 * print additional error msg for partial failure when more than
1004 	 * one wwn is specified.
1005 	 */
1006 	if (err_cnt != 0) {
1007 	    if (wwnCount > 1) {
1008 		if (err_cnt == wwnCount) {
1009 		    fprintf(stderr, gettext(
1010 		    "Error: All specified HBA ports are not found\n"));
1011 		} else {
1012 		    fprintf(stderr, gettext(
1013 		    "Error: Some of specified HBA ports are not found\n"));
1014 		}
1015 	    }
1016 	    return (1);
1017 	}
1018 
1019 	return (0);
1020 }
1021 
1022 /*
1023  * Search the existing device list
1024  *
1025  * Take one of two actions:
1026  *
1027  * Add an entry if an entry doesn't exist
1028  * Add WWN data to it if an entry does exist
1029  *
1030  * Arguments:
1031  *	devList - OS device path list
1032  *	map - target mapping data
1033  *	index - index into target mapping data
1034  *	initiatorPortWWN - HBA port WWN
1035  *	verbose - boolean indicating whether to get additional data
1036  *
1037  * returns:
1038  *	none
1039  */
1040 static void
1041 searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry,
1042 HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose)
1043 {
1044 	discoveredDevice *discoveredDevList, *newDevice;
1045 	portWWNList *WWNList, *newWWN;
1046 	tgtPortWWNList *newTgtWWN;
1047 	boolean_t foundDevice = B_FALSE, foundWWN;
1048 	struct scsi_inquiry	    inq;
1049 	struct scsi_extended_sense  sense;
1050 	HBA_UINT32		    responseSize, senseSize = 0;
1051 	HBA_UINT8		    inq_status;
1052 	HBA_STATUS		status;
1053 
1054 	for (discoveredDevList = *devList; discoveredDevList != NULL;
1055 	    discoveredDevList = discoveredDevList->next) {
1056 		if (strcmp(entry.ScsiId.OSDeviceName,
1057 		    discoveredDevList->OSDeviceName) == 0) {
1058 			/*
1059 			 * if only device names are requested,
1060 			 * no reason to go any further
1061 			 */
1062 			if (verbose == B_FALSE) {
1063 				return;
1064 			}
1065 			foundDevice = B_TRUE;
1066 			break;
1067 		}
1068 	}
1069 	if (foundDevice == B_TRUE) {
1070 		/* add initiator Port WWN if it doesn't exist */
1071 		for (WWNList = discoveredDevList->HBAPortWWN,
1072 		    foundWWN = B_FALSE; WWNList != NULL;
1073 		    WWNList = WWNList->next) {
1074 			if (memcmp((void *)&(WWNList->portWWN),
1075 			    (void *)&initiatorPortWWN,
1076 			    sizeof (HBA_WWN)) == 0) {
1077 				foundWWN = B_TRUE;
1078 				break;
1079 			}
1080 		}
1081 		if (discoveredDevList->inqSuccess == B_FALSE) {
1082 			responseSize = sizeof (struct scsi_inquiry);
1083 			senseSize = sizeof (struct scsi_extended_sense);
1084 			memset(&inq, 0, sizeof (struct scsi_inquiry));
1085 			memset(&sense, 0, sizeof (sense));
1086 			status = HBA_ScsiInquiryV2(
1087 			    handle,
1088 			    initiatorPortWWN,
1089 			    entry.FcpId.PortWWN,
1090 			    entry.FcpId.FcpLun,
1091 			    0, /* CDB Byte 1 */
1092 			    0, /* CDB Byte 2 */
1093 			    &inq, &responseSize,
1094 			    &inq_status,
1095 			    &sense, &senseSize);
1096 			if (status == HBA_STATUS_OK) {
1097 				memcpy(discoveredDevList->VID, inq.inq_vid,
1098 				    sizeof (discoveredDevList->VID));
1099 				memcpy(discoveredDevList->PID, inq.inq_pid,
1100 				    sizeof (discoveredDevList->PID));
1101 				discoveredDevList->dType = inq.inq_dtype;
1102 				discoveredDevList->inqSuccess = B_TRUE;
1103 			}
1104 		}
1105 
1106 		if (foundWWN == B_FALSE) {
1107 			newWWN = (portWWNList *)calloc(1, sizeof (portWWNList));
1108 			if (newWWN == NULL) {
1109 				perror("Out of memory");
1110 				exit(1);
1111 			}
1112 
1113 			/* insert at head */
1114 			newWWN->next = discoveredDevList->HBAPortWWN;
1115 			discoveredDevList->HBAPortWWN = newWWN;
1116 			memcpy((void *)&(newWWN->portWWN),
1117 			    (void *)&initiatorPortWWN,
1118 			    sizeof (newWWN->portWWN));
1119 			/* add Target Port */
1120 			newWWN->tgtPortWWN = (tgtPortWWNList *)calloc(1,
1121 			    sizeof (tgtPortWWNList));
1122 			if (newWWN->tgtPortWWN == NULL) {
1123 				perror("Out of memory");
1124 				exit(1);
1125 			}
1126 
1127 			memcpy((void *)&(newWWN->tgtPortWWN->portWWN),
1128 			    (void *)&(entry.FcpId.PortWWN),
1129 			    sizeof (newWWN->tgtPortWWN->portWWN));
1130 			/* Set LUN data */
1131 			newWWN->tgtPortWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
1132 		} else { /* add it to existing */
1133 			newTgtWWN = (tgtPortWWNList *)calloc(1,
1134 			    sizeof (tgtPortWWNList));
1135 			if (newTgtWWN == NULL) {
1136 				perror("Out of memory");
1137 				exit(1);
1138 			}
1139 			/* insert at head */
1140 			newTgtWWN->next = WWNList->tgtPortWWN;
1141 			WWNList->tgtPortWWN = newTgtWWN;
1142 			memcpy((void *)&(newTgtWWN->portWWN),
1143 			    (void *)&(entry.FcpId.PortWWN),
1144 			    sizeof (newTgtWWN->portWWN));
1145 			/* Set LUN data */
1146 			newTgtWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
1147 		}
1148 	} else { /* add new entry */
1149 		newDevice = (discoveredDevice *)calloc(1,
1150 		    sizeof (discoveredDevice));
1151 		if (newDevice == NULL) {
1152 			perror("Out of memory");
1153 			exit(1);
1154 		}
1155 		newDevice->next = *devList; /* insert at head */
1156 		*devList = newDevice; /* set new head */
1157 
1158 		/* Copy device name */
1159 		strncpy(newDevice->OSDeviceName, entry.ScsiId.OSDeviceName,
1160 		    sizeof (newDevice->OSDeviceName) - 1);
1161 
1162 		/*
1163 		 * if only device names are requested,
1164 		 * no reason to go any further
1165 		 */
1166 		if (verbose == B_FALSE) {
1167 			return;
1168 		}
1169 
1170 		/*
1171 		 * copy WWN data
1172 		 */
1173 		newDevice->HBAPortWWN = (portWWNList *)calloc(1,
1174 		    sizeof (portWWNList));
1175 		if (newDevice->HBAPortWWN == NULL) {
1176 			perror("Out of memory");
1177 			exit(1);
1178 		}
1179 		memcpy((void *)&(newDevice->HBAPortWWN->portWWN),
1180 		    (void *)&initiatorPortWWN, sizeof (newWWN->portWWN));
1181 
1182 		newDevice->HBAPortWWN->tgtPortWWN =
1183 		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
1184 		if (newDevice->HBAPortWWN->tgtPortWWN == NULL) {
1185 			perror("Out of memory");
1186 			exit(1);
1187 		}
1188 
1189 		memcpy((void *)&(newDevice->HBAPortWWN->tgtPortWWN->portWWN),
1190 		    (void *)&(entry.FcpId.PortWWN),
1191 		    sizeof (newDevice->HBAPortWWN->tgtPortWWN->portWWN));
1192 
1193 		/* Set LUN data */
1194 		newDevice->HBAPortWWN->tgtPortWWN->scsiOSLun =
1195 		    entry.ScsiId.ScsiOSLun;
1196 
1197 		responseSize = sizeof (struct scsi_inquiry);
1198 		senseSize = sizeof (struct scsi_extended_sense);
1199 		memset(&inq, 0, sizeof (struct scsi_inquiry));
1200 		memset(&sense, 0, sizeof (sense));
1201 		status = HBA_ScsiInquiryV2(
1202 		    handle,
1203 		    initiatorPortWWN,
1204 		    entry.FcpId.PortWWN,
1205 		    entry.FcpId.FcpLun,
1206 		    0, /* CDB Byte 1 */
1207 		    0, /* CDB Byte 2 */
1208 		    &inq, &responseSize,
1209 		    &inq_status,
1210 		    &sense, &senseSize);
1211 		if (status != HBA_STATUS_OK) {
1212 			/* initialize VID/PID/dType as "Unknown" */
1213 			strcpy(newDevice->VID, "Unknown");
1214 			strcpy(newDevice->PID, "Unknown");
1215 			newDevice->dType = DTYPE_UNKNOWN;
1216 			/* initialize inq status */
1217 			newDevice->inqSuccess = B_FALSE;
1218 		} else {
1219 			memcpy(newDevice->VID, inq.inq_vid,
1220 			    sizeof (newDevice->VID));
1221 			memcpy(newDevice->PID, inq.inq_pid,
1222 			    sizeof (newDevice->PID));
1223 			newDevice->dType = inq.inq_dtype;
1224 			/* initialize inq status */
1225 			newDevice->inqSuccess = B_TRUE;
1226 		}
1227 	}
1228 }
1229 
1230 
1231 /*
1232  * process the logical-unit object
1233  *
1234  * Arguments:
1235  *	luCount - count of the number of device paths in paths_argv
1236  *	    if pathCount > 0, then we will only print information for
1237  *		the device paths listed in paths_argv
1238  *	    if pathCount == 0, then we will print information on all device
1239  *	        paths
1240  *	luArgv - argument array of device paths
1241  *	options - any options specified by the caller
1242  *
1243  * returns:
1244  *	0	if successful
1245  *	> 0	otherwise
1246  */
1247 int
1248 fc_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
1249 {
1250 	int			pathCtr, numAdapters, i, count;
1251 	HBA_STATUS		status;
1252 	char			adapterName[256];
1253 	HBA_HANDLE		handle;
1254 	HBA_PORTATTRIBUTES	port;
1255 	HBA_ADAPTERATTRIBUTES	attrs;
1256 	int			portIndex = 0;
1257 	int			ret = 0;
1258 	boolean_t		verbose = B_FALSE;
1259 	HBA_FCPTARGETMAPPINGV2	*map = NULL;
1260 	discoveredDevice	*devListWalk, *devList = NULL;
1261 	boolean_t		pathFound;
1262 
1263 	/* process each of the options */
1264 	for (; options->optval; options++) {
1265 		if (options->optval == 'v') {
1266 			verbose = B_TRUE;
1267 		}
1268 	}
1269 
1270 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
1271 		fprintf(stderr,
1272 		    gettext("Failed to load FC-HBA common library\n"));
1273 		printStatus(status);
1274 		fprintf(stderr, "\n");
1275 		return (1);
1276 	}
1277 	/*
1278 	 * Retrieve all device paths. We'll need to traverse the list
1279 	 * until we find the input paths or all paths if none were given. We
1280 	 * cannot print as we go since there can be duplicate paths returned
1281 	 */
1282 	numAdapters = HBA_GetNumberOfAdapters();
1283 	if (numAdapters == 0) {
1284 		return (0);
1285 	}
1286 	for (i = 0; i < numAdapters; i++) {
1287 		int times;
1288 		status = HBA_GetAdapterName(i, adapterName);
1289 		if (status != HBA_STATUS_OK) {
1290 			fprintf(stderr, gettext(
1291 			    "Failed to get adapter %d. Reason: "), i);
1292 			printStatus(status);
1293 			fprintf(stderr, "\n");
1294 			ret++;
1295 			continue;
1296 		}
1297 		if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
1298 			fprintf(stderr, gettext("Failed to open adapter %s\n"),
1299 			    adapterName);
1300 			ret++;
1301 			continue;
1302 		}
1303 		/* get adapter attributes for the given handle */
1304 		memset(&attrs, 0, sizeof (attrs));
1305 		times = 0;
1306 		status = HBA_GetAdapterAttributes(handle, &attrs);
1307 		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1308 		    status == HBA_STATUS_ERROR_BUSY) &&
1309 		    times++ < HBA_MAX_RETRIES) {
1310 			(void) sleep(1);
1311 			status = HBA_GetAdapterAttributes(handle, &attrs);
1312 			if (status == HBA_STATUS_OK) {
1313 				break;
1314 			}
1315 		}
1316 		if (status != HBA_STATUS_OK) {
1317 			fprintf(stderr,
1318 			    gettext("Failed to get adapter attributes "
1319 				    "handle(%d) Reason: "), handle);
1320 			printStatus(status);
1321 			fprintf(stderr, "\n");
1322 			ret++;
1323 			HBA_CloseAdapter(handle);
1324 			continue;
1325 		}
1326 
1327 		/* process each port on adapter */
1328 		for (portIndex = 0; portIndex < attrs.NumberOfPorts;
1329 		    portIndex++) {
1330 			memset(&port, 0, sizeof (port));
1331 			if ((status = HBA_GetAdapterPortAttributes(handle,
1332 			    portIndex, &port)) != HBA_STATUS_OK) {
1333 				/*
1334 				 * not able to get port attributes.
1335 				 * print out error message and move
1336 				 * on to the next port
1337 				 */
1338 				fprintf(stderr, gettext("Failed to get port "
1339 				    "(%d) attributes reason: "),
1340 				    portIndex);
1341 				printStatus(status);
1342 				fprintf(stderr, "\n");
1343 				ret++;
1344 				continue;
1345 			}
1346 
1347 			/* get OS Device Paths */
1348 			getTargetMapping(handle, port.PortWWN, &map);
1349 			if (map != NULL) {
1350 				for (count = 0; count < map->NumberOfEntries;
1351 				    count++) {
1352 					searchDevice(&devList,
1353 					    map->entry[count], port.PortWWN,
1354 					    handle, verbose);
1355 				}
1356 			}
1357 		}
1358 		HBA_CloseAdapter(handle);
1359 	}
1360 	HBA_FreeLibrary();
1361 
1362 	if (luCount == 0) {
1363 		/* list all paths */
1364 		for (devListWalk = devList; devListWalk != NULL;
1365 		    devListWalk = devListWalk->next) {
1366 			printOSDeviceNameInfo(devListWalk, verbose);
1367 		}
1368 	} else {
1369 		/*
1370 		 * list any paths not found first
1371 		 * this gives the user cleaner output
1372 		 */
1373 		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
1374 			for (devListWalk = devList, pathFound = B_FALSE;
1375 			    devListWalk != NULL;
1376 			    devListWalk = devListWalk->next) {
1377 				if (strcmp(devListWalk->OSDeviceName,
1378 				    luArgv[pathCtr]) == 0) {
1379 					pathFound = B_TRUE;
1380 				}
1381 			}
1382 			if (pathFound == B_FALSE) {
1383 				fprintf(stderr, "%s: no such path\n",
1384 				    luArgv[pathCtr]);
1385 				ret++;
1386 			}
1387 		}
1388 		/* list all paths requested in order requested */
1389 		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
1390 			for (devListWalk = devList; devListWalk != NULL;
1391 			    devListWalk = devListWalk->next) {
1392 				if (strcmp(devListWalk->OSDeviceName,
1393 				    luArgv[pathCtr]) == 0) {
1394 					printOSDeviceNameInfo(devListWalk,
1395 					    verbose);
1396 				}
1397 			}
1398 		}
1399 	}
1400 	return (ret);
1401 }
1402