xref: /titanic_51/usr/src/cmd/fcinfo/fcinfo-list.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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 				continue;
896 			}
897 
898 			/* process each port on the given adatpter */
899 			for (portIndex = 0;
900 			    portIndex < attrs.NumberOfPorts;
901 			    portIndex++) {
902 				memset(&port, 0, sizeof (port));
903 				if ((status = HBA_GetAdapterPortAttributes(
904 						    handle, portIndex, &port))
905 				    != HBA_STATUS_OK) {
906 					/*
907 					 * not able to get port attributes.
908 					 * print out error * message and move
909 					 * on to the next port
910 					 */
911 					fprintf(stderr,
912 					    gettext("Error: Failed to get port "
913 						    "(%d) attributes reason: "),
914 					    portIndex);
915 					printStatus(status);
916 					fprintf(stderr, "\n");
917 					continue;
918 				}
919 				processHBA(handle, attrs, portIndex, port,
920 				    NULL, HBA_PORT, processHBA_flags,
921 				    INITIATOR_MODE);
922 				if (printHBANPIVPortInfo(handle, portIndex)
923 				    != 0) {
924 					err_cnt++;
925 				}
926 			}
927 			HBA_CloseAdapter(handle);
928 		    }
929 		}
930 
931 		/*
932 		 * Get the info on the target mode FC port if PRINT_TARGET
933 		 * is specified.
934 		 */
935 		if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) {
936 		    numTgtAdapters = Sun_HBA_GetNumberOfTgtAdapters();
937 		    if (numTgtAdapters == 0 && numAdapters == 0) {
938 			fprintf(stdout,
939 			    gettext("No Adapters Found.\n"));
940 		    }
941 		    for (i = 0; i < numTgtAdapters; i++) {
942 			status = Sun_HBA_GetTgtAdapterName(i, adapterName);
943 			if (status != HBA_STATUS_OK) {
944 			    fprintf(stderr, gettext(
945 				"failed to get adapter %d. Reason: "), i);
946 			    printStatus(status);
947 			    fprintf(stderr, "\n");
948 			    continue;
949 			}
950 			if ((handle = Sun_HBA_OpenTgtAdapter(adapterName))
951 			    == 0) {
952 			    fprintf(stderr, gettext(
953 				"Failed to open adapter %s.\n"), adapterName);
954 			    continue;
955 			}
956 			/* get adapater attributes for the given handle */
957 			memset(&attrs, 0, sizeof (attrs));
958 			if ((status = HBA_GetAdapterAttributes(handle, &attrs))
959 			    != HBA_STATUS_OK) {
960 				fprintf(stderr,
961 				    gettext("Failed to get target mode adapter"
962 					"attributes handle(%d) Reason: "),
963 					handle);
964 				printStatus(status);
965 				fprintf(stderr, "\n");
966 				continue;
967 			}
968 
969 			/* process each port on the given adatpter */
970 			for (portIndex = 0;
971 			    portIndex < attrs.NumberOfPorts;
972 			    portIndex++) {
973 				memset(&port, 0, sizeof (port));
974 				if ((status = HBA_GetAdapterPortAttributes(
975 						    handle, portIndex, &port))
976 				    != HBA_STATUS_OK) {
977 					/*
978 					 * not able to get port attributes.
979 					 * print out error * message and move
980 					 * on to the next port
981 					 */
982 					fprintf(stderr,
983 					    gettext("Error: Failed to get port "
984 						    "(%d) attributes reason: "),
985 					    portIndex);
986 					printStatus(status);
987 					fprintf(stderr, "\n");
988 					continue;
989 				}
990 				processHBA(handle, attrs, portIndex, port,
991 				    NULL, HBA_PORT, processHBA_flags,
992 				    TARGET_MODE);
993 			}
994 		    HBA_CloseAdapter(handle);
995 		}
996 	    }
997 	}
998 
999 	HBA_FreeLibrary();
1000 
1001 	/*
1002 	 * print additional error msg for partial failure when more than
1003 	 * one wwn is specified.
1004 	 */
1005 	if (err_cnt != 0) {
1006 	    if (wwnCount > 1) {
1007 		if (err_cnt == wwnCount) {
1008 		    fprintf(stderr, gettext(
1009 		    "Error: All specified HBA ports are not found\n"));
1010 		} else {
1011 		    fprintf(stderr, gettext(
1012 		    "Error: Some of specified HBA ports are not found\n"));
1013 		}
1014 	    }
1015 	    return (1);
1016 	}
1017 
1018 	return (0);
1019 }
1020 
1021 /*
1022  * Search the existing device list
1023  *
1024  * Take one of two actions:
1025  *
1026  * Add an entry if an entry doesn't exist
1027  * Add WWN data to it if an entry does exist
1028  *
1029  * Arguments:
1030  *	devList - OS device path list
1031  *	map - target mapping data
1032  *	index - index into target mapping data
1033  *	initiatorPortWWN - HBA port WWN
1034  *	verbose - boolean indicating whether to get additional data
1035  *
1036  * returns:
1037  *	none
1038  */
1039 static void
1040 searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry,
1041 HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose)
1042 {
1043 	discoveredDevice *discoveredDevList, *newDevice;
1044 	portWWNList *WWNList, *newWWN;
1045 	tgtPortWWNList *newTgtWWN;
1046 	boolean_t foundDevice = B_FALSE, foundWWN;
1047 	struct scsi_inquiry	    inq;
1048 	struct scsi_extended_sense  sense;
1049 	HBA_UINT32		    responseSize, senseSize = 0;
1050 	HBA_UINT8		    inq_status;
1051 	HBA_STATUS		status;
1052 
1053 	for (discoveredDevList = *devList; discoveredDevList != NULL;
1054 	    discoveredDevList = discoveredDevList->next) {
1055 		if (strcmp(entry.ScsiId.OSDeviceName,
1056 		    discoveredDevList->OSDeviceName) == 0) {
1057 			/*
1058 			 * if only device names are requested,
1059 			 * no reason to go any further
1060 			 */
1061 			if (verbose == B_FALSE) {
1062 				return;
1063 			}
1064 			foundDevice = B_TRUE;
1065 			break;
1066 		}
1067 	}
1068 	if (foundDevice == B_TRUE) {
1069 		/* add initiator Port WWN if it doesn't exist */
1070 		for (WWNList = discoveredDevList->HBAPortWWN,
1071 		    foundWWN = B_FALSE; WWNList != NULL;
1072 		    WWNList = WWNList->next) {
1073 			if (memcmp((void *)&(WWNList->portWWN),
1074 			    (void *)&initiatorPortWWN,
1075 			    sizeof (HBA_WWN)) == 0) {
1076 				foundWWN = B_TRUE;
1077 				break;
1078 			}
1079 		}
1080 		if (discoveredDevList->inqSuccess == B_FALSE) {
1081 			responseSize = sizeof (struct scsi_inquiry);
1082 			senseSize = sizeof (struct scsi_extended_sense);
1083 			memset(&inq, 0, sizeof (struct scsi_inquiry));
1084 			memset(&sense, 0, sizeof (sense));
1085 			status = HBA_ScsiInquiryV2(
1086 			    handle,
1087 			    initiatorPortWWN,
1088 			    entry.FcpId.PortWWN,
1089 			    entry.FcpId.FcpLun,
1090 			    0, /* CDB Byte 1 */
1091 			    0, /* CDB Byte 2 */
1092 			    &inq, &responseSize,
1093 			    &inq_status,
1094 			    &sense, &senseSize);
1095 			if (status == HBA_STATUS_OK) {
1096 				memcpy(discoveredDevList->VID, inq.inq_vid,
1097 				    sizeof (discoveredDevList->VID));
1098 				memcpy(discoveredDevList->PID, inq.inq_pid,
1099 				    sizeof (discoveredDevList->PID));
1100 				discoveredDevList->dType = inq.inq_dtype;
1101 				discoveredDevList->inqSuccess = B_TRUE;
1102 			}
1103 		}
1104 
1105 		if (foundWWN == B_FALSE) {
1106 			newWWN = (portWWNList *)calloc(1, sizeof (portWWNList));
1107 			if (newWWN == NULL) {
1108 				perror("Out of memory");
1109 				exit(1);
1110 			}
1111 
1112 			/* insert at head */
1113 			newWWN->next = discoveredDevList->HBAPortWWN;
1114 			discoveredDevList->HBAPortWWN = newWWN;
1115 			memcpy((void *)&(newWWN->portWWN),
1116 			    (void *)&initiatorPortWWN,
1117 			    sizeof (newWWN->portWWN));
1118 			/* add Target Port */
1119 			newWWN->tgtPortWWN = (tgtPortWWNList *)calloc(1,
1120 			    sizeof (tgtPortWWNList));
1121 			if (newWWN->tgtPortWWN == NULL) {
1122 				perror("Out of memory");
1123 				exit(1);
1124 			}
1125 
1126 			memcpy((void *)&(newWWN->tgtPortWWN->portWWN),
1127 			    (void *)&(entry.FcpId.PortWWN),
1128 			    sizeof (newWWN->tgtPortWWN->portWWN));
1129 			/* Set LUN data */
1130 			newWWN->tgtPortWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
1131 		} else { /* add it to existing */
1132 			newTgtWWN = (tgtPortWWNList *)calloc(1,
1133 			    sizeof (tgtPortWWNList));
1134 			if (newTgtWWN == NULL) {
1135 				perror("Out of memory");
1136 				exit(1);
1137 			}
1138 			/* insert at head */
1139 			newTgtWWN->next = WWNList->tgtPortWWN;
1140 			WWNList->tgtPortWWN = newTgtWWN;
1141 			memcpy((void *)&(newTgtWWN->portWWN),
1142 			    (void *)&(entry.FcpId.PortWWN),
1143 			    sizeof (newTgtWWN->portWWN));
1144 			/* Set LUN data */
1145 			newTgtWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
1146 		}
1147 	} else { /* add new entry */
1148 		newDevice = (discoveredDevice *)calloc(1,
1149 		    sizeof (discoveredDevice));
1150 		if (newDevice == NULL) {
1151 			perror("Out of memory");
1152 			exit(1);
1153 		}
1154 		newDevice->next = *devList; /* insert at head */
1155 		*devList = newDevice; /* set new head */
1156 
1157 		/* Copy device name */
1158 		strncpy(newDevice->OSDeviceName, entry.ScsiId.OSDeviceName,
1159 		    sizeof (newDevice->OSDeviceName) - 1);
1160 
1161 		/*
1162 		 * if only device names are requested,
1163 		 * no reason to go any further
1164 		 */
1165 		if (verbose == B_FALSE) {
1166 			return;
1167 		}
1168 
1169 		/*
1170 		 * copy WWN data
1171 		 */
1172 		newDevice->HBAPortWWN = (portWWNList *)calloc(1,
1173 		    sizeof (portWWNList));
1174 		if (newDevice->HBAPortWWN == NULL) {
1175 			perror("Out of memory");
1176 			exit(1);
1177 		}
1178 		memcpy((void *)&(newDevice->HBAPortWWN->portWWN),
1179 		    (void *)&initiatorPortWWN, sizeof (newWWN->portWWN));
1180 
1181 		newDevice->HBAPortWWN->tgtPortWWN =
1182 		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
1183 		if (newDevice->HBAPortWWN->tgtPortWWN == NULL) {
1184 			perror("Out of memory");
1185 			exit(1);
1186 		}
1187 
1188 		memcpy((void *)&(newDevice->HBAPortWWN->tgtPortWWN->portWWN),
1189 		    (void *)&(entry.FcpId.PortWWN),
1190 		    sizeof (newDevice->HBAPortWWN->tgtPortWWN->portWWN));
1191 
1192 		/* Set LUN data */
1193 		newDevice->HBAPortWWN->tgtPortWWN->scsiOSLun =
1194 		    entry.ScsiId.ScsiOSLun;
1195 
1196 		responseSize = sizeof (struct scsi_inquiry);
1197 		senseSize = sizeof (struct scsi_extended_sense);
1198 		memset(&inq, 0, sizeof (struct scsi_inquiry));
1199 		memset(&sense, 0, sizeof (sense));
1200 		status = HBA_ScsiInquiryV2(
1201 		    handle,
1202 		    initiatorPortWWN,
1203 		    entry.FcpId.PortWWN,
1204 		    entry.FcpId.FcpLun,
1205 		    0, /* CDB Byte 1 */
1206 		    0, /* CDB Byte 2 */
1207 		    &inq, &responseSize,
1208 		    &inq_status,
1209 		    &sense, &senseSize);
1210 		if (status != HBA_STATUS_OK) {
1211 			/* initialize VID/PID/dType as "Unknown" */
1212 			strcpy(newDevice->VID, "Unknown");
1213 			strcpy(newDevice->PID, "Unknown");
1214 			newDevice->dType = DTYPE_UNKNOWN;
1215 			/* initialize inq status */
1216 			newDevice->inqSuccess = B_FALSE;
1217 		} else {
1218 			memcpy(newDevice->VID, inq.inq_vid,
1219 			    sizeof (newDevice->VID));
1220 			memcpy(newDevice->PID, inq.inq_pid,
1221 			    sizeof (newDevice->PID));
1222 			newDevice->dType = inq.inq_dtype;
1223 			/* initialize inq status */
1224 			newDevice->inqSuccess = B_TRUE;
1225 		}
1226 	}
1227 }
1228 
1229 
1230 /*
1231  * process the logical-unit object
1232  *
1233  * Arguments:
1234  *	luCount - count of the number of device paths in paths_argv
1235  *	    if pathCount > 0, then we will only print information for
1236  *		the device paths listed in paths_argv
1237  *	    if pathCount == 0, then we will print information on all device
1238  *	        paths
1239  *	luArgv - argument array of device paths
1240  *	options - any options specified by the caller
1241  *
1242  * returns:
1243  *	0	if successful
1244  *	> 0	otherwise
1245  */
1246 int
1247 fc_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
1248 {
1249 	int			pathCtr, numAdapters, i, count;
1250 	HBA_STATUS		status;
1251 	char			adapterName[256];
1252 	HBA_HANDLE		handle;
1253 	HBA_PORTATTRIBUTES	port;
1254 	HBA_ADAPTERATTRIBUTES	attrs;
1255 	int			portIndex = 0;
1256 	int			ret = 0;
1257 	boolean_t		verbose = B_FALSE;
1258 	HBA_FCPTARGETMAPPINGV2	*map = NULL;
1259 	discoveredDevice	*devListWalk, *devList = NULL;
1260 	boolean_t		pathFound;
1261 
1262 	/* process each of the options */
1263 	for (; options->optval; options++) {
1264 		if (options->optval == 'v') {
1265 			verbose = B_TRUE;
1266 		}
1267 	}
1268 
1269 	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
1270 		fprintf(stderr,
1271 		    gettext("Failed to load FC-HBA common library\n"));
1272 		printStatus(status);
1273 		fprintf(stderr, "\n");
1274 		return (1);
1275 	}
1276 	/*
1277 	 * Retrieve all device paths. We'll need to traverse the list
1278 	 * until we find the input paths or all paths if none were given. We
1279 	 * cannot print as we go since there can be duplicate paths returned
1280 	 */
1281 	numAdapters = HBA_GetNumberOfAdapters();
1282 	if (numAdapters == 0) {
1283 		return (0);
1284 	}
1285 	for (i = 0; i < numAdapters; i++) {
1286 		int times;
1287 		status = HBA_GetAdapterName(i, adapterName);
1288 		if (status != HBA_STATUS_OK) {
1289 			fprintf(stderr, gettext(
1290 			    "Failed to get adapter %d. Reason: "), i);
1291 			printStatus(status);
1292 			fprintf(stderr, "\n");
1293 			ret++;
1294 			continue;
1295 		}
1296 		if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
1297 			fprintf(stderr, gettext("Failed to open adapter %s\n"),
1298 			    adapterName);
1299 			ret++;
1300 			continue;
1301 		}
1302 		/* get adapter attributes for the given handle */
1303 		memset(&attrs, 0, sizeof (attrs));
1304 		times = 0;
1305 		status = HBA_GetAdapterAttributes(handle, &attrs);
1306 		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1307 		    status == HBA_STATUS_ERROR_BUSY) &&
1308 		    times++ < HBA_MAX_RETRIES) {
1309 			(void) sleep(1);
1310 			status = HBA_GetAdapterAttributes(handle, &attrs);
1311 			if (status == HBA_STATUS_OK) {
1312 				break;
1313 			}
1314 		}
1315 		if (status != HBA_STATUS_OK) {
1316 			fprintf(stderr,
1317 			    gettext("Failed to get adapter attributes "
1318 			    "handle(%d) Reason: "), handle);
1319 			printStatus(status);
1320 			fprintf(stderr, "\n");
1321 			ret++;
1322 			continue;
1323 		}
1324 
1325 		/* process each port on adapter */
1326 		for (portIndex = 0; portIndex < attrs.NumberOfPorts;
1327 		    portIndex++) {
1328 			memset(&port, 0, sizeof (port));
1329 			if ((status = HBA_GetAdapterPortAttributes(handle,
1330 			    portIndex, &port)) != HBA_STATUS_OK) {
1331 				/*
1332 				 * not able to get port attributes.
1333 				 * print out error message and move
1334 				 * on to the next port
1335 				 */
1336 				fprintf(stderr, gettext("Failed to get port "
1337 				    "(%d) attributes reason: "),
1338 				    portIndex);
1339 				printStatus(status);
1340 				fprintf(stderr, "\n");
1341 				ret++;
1342 				continue;
1343 			}
1344 
1345 			/* get OS Device Paths */
1346 			getTargetMapping(handle, port.PortWWN, &map);
1347 			if (map != NULL) {
1348 				for (count = 0; count < map->NumberOfEntries;
1349 				    count++) {
1350 					searchDevice(&devList,
1351 					    map->entry[count], port.PortWWN,
1352 					    handle, verbose);
1353 				}
1354 			}
1355 		}
1356 		HBA_CloseAdapter(handle);
1357 	}
1358 	HBA_FreeLibrary();
1359 
1360 	if (luCount == 0) {
1361 		/* list all paths */
1362 		for (devListWalk = devList; devListWalk != NULL;
1363 		    devListWalk = devListWalk->next) {
1364 			printOSDeviceNameInfo(devListWalk, verbose);
1365 		}
1366 	} else {
1367 		/*
1368 		 * list any paths not found first
1369 		 * this gives the user cleaner output
1370 		 */
1371 		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
1372 			for (devListWalk = devList, pathFound = B_FALSE;
1373 			    devListWalk != NULL;
1374 			    devListWalk = devListWalk->next) {
1375 				if (strcmp(devListWalk->OSDeviceName,
1376 				    luArgv[pathCtr]) == 0) {
1377 					pathFound = B_TRUE;
1378 				}
1379 			}
1380 			if (pathFound == B_FALSE) {
1381 				fprintf(stderr, "%s: no such path\n",
1382 				    luArgv[pathCtr]);
1383 				ret++;
1384 			}
1385 		}
1386 		/* list all paths requested in order requested */
1387 		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
1388 			for (devListWalk = devList; devListWalk != NULL;
1389 			    devListWalk = devListWalk->next) {
1390 				if (strcmp(devListWalk->OSDeviceName,
1391 				    luArgv[pathCtr]) == 0) {
1392 					printOSDeviceNameInfo(devListWalk,
1393 					    verbose);
1394 				}
1395 			}
1396 		}
1397 	}
1398 	return (ret);
1399 }
1400