xref: /illumos-gate/usr/src/cmd/fcinfo/fcinfo-list.c (revision 7a088f03b431bdffa96c3b2175964d4d38420caa)
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 2009 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 		if ((flags & PRINT_FCOE) == PRINT_FCOE &&
381 		    attrs.VendorSpecificID != 0xFC0E) {
382 			return (0);
383 		}
384 		printHBAPortInfo(&port, &attrs, mode);
385 		if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
386 			printLinkStat(handle, port.PortWWN, port.PortWWN);
387 		}
388 		return (0);
389 	}
390 	/*
391 	 * process each of the remote targets from this hba port
392 	 */
393 	for (discPortCount = 0;
394 	    discPortCount < port.NumberofDiscoveredPorts;
395 	    discPortCount++) {
396 		status = HBA_GetDiscoveredPortAttributes(handle,
397 		    portIndex, discPortCount, &discPort);
398 		if (status != HBA_STATUS_OK) {
399 			fprintf(stderr,
400 			    gettext("Failed to get discovered port (%d)"
401 				    " attributes reason :"), discPortCount);
402 			printStatus(status);
403 			fprintf(stderr, "\n");
404 			continue;
405 		}
406 		if (resourceType == REMOTE_PORT) {
407 			handleRemotePort(handle, port.PortWWN, discPort.PortWWN,
408 			    &discPort);
409 			if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
410 			    printLinkStat(handle, port.PortWWN,
411 				discPort.PortWWN);
412 			}
413 			if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
414 				handleScsiTarget(handle, port.PortWWN,
415 				    discPort.PortWWN, map);
416 			}
417 		}
418 	}
419 	return (0);
420 }
421 
422 /*
423  * This function will process remote port information for the given handle.
424  *
425  * Arguments:
426  *	handle - a handle to a HBA that we will be processing
427  *	portWWN - the port WWN for the HBA port we will be issuing the SCSI
428  *	    ReportLUNS through
429  *	wwnCount - the number of wwns in wwn_argv
430  *	wwn_argv - argument vector of WWNs
431  */
432 static void
433 processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
434     HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags)
435 {
436 	int			remote_wwn_counter;
437 	uint64_t		remotePortWWN;
438 	HBA_WWN			myremotePortWWN;
439 	HBA_PORTATTRIBUTES	discPort;
440 	HBA_STATUS		status;
441 
442 	for (remote_wwn_counter = 0;
443 	    remote_wwn_counter < wwnCount;
444 	    remote_wwn_counter++) {
445 		int times = 0;
446 		sscanf(wwn_argv[remote_wwn_counter], "%016llx",
447 		    &remotePortWWN);
448 		remotePortWWN = htonll(remotePortWWN);
449 		memcpy(myremotePortWWN.wwn, &remotePortWWN,
450 		    sizeof (remotePortWWN));
451 		memset(&discPort, 0, sizeof (discPort));
452 		status = HBA_GetPortAttributesByWWN(handle, myremotePortWWN,
453 		    &discPort);
454 		while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
455 		    status == HBA_STATUS_ERROR_BUSY) {
456 			(void) sleep(1);
457 			status = HBA_GetPortAttributesByWWN(handle,
458 			    myremotePortWWN, &discPort);
459 			if (times++ > HBA_MAX_RETRIES) {
460 				break;
461 			}
462 		}
463 		if (status != HBA_STATUS_OK) {
464 			fprintf(stderr, gettext("HBA_GetPortAttributesByWWN "
465 				    "failed: reason: "));
466 			printStatus(status);
467 			fprintf(stderr, "\n");
468 			continue;
469 		}
470 		handleRemotePort(handle, portWWN, myremotePortWWN, &discPort);
471 		if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
472 			printLinkStat(handle, portWWN, myremotePortWWN);
473 		}
474 		if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
475 			handleScsiTarget(handle, portWWN,
476 			    myremotePortWWN, map);
477 		}
478 	}
479 }
480 
481 /*
482  * This function handles printing Scsi target information for remote ports
483  *
484  * Arguments:
485  *	handle - a handle to a HBA that we will be processing
486  *	hbaPortWWN - the port WWN for the HBA port through which the SCSI call
487  *	    is being sent
488  *	scsiTargetWWN - target port WWN of the remote target the SCSI call is
489  *	    being sent to
490  *	map - a pointer to the target mapping structure for the given HBA port
491  */
492 static void
493 handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN scsiTargetWWN,
494     HBA_FCPTARGETMAPPINGV2 *map)
495 {
496 	HBA_STATUS		    status;
497 	struct scsi_inquiry	    inq;
498 	struct scsi_extended_sense  sense;
499 	HBA_UINT32		    responseSize, senseSize = 0;
500 	HBA_UINT8		    inq_status;
501 	uchar_t			    raw_luns[DEFAULT_LUN_LENGTH], *lun_string;
502 	HBA_UINT8		    rep_luns_status;
503 	rep_luns_rsp_t		    *lun_resp;
504 	uint64_t		    fcLUN;
505 	int			    lunNum, numberOfLun, lunCount, count;
506 	uint32_t		    lunlength, tmp_lunlength;
507 
508 	responseSize = DEFAULT_LUN_LENGTH;
509 	senseSize = sizeof (struct scsi_extended_sense);
510 	memset(&sense, 0, sizeof (sense));
511 	status = HBA_ScsiReportLUNsV2(handle, hbaPortWWN,
512 	    scsiTargetWWN, (void *)raw_luns, &responseSize,
513 	    &rep_luns_status, (void *)&sense, &senseSize);
514 	/*
515 	 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
516 	 * a remote HBA and move on
517 	 */
518 	if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
519 		return;
520 	} else if (status != HBA_STATUS_OK) {
521 		fprintf(stderr, gettext("Error has occured. "
522 			    "HBA_ScsiReportLUNsV2 failed.  reason "));
523 		printStatus(status);
524 		fprintf(stderr, "\n");
525 		return;
526 	}
527 	lun_resp = (rep_luns_rsp_t *)raw_luns;
528 	memcpy(&tmp_lunlength, &(lun_resp->length), sizeof (tmp_lunlength));
529 	lunlength = htonl(tmp_lunlength);
530 	memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
531 	for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
532 		/*
533 		 * now issue standard inquiry to get Vendor
534 		 * and product information
535 		 */
536 		responseSize = sizeof (struct scsi_inquiry);
537 		senseSize = sizeof (struct scsi_extended_sense);
538 		memset(&inq, 0, sizeof (struct scsi_inquiry));
539 		memset(&sense, 0, sizeof (sense));
540 		fcLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
541 		status = HBA_ScsiInquiryV2(
542 			handle,
543 			hbaPortWWN,
544 			scsiTargetWWN,
545 			fcLUN,
546 			0, /* EVPD */
547 			0,
548 			&inq, &responseSize,
549 			&inq_status,
550 			&sense, &senseSize);
551 		if (status != HBA_STATUS_OK) {
552 		    fprintf(stderr, gettext("Not able to issue Inquiry.\n"));
553 		    printStatus(status);
554 		    fprintf(stderr, "\n");
555 		    strcpy(inq.inq_vid, "Unknown");
556 		    strcpy(inq.inq_pid, "Unknown");
557 		}
558 		if (map != NULL) {
559 			for (count = 0; count < map->NumberOfEntries; count++) {
560 			    if ((memcmp(map->entry[count].FcpId.PortWWN.wwn,
561 						    scsiTargetWWN.wwn,
562 						    sizeof (scsiTargetWWN.wwn))
563 					    == 0) &&
564 				    (memcmp(&(map->entry[count].FcpId.FcpLun),
565 					    &fcLUN, sizeof (fcLUN)) == 0)) {
566 				printLUNInfo(&inq,
567 				    map->entry[count].ScsiId.ScsiOSLun,
568 				    map->entry[count].ScsiId.OSDeviceName);
569 				    break;
570 			    }
571 			}
572 			if (count == map->NumberOfEntries) {
573 				lun_string = lun_resp->lun[lunCount].val;
574 				lunNum = ((lun_string[0] & 0x3F) << 8) |
575 				    lun_string[1];
576 				printLUNInfo(&inq, lunNum, "Unknown");
577 			}
578 		} else {
579 			/* Not able to get any target mapping information */
580 			lun_string = lun_resp->lun[lunCount].val;
581 			lunNum = ((lun_string[0] & 0x3F) << 8) |
582 			    lun_string[1];
583 			printLUNInfo(&inq, lunNum, "Unknown");
584 		}
585 	}
586 }
587 
588 /*
589  * function to handle the list remoteport command
590  *
591  * Arguments:
592  *	wwnCount - the number of wwns in wwn_argv
593  *	    if wwnCount == 0, then print information on all
594  *		remote ports.  wwn_argv will not be used in this case
595  *	    if wwnCount > 0, then print information for the WWNs
596  *		given in wwn_argv
597  *	wwn_argv - argument vector of WWNs
598  *	options - any options specified by the caller
599  *
600  * returns:
601  *	0	if successful
602  *	1	otherwise
603  */
604 int
605 fc_util_list_remoteport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
606 {
607 	HBA_STATUS		status;
608 	HBA_FCPTARGETMAPPINGV2	*map = NULL;
609 	HBA_PORTATTRIBUTES	port;
610 	HBA_ADAPTERATTRIBUTES	attrs;
611 	HBA_HANDLE		handle;
612 	uint64_t		hbaPortWWN;
613 	HBA_WWN			myhbaPortWWN;
614 	int			processHBA_flags = 0, portCount = 0;
615 	int			mode;
616 
617 	/* grab the hba port wwn from the -p option */
618 	for (; options->optval; options++) {
619 		if (options->optval == 'p') {
620 			sscanf(options->optarg, "%016llx",
621 			    &hbaPortWWN);
622 		} else if (options->optval == 's') {
623 			processHBA_flags |= PRINT_SCSI_TARGET;
624 		} else if (options->optval == 'l') {
625 			processHBA_flags |= PRINT_LINKSTAT;
626 		} else {
627 			fprintf(stderr, gettext("Error: Illegal option: %c.\n"),
628 			    options->optval);
629 			return (1);
630 		}
631 	}
632 	/*
633 	 * -h option was not specified, this should not happen either.
634 	 * cmdparse should catch this problem, but checking anyways
635 	 */
636 	if (hbaPortWWN == 0) {
637 		fprintf(stderr,
638 		    gettext("Error: -p option was not specified.\n"));
639 		return (1);
640 	}
641 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
642 		fprintf(stderr,
643 		    gettext("Failed to load FC-HBA common library\n"));
644 		printStatus(status);
645 		fprintf(stderr, "\n");
646 		return (1);
647 	}
648 	hbaPortWWN = htonll(hbaPortWWN);
649 	memcpy(myhbaPortWWN.wwn, &hbaPortWWN, sizeof (hbaPortWWN));
650 	if ((status = HBA_OpenAdapterByWWN(&handle, myhbaPortWWN))
651 	    != HBA_STATUS_OK) {
652 		status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myhbaPortWWN);
653 		if (status != HBA_STATUS_OK) {
654 		    fprintf(stderr,
655 			gettext("Error: Failed to open adapter port. Reason "));
656 			printStatus(status);
657 		    fprintf(stderr, "\n");
658 		    HBA_FreeLibrary();
659 		    return (1);
660 		} else {
661 		    if ((processHBA_flags & PRINT_SCSI_TARGET) ==
662 			PRINT_SCSI_TARGET) {
663 			fprintf(stderr, gettext(
664 			    "Error: Unsupported option for target mode: %c.\n"),
665 			    's');
666 			HBA_FreeLibrary();
667 			return (1);
668 		    }
669 		    mode = TARGET_MODE;
670 		}
671 	} else {
672 	    mode = INITIATOR_MODE;
673 	}
674 
675 	if ((processHBA_flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
676 		getTargetMapping(handle, myhbaPortWWN, &map);
677 	}
678 	if (wwnCount == 0) {
679 		/* get adapater attributes for the given handle */
680 		memset(&attrs, 0, sizeof (attrs));
681 		memset(&port, 0, sizeof (port));
682 		if (retrieveAttrs(handle, myhbaPortWWN, &attrs, &port,
683 			    &portCount) != 0) {
684 			if (map != NULL) {
685 				free(map);
686 			}
687 			HBA_CloseAdapter(handle);
688 			HBA_FreeLibrary();
689 			return (1);
690 		}
691 		processHBA(handle, attrs, portCount, port, map, REMOTE_PORT,
692 		    processHBA_flags, mode);
693 	} else {
694 		processRemotePort(handle, myhbaPortWWN, map, wwnCount,
695 		    wwn_argv, processHBA_flags);
696 	}
697 	if (map != NULL) {
698 		free(map);
699 	}
700 	HBA_CloseAdapter(handle);
701 	HBA_FreeLibrary();
702 	return (0);
703 }
704 
705 /*
706  * process the hbaport object
707  *
708  * Arguments:
709  *	wwnCount - count of the number of WWNs in wwn_argv
710  *	    if wwnCount > 0, then we will only print information for
711  *		the hba ports listed in wwn_argv
712  *	    if wwnCount == 0, then we will print information on all hba ports
713  *	wwn_argv - argument array of hba port WWNs
714  *	options - any options specified by the caller
715  *
716  * returns:
717  *	0	if successful
718  *	1	otherwise
719  */
720 int
721 fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
722 {
723 	int	port_wwn_counter, numAdapters = 0, numTgtAdapters = 0, i;
724 	HBA_STATUS		status;
725 	char			adapterName[256];
726 	HBA_HANDLE		handle;
727 	uint64_t		hbaWWN;
728 	HBA_WWN			myWWN;
729 	int			processHBA_flags = 0;
730 	HBA_PORTATTRIBUTES	port;
731 	HBA_ADAPTERATTRIBUTES	attrs;
732 	int			portIndex = 0, err_cnt = 0;
733 	int			mode;
734 
735 	/* process each of the options */
736 	for (; options->optval; options++) {
737 		if (options->optval == 'l') {
738 			processHBA_flags |= PRINT_LINKSTAT;
739 		} else if (options->optval == 'i') {
740 			processHBA_flags |= PRINT_INITIATOR;
741 		} else if (options->optval == 't') {
742 			processHBA_flags |= PRINT_TARGET;
743 		} else if (options->optval == 'e') {
744 			processHBA_flags |= PRINT_FCOE;
745 		}
746 	}
747 
748 	/*
749 	 * Print both initiator and target if no initiator/target flag
750 	 * specified.
751 	 */
752 	if (((processHBA_flags & PRINT_INITIATOR) == 0) &&
753 	    ((processHBA_flags & PRINT_TARGET) == 0)) {
754 	    processHBA_flags |= PRINT_INITIATOR | PRINT_TARGET;
755 	}
756 
757 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
758 		fprintf(stderr,
759 		    gettext("Failed to load FC-HBA common library\n"));
760 		printStatus(status);
761 		fprintf(stderr, "\n");
762 		return (1);
763 	}
764 	if (wwnCount > 0) {
765 		/* list only ports given in wwn_argv */
766 		for (port_wwn_counter = 0;
767 		    port_wwn_counter < wwnCount;
768 		    port_wwn_counter++) {
769 			sscanf(wwn_argv[port_wwn_counter], "%016llx", &hbaWWN);
770 			hbaWWN = htonll(hbaWWN);
771 			memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN));
772 			/* first check to see if it is an initiator port. */
773 			if ((processHBA_flags & PRINT_INITIATOR) ==
774 			    PRINT_INITIATOR) {
775 			    int times = 0;
776 			    status = HBA_OpenAdapterByWWN(&handle, myWWN);
777 			    while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
778 				status == HBA_STATUS_ERROR_BUSY) {
779 				(void) sleep(1);
780 				status = HBA_OpenAdapterByWWN(&handle, myWWN);
781 				if (times++ > HBA_MAX_RETRIES) {
782 					break;
783 				}
784 			    }
785 			    if (status != HBA_STATUS_OK) {
786 				/* now see if it is a target mode FC port */
787 				if ((processHBA_flags & PRINT_TARGET) ==
788 				    PRINT_TARGET) {
789 				    status =
790 				    Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN);
791 				    if (status != HBA_STATUS_OK) {
792 					fprintf(stderr,
793 					    gettext(
794 					    "Error: HBA port %s: not found\n"),
795 					    wwn_argv[port_wwn_counter]);
796 					    err_cnt++;
797 					continue;
798 				    } else {
799 					/* set the port mode. */
800 					mode = TARGET_MODE;
801 				    }
802 				} else {
803 				    fprintf(stderr,
804 					gettext(
805 					    "Error: HBA port %s: not found\n"),
806 					    wwn_argv[port_wwn_counter]);
807 					    err_cnt++;
808 					continue;
809 				}
810 			    } else {
811 				/* set the port mode. */
812 				mode = INITIATOR_MODE;
813 			    }
814 			/* try target mode discovery if print target is set. */
815 			} else if ((processHBA_flags & PRINT_TARGET) ==
816 				PRINT_TARGET) {
817 			    status =
818 				Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN);
819 			    if (status != HBA_STATUS_OK) {
820 				fprintf(stderr, gettext(
821 				    "Error: HBA port %s: not found\n"),
822 				    wwn_argv[port_wwn_counter]);
823 				    err_cnt++;
824 				continue;
825 			    } else {
826 				/* set the port mode. */
827 				mode = TARGET_MODE;
828 			    }
829 			} else {
830 			    /* should not get here. */
831 			    fprintf(stderr, gettext(
832 				"Error: HBA port %s: not found\n"),
833 				wwn_argv[port_wwn_counter]);
834 			    err_cnt++;
835 			    continue;
836 			}
837 			memset(&attrs, 0, sizeof (attrs));
838 			memset(&port, 0, sizeof (port));
839 			if (retrieveAttrs(handle, myWWN, &attrs, &port,
840 				    &portIndex) != 0) {
841 				HBA_CloseAdapter(handle);
842 				continue;
843 			}
844 			processHBA(handle, attrs, portIndex, port, NULL,
845 			    HBA_PORT, processHBA_flags, mode);
846 			if ((processHBA_flags & PRINT_FCOE) != PRINT_FCOE &&
847 			    attrs.VendorSpecificID != 0xFC0E &&
848 			    printHBANPIVPortInfo(handle, portIndex) != 0) {
849 				err_cnt++;
850 			}
851 			HBA_CloseAdapter(handle);
852 		}
853 	} else {
854 		/*
855 		 * if PRINT_INITIATOR is specified, get the list of initiator
856 		 * mod port.
857 		 */
858 		if ((processHBA_flags & PRINT_INITIATOR) == PRINT_INITIATOR) {
859 		    numAdapters = HBA_GetNumberOfAdapters();
860 		    if ((numAdapters == 0) &&
861 			((processHBA_flags & ~PRINT_INITIATOR) == 0)) {
862 			fprintf(stdout, gettext("No Adapters Found.\n"));
863 		    }
864 		    for (i = 0; i < numAdapters; i++) {
865 			int times = 0;
866 			status = HBA_GetAdapterName(i, adapterName);
867 			if (status != HBA_STATUS_OK) {
868 				fprintf(stderr, gettext(
869 				    "failed to get adapter %d. Reason: "), i);
870 				printStatus(status);
871 				fprintf(stderr, "\n");
872 				continue;
873 			}
874 			if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
875 				fprintf(stderr, gettext(
876 					    "Failed to open adapter %s.\n"),
877 				    adapterName);
878 				continue;
879 			}
880 			/* get adapater attributes for the given handle */
881 			memset(&attrs, 0, sizeof (attrs));
882 			status =
883 			    Sun_HBA_NPIVGetAdapterAttributes(handle,
884 			    &attrs);
885 			while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
886 			    status == HBA_STATUS_ERROR_BUSY) &&
887 			    times++ < HBA_MAX_RETRIES) {
888 				(void) sleep(1);
889 				status =
890 				    Sun_HBA_NPIVGetAdapterAttributes(handle,
891 				    &attrs);
892 				if (status == HBA_STATUS_OK) {
893 					break;
894 				}
895 			}
896 			if (status != HBA_STATUS_OK) {
897 				fprintf(stderr,
898 				    gettext("Failed to get adapter attributes "
899 					    "handle(%d) Reason: "), handle);
900 				printStatus(status);
901 				fprintf(stderr, "\n");
902 				HBA_CloseAdapter(handle);
903 				continue;
904 			}
905 
906 			/* process each port on the given adatpter */
907 			for (portIndex = 0;
908 			    portIndex < attrs.NumberOfPorts;
909 			    portIndex++) {
910 				memset(&port, 0, sizeof (port));
911 				if ((status = HBA_GetAdapterPortAttributes(
912 						    handle, portIndex, &port))
913 				    != HBA_STATUS_OK) {
914 					/*
915 					 * not able to get port attributes.
916 					 * print out error * message and move
917 					 * on to the next port
918 					 */
919 					fprintf(stderr,
920 					    gettext("Error: Failed to get port "
921 						    "(%d) attributes reason: "),
922 					    portIndex);
923 					printStatus(status);
924 					fprintf(stderr, "\n");
925 					continue;
926 				}
927 				processHBA(handle, attrs, portIndex, port,
928 				    NULL, HBA_PORT, processHBA_flags,
929 				    INITIATOR_MODE);
930 				if ((processHBA_flags & PRINT_FCOE) !=
931 				    PRINT_FCOE &&
932 				    attrs.VendorSpecificID != 0xFC0E &&
933 				    printHBANPIVPortInfo(handle,
934 				    portIndex) != 0) {
935 					err_cnt++;
936 				}
937 			}
938 			HBA_CloseAdapter(handle);
939 		    }
940 		}
941 
942 		/*
943 		 * Get the info on the target mode FC port if PRINT_TARGET
944 		 * is specified.
945 		 */
946 		if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) {
947 		    numTgtAdapters = Sun_HBA_GetNumberOfTgtAdapters();
948 		    if (numTgtAdapters == 0 && numAdapters == 0) {
949 			fprintf(stdout,
950 			    gettext("No Adapters Found.\n"));
951 		    }
952 		    for (i = 0; i < numTgtAdapters; i++) {
953 			status = Sun_HBA_GetTgtAdapterName(i, adapterName);
954 			if (status != HBA_STATUS_OK) {
955 			    fprintf(stderr, gettext(
956 				"failed to get adapter %d. Reason: "), i);
957 			    printStatus(status);
958 			    fprintf(stderr, "\n");
959 			    continue;
960 			}
961 			if ((handle = Sun_HBA_OpenTgtAdapter(adapterName))
962 			    == 0) {
963 			    fprintf(stderr, gettext(
964 				"Failed to open adapter %s.\n"), adapterName);
965 			    continue;
966 			}
967 			/* get adapater attributes for the given handle */
968 			memset(&attrs, 0, sizeof (attrs));
969 			if ((status = HBA_GetAdapterAttributes(handle, &attrs))
970 			    != HBA_STATUS_OK) {
971 				fprintf(stderr,
972 				    gettext("Failed to get target mode adapter"
973 					"attributes handle(%d) Reason: "),
974 					handle);
975 				printStatus(status);
976 				fprintf(stderr, "\n");
977 				continue;
978 			}
979 
980 			/* process each port on the given adatpter */
981 			for (portIndex = 0;
982 			    portIndex < attrs.NumberOfPorts;
983 			    portIndex++) {
984 				memset(&port, 0, sizeof (port));
985 				if ((status = HBA_GetAdapterPortAttributes(
986 						    handle, portIndex, &port))
987 				    != HBA_STATUS_OK) {
988 					/*
989 					 * not able to get port attributes.
990 					 * print out error * message and move
991 					 * on to the next port
992 					 */
993 					fprintf(stderr,
994 					    gettext("Error: Failed to get port "
995 						    "(%d) attributes reason: "),
996 					    portIndex);
997 					printStatus(status);
998 					fprintf(stderr, "\n");
999 					continue;
1000 				}
1001 				processHBA(handle, attrs, portIndex, port,
1002 				    NULL, HBA_PORT, processHBA_flags,
1003 				    TARGET_MODE);
1004 			}
1005 		    HBA_CloseAdapter(handle);
1006 		}
1007 	    }
1008 	}
1009 
1010 	HBA_FreeLibrary();
1011 
1012 	/*
1013 	 * print additional error msg for partial failure when more than
1014 	 * one wwn is specified.
1015 	 */
1016 	if (err_cnt != 0) {
1017 	    if (wwnCount > 1) {
1018 		if (err_cnt == wwnCount) {
1019 		    fprintf(stderr, gettext(
1020 		    "Error: All specified HBA ports are not found\n"));
1021 		} else {
1022 		    fprintf(stderr, gettext(
1023 		    "Error: Some of specified HBA ports are not found\n"));
1024 		}
1025 	    }
1026 	    return (1);
1027 	}
1028 
1029 	return (0);
1030 }
1031 
1032 /*
1033  * Search the existing device list
1034  *
1035  * Take one of two actions:
1036  *
1037  * Add an entry if an entry doesn't exist
1038  * Add WWN data to it if an entry does exist
1039  *
1040  * Arguments:
1041  *	devList - OS device path list
1042  *	map - target mapping data
1043  *	index - index into target mapping data
1044  *	initiatorPortWWN - HBA port WWN
1045  *	verbose - boolean indicating whether to get additional data
1046  *
1047  * returns:
1048  *	none
1049  */
1050 static void
1051 searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry,
1052 HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose)
1053 {
1054 	discoveredDevice *discoveredDevList, *newDevice;
1055 	portWWNList *WWNList, *newWWN;
1056 	tgtPortWWNList *newTgtWWN;
1057 	boolean_t foundDevice = B_FALSE, foundWWN;
1058 	struct scsi_inquiry	    inq;
1059 	struct scsi_extended_sense  sense;
1060 	HBA_UINT32		    responseSize, senseSize = 0;
1061 	HBA_UINT8		    inq_status;
1062 	HBA_STATUS		status;
1063 
1064 	for (discoveredDevList = *devList; discoveredDevList != NULL;
1065 	    discoveredDevList = discoveredDevList->next) {
1066 		if (strcmp(entry.ScsiId.OSDeviceName,
1067 		    discoveredDevList->OSDeviceName) == 0) {
1068 			/*
1069 			 * if only device names are requested,
1070 			 * no reason to go any further
1071 			 */
1072 			if (verbose == B_FALSE) {
1073 				return;
1074 			}
1075 			foundDevice = B_TRUE;
1076 			break;
1077 		}
1078 	}
1079 	if (foundDevice == B_TRUE) {
1080 		/* add initiator Port WWN if it doesn't exist */
1081 		for (WWNList = discoveredDevList->HBAPortWWN,
1082 		    foundWWN = B_FALSE; WWNList != NULL;
1083 		    WWNList = WWNList->next) {
1084 			if (memcmp((void *)&(WWNList->portWWN),
1085 			    (void *)&initiatorPortWWN,
1086 			    sizeof (HBA_WWN)) == 0) {
1087 				foundWWN = B_TRUE;
1088 				break;
1089 			}
1090 		}
1091 		if (discoveredDevList->inqSuccess == B_FALSE) {
1092 			responseSize = sizeof (struct scsi_inquiry);
1093 			senseSize = sizeof (struct scsi_extended_sense);
1094 			memset(&inq, 0, sizeof (struct scsi_inquiry));
1095 			memset(&sense, 0, sizeof (sense));
1096 			status = HBA_ScsiInquiryV2(
1097 			    handle,
1098 			    initiatorPortWWN,
1099 			    entry.FcpId.PortWWN,
1100 			    entry.FcpId.FcpLun,
1101 			    0, /* CDB Byte 1 */
1102 			    0, /* CDB Byte 2 */
1103 			    &inq, &responseSize,
1104 			    &inq_status,
1105 			    &sense, &senseSize);
1106 			if (status == HBA_STATUS_OK) {
1107 				memcpy(discoveredDevList->VID, inq.inq_vid,
1108 				    sizeof (discoveredDevList->VID));
1109 				memcpy(discoveredDevList->PID, inq.inq_pid,
1110 				    sizeof (discoveredDevList->PID));
1111 				discoveredDevList->dType = inq.inq_dtype;
1112 				discoveredDevList->inqSuccess = B_TRUE;
1113 			}
1114 		}
1115 
1116 		if (foundWWN == B_FALSE) {
1117 			newWWN = (portWWNList *)calloc(1, sizeof (portWWNList));
1118 			if (newWWN == NULL) {
1119 				perror("Out of memory");
1120 				exit(1);
1121 			}
1122 
1123 			/* insert at head */
1124 			newWWN->next = discoveredDevList->HBAPortWWN;
1125 			discoveredDevList->HBAPortWWN = newWWN;
1126 			memcpy((void *)&(newWWN->portWWN),
1127 			    (void *)&initiatorPortWWN,
1128 			    sizeof (newWWN->portWWN));
1129 			/* add Target Port */
1130 			newWWN->tgtPortWWN = (tgtPortWWNList *)calloc(1,
1131 			    sizeof (tgtPortWWNList));
1132 			if (newWWN->tgtPortWWN == NULL) {
1133 				perror("Out of memory");
1134 				exit(1);
1135 			}
1136 
1137 			memcpy((void *)&(newWWN->tgtPortWWN->portWWN),
1138 			    (void *)&(entry.FcpId.PortWWN),
1139 			    sizeof (newWWN->tgtPortWWN->portWWN));
1140 			/* Set LUN data */
1141 			newWWN->tgtPortWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
1142 		} else { /* add it to existing */
1143 			newTgtWWN = (tgtPortWWNList *)calloc(1,
1144 			    sizeof (tgtPortWWNList));
1145 			if (newTgtWWN == NULL) {
1146 				perror("Out of memory");
1147 				exit(1);
1148 			}
1149 			/* insert at head */
1150 			newTgtWWN->next = WWNList->tgtPortWWN;
1151 			WWNList->tgtPortWWN = newTgtWWN;
1152 			memcpy((void *)&(newTgtWWN->portWWN),
1153 			    (void *)&(entry.FcpId.PortWWN),
1154 			    sizeof (newTgtWWN->portWWN));
1155 			/* Set LUN data */
1156 			newTgtWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
1157 		}
1158 	} else { /* add new entry */
1159 		newDevice = (discoveredDevice *)calloc(1,
1160 		    sizeof (discoveredDevice));
1161 		if (newDevice == NULL) {
1162 			perror("Out of memory");
1163 			exit(1);
1164 		}
1165 		newDevice->next = *devList; /* insert at head */
1166 		*devList = newDevice; /* set new head */
1167 
1168 		/* Copy device name */
1169 		strncpy(newDevice->OSDeviceName, entry.ScsiId.OSDeviceName,
1170 		    sizeof (newDevice->OSDeviceName) - 1);
1171 
1172 		/*
1173 		 * if only device names are requested,
1174 		 * no reason to go any further
1175 		 */
1176 		if (verbose == B_FALSE) {
1177 			return;
1178 		}
1179 
1180 		/*
1181 		 * copy WWN data
1182 		 */
1183 		newDevice->HBAPortWWN = (portWWNList *)calloc(1,
1184 		    sizeof (portWWNList));
1185 		if (newDevice->HBAPortWWN == NULL) {
1186 			perror("Out of memory");
1187 			exit(1);
1188 		}
1189 		memcpy((void *)&(newDevice->HBAPortWWN->portWWN),
1190 		    (void *)&initiatorPortWWN, sizeof (newWWN->portWWN));
1191 
1192 		newDevice->HBAPortWWN->tgtPortWWN =
1193 		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
1194 		if (newDevice->HBAPortWWN->tgtPortWWN == NULL) {
1195 			perror("Out of memory");
1196 			exit(1);
1197 		}
1198 
1199 		memcpy((void *)&(newDevice->HBAPortWWN->tgtPortWWN->portWWN),
1200 		    (void *)&(entry.FcpId.PortWWN),
1201 		    sizeof (newDevice->HBAPortWWN->tgtPortWWN->portWWN));
1202 
1203 		/* Set LUN data */
1204 		newDevice->HBAPortWWN->tgtPortWWN->scsiOSLun =
1205 		    entry.ScsiId.ScsiOSLun;
1206 
1207 		responseSize = sizeof (struct scsi_inquiry);
1208 		senseSize = sizeof (struct scsi_extended_sense);
1209 		memset(&inq, 0, sizeof (struct scsi_inquiry));
1210 		memset(&sense, 0, sizeof (sense));
1211 		status = HBA_ScsiInquiryV2(
1212 		    handle,
1213 		    initiatorPortWWN,
1214 		    entry.FcpId.PortWWN,
1215 		    entry.FcpId.FcpLun,
1216 		    0, /* CDB Byte 1 */
1217 		    0, /* CDB Byte 2 */
1218 		    &inq, &responseSize,
1219 		    &inq_status,
1220 		    &sense, &senseSize);
1221 		if (status != HBA_STATUS_OK) {
1222 			/* initialize VID/PID/dType as "Unknown" */
1223 			strcpy(newDevice->VID, "Unknown");
1224 			strcpy(newDevice->PID, "Unknown");
1225 			newDevice->dType = DTYPE_UNKNOWN;
1226 			/* initialize inq status */
1227 			newDevice->inqSuccess = B_FALSE;
1228 		} else {
1229 			memcpy(newDevice->VID, inq.inq_vid,
1230 			    sizeof (newDevice->VID));
1231 			memcpy(newDevice->PID, inq.inq_pid,
1232 			    sizeof (newDevice->PID));
1233 			newDevice->dType = inq.inq_dtype;
1234 			/* initialize inq status */
1235 			newDevice->inqSuccess = B_TRUE;
1236 		}
1237 	}
1238 }
1239 
1240 
1241 /*
1242  * process the logical-unit object
1243  *
1244  * Arguments:
1245  *	luCount - count of the number of device paths in paths_argv
1246  *	    if pathCount > 0, then we will only print information for
1247  *		the device paths listed in paths_argv
1248  *	    if pathCount == 0, then we will print information on all device
1249  *	        paths
1250  *	luArgv - argument array of device paths
1251  *	options - any options specified by the caller
1252  *
1253  * returns:
1254  *	0	if successful
1255  *	> 0	otherwise
1256  */
1257 int
1258 fc_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
1259 {
1260 	int			pathCtr, numAdapters, i, count;
1261 	HBA_STATUS		status;
1262 	char			adapterName[256];
1263 	HBA_HANDLE		handle;
1264 	HBA_PORTATTRIBUTES	port;
1265 	HBA_ADAPTERATTRIBUTES	attrs;
1266 	int			portIndex = 0;
1267 	int			ret = 0;
1268 	boolean_t		verbose = B_FALSE;
1269 	HBA_FCPTARGETMAPPINGV2	*map = NULL;
1270 	discoveredDevice	*devListWalk, *devList = NULL;
1271 	boolean_t		pathFound;
1272 
1273 	/* process each of the options */
1274 	for (; options->optval; options++) {
1275 		if (options->optval == 'v') {
1276 			verbose = B_TRUE;
1277 		}
1278 	}
1279 
1280 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
1281 		fprintf(stderr,
1282 		    gettext("Failed to load FC-HBA common library\n"));
1283 		printStatus(status);
1284 		fprintf(stderr, "\n");
1285 		return (1);
1286 	}
1287 	/*
1288 	 * Retrieve all device paths. We'll need to traverse the list
1289 	 * until we find the input paths or all paths if none were given. We
1290 	 * cannot print as we go since there can be duplicate paths returned
1291 	 */
1292 	numAdapters = HBA_GetNumberOfAdapters();
1293 	if (numAdapters == 0) {
1294 		return (0);
1295 	}
1296 	for (i = 0; i < numAdapters; i++) {
1297 		int times;
1298 		status = HBA_GetAdapterName(i, adapterName);
1299 		if (status != HBA_STATUS_OK) {
1300 			fprintf(stderr, gettext(
1301 			    "Failed to get adapter %d. Reason: "), i);
1302 			printStatus(status);
1303 			fprintf(stderr, "\n");
1304 			ret++;
1305 			continue;
1306 		}
1307 		if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
1308 			fprintf(stderr, gettext("Failed to open adapter %s\n"),
1309 			    adapterName);
1310 			ret++;
1311 			continue;
1312 		}
1313 		/* get adapter attributes for the given handle */
1314 		memset(&attrs, 0, sizeof (attrs));
1315 		times = 0;
1316 		status = HBA_GetAdapterAttributes(handle, &attrs);
1317 		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1318 		    status == HBA_STATUS_ERROR_BUSY) &&
1319 		    times++ < HBA_MAX_RETRIES) {
1320 			(void) sleep(1);
1321 			status = HBA_GetAdapterAttributes(handle, &attrs);
1322 			if (status == HBA_STATUS_OK) {
1323 				break;
1324 			}
1325 		}
1326 		if (status != HBA_STATUS_OK) {
1327 			fprintf(stderr,
1328 			    gettext("Failed to get adapter attributes "
1329 				    "handle(%d) Reason: "), handle);
1330 			printStatus(status);
1331 			fprintf(stderr, "\n");
1332 			ret++;
1333 			HBA_CloseAdapter(handle);
1334 			continue;
1335 		}
1336 
1337 		/* process each port on adapter */
1338 		for (portIndex = 0; portIndex < attrs.NumberOfPorts;
1339 		    portIndex++) {
1340 			memset(&port, 0, sizeof (port));
1341 			if ((status = HBA_GetAdapterPortAttributes(handle,
1342 			    portIndex, &port)) != HBA_STATUS_OK) {
1343 				/*
1344 				 * not able to get port attributes.
1345 				 * print out error message and move
1346 				 * on to the next port
1347 				 */
1348 				fprintf(stderr, gettext("Failed to get port "
1349 				    "(%d) attributes reason: "),
1350 				    portIndex);
1351 				printStatus(status);
1352 				fprintf(stderr, "\n");
1353 				ret++;
1354 				continue;
1355 			}
1356 
1357 			/* get OS Device Paths */
1358 			getTargetMapping(handle, port.PortWWN, &map);
1359 			if (map != NULL) {
1360 				for (count = 0; count < map->NumberOfEntries;
1361 				    count++) {
1362 					searchDevice(&devList,
1363 					    map->entry[count], port.PortWWN,
1364 					    handle, verbose);
1365 				}
1366 			}
1367 		}
1368 		HBA_CloseAdapter(handle);
1369 	}
1370 	HBA_FreeLibrary();
1371 
1372 	if (luCount == 0) {
1373 		/* list all paths */
1374 		for (devListWalk = devList; devListWalk != NULL;
1375 		    devListWalk = devListWalk->next) {
1376 			printOSDeviceNameInfo(devListWalk, verbose);
1377 		}
1378 	} else {
1379 		/*
1380 		 * list any paths not found first
1381 		 * this gives the user cleaner output
1382 		 */
1383 		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
1384 			for (devListWalk = devList, pathFound = B_FALSE;
1385 			    devListWalk != NULL;
1386 			    devListWalk = devListWalk->next) {
1387 				if (strcmp(devListWalk->OSDeviceName,
1388 				    luArgv[pathCtr]) == 0) {
1389 					pathFound = B_TRUE;
1390 				}
1391 			}
1392 			if (pathFound == B_FALSE) {
1393 				fprintf(stderr, "%s: no such path\n",
1394 				    luArgv[pathCtr]);
1395 				ret++;
1396 			}
1397 		}
1398 		/* list all paths requested in order requested */
1399 		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
1400 			for (devListWalk = devList; devListWalk != NULL;
1401 			    devListWalk = devListWalk->next) {
1402 				if (strcmp(devListWalk->OSDeviceName,
1403 				    luArgv[pathCtr]) == 0) {
1404 					printOSDeviceNameInfo(devListWalk,
1405 					    verbose);
1406 				}
1407 			}
1408 		}
1409 	}
1410 	return (ret);
1411 }
1412