OpenSolaris_b135/cmd/fcinfo/fcinfo-list.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */


#include "fcinfo.h"
#include <libintl.h>

struct lun {
	uchar_t val[8];
};

typedef enum {
    HBA_PORT,
    REMOTE_PORT,
    LOGICAL_UNIT
} resource_type;

typedef struct rep_luns_rsp {
	uint32_t    length;
	uint32_t    rsrvd;
	struct lun  lun[1];
} rep_luns_rsp_t;

static int getTargetMapping(HBA_HANDLE, HBA_WWN myhbaPortWWN,
    HBA_FCPTARGETMAPPINGV2 **mapping);
static int processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs,
    int portIndex, HBA_PORTATTRIBUTES port, HBA_FCPTARGETMAPPINGV2 *map,
    int resourceType, int flags, int mode);
static void processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
    HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags);
static void handleRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
    HBA_WWN myRemotePortWWN, HBA_PORTATTRIBUTES *discPort);
static void printLinkStat(HBA_HANDLE handle, HBA_WWN hbaportWWN,
    HBA_WWN destWWN);
static void handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
    HBA_WWN scsiTargetWWN, HBA_FCPTARGETMAPPINGV2 *map);
static int retrieveAttrs(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
    HBA_ADAPTERATTRIBUTES *attrs, HBA_PORTATTRIBUTES *port, int *portIndex);
static void searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry,
    HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose);

/*
 * This function retrieve the adapater attributes, port attributes, and
 * portIndex for the given handle and hba port WWN.
 *
 * Arguments:
 *	handle	    an HBA_HANDLE to a adapter
 *	hbaPortWWN  WWN of the port on the adapter to which to retrieve
 *			HBA_PORTATTRIBUTES from
 *	attrs	    pointer to a HBA_ADAPTERATTRIBUTES structure.  Upon
 *			successful completion, this structure will be filled in
 *	port	    pointer to a HBA_PORTATTRIBUTES structure.  Upon successful
 *			completion, this structure will be fill in
 *	portIndex   the Index count of the port on the adapter that is
 *			associated with the WWN.
 *
 * Returns
 *	0	    successfully retrieve all information
 *	>0	    otherwise
 */
static int
retrieveAttrs(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
    HBA_ADAPTERATTRIBUTES *attrs, HBA_PORTATTRIBUTES *port, int *portIndex)
{
	HBA_STATUS		status;
	int			portCtr;
	int			times;

	/* argument checking */
	if (attrs == NULL || port == NULL || portIndex == NULL) {
		fprintf(stderr, gettext("Error: Invalid arguments to "
			    "retreiveAttrs\n"));
		return (1);
	}

	/* retrieve Adapter attributes */
	memset(attrs, 0, sizeof (HBA_ADAPTERATTRIBUTES));
	status = HBA_GetAdapterAttributes(handle, attrs);
	times = 0;
	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
	    status == HBA_STATUS_ERROR_BUSY) &&
	    times++ < HBA_MAX_RETRIES) {
		(void) sleep(1);
		status = HBA_GetAdapterAttributes(handle, attrs);
		if (status == HBA_STATUS_OK) {
			break;
		}
	}
	if (status != HBA_STATUS_OK) {
		fprintf(stderr, gettext("Failed to get adapter "
		    "attributes handle(%d) Reason: "), handle);
		printStatus(status);
		fprintf(stderr, "\n");
		return (1);
	}

	/*
	 * find the corresponding port on the adapter and retrieve
	 * port attributes as well as the port index
	 */
	memset(port,  0, sizeof (HBA_PORTATTRIBUTES));
	for (portCtr = 0; portCtr < attrs->NumberOfPorts; portCtr++) {
		if ((status = HBA_GetAdapterPortAttributes(handle,
				    portCtr, port)) != HBA_STATUS_OK) {
			fprintf(stderr,
			    gettext("Error: Failed to get port (%d) "
				    "attributes reason: "), portCtr);
			printStatus(status);
			fprintf(stderr, "\n");
			return (1);
		}
		if (memcmp(hbaPortWWN.wwn, port->PortWWN.wwn,
			    sizeof (port->PortWWN.wwn)) == 0) {
			break;
		}
	}
	if (portCtr >= attrs->NumberOfPorts) {
		/*
		 * not able to find corresponding port WWN
		 * returning an error
		 */
		*portIndex = 0;
		return (1);
	}
	*portIndex = portCtr;
	return (0);
}

/*
 * This function retrieves target mapping information for the HBA port WWN.
 * This function will allocate space for the mapping structure which the caller
 * must free when they are finished
 *
 * Arguments:
 *	handle - a handle to a HBA that we will be processing
 *	hbaPortWWN - the port WWN for the HBA port to retrieve the mappings for
 *	mapping - a pointer to a pointer for the target mapping structure
 *	    Upon successful completion of this function, *mapping will contain
 *	    the target mapping information
 *
 * returns:
 *	0	if successful
 *	1	otherwise
 */
static int
getTargetMapping(HBA_HANDLE handle, HBA_WWN hbaPortWWN,
    HBA_FCPTARGETMAPPINGV2 **mapping)
{
	HBA_FCPTARGETMAPPINGV2	*map;
	HBA_STATUS		status;
	int			count;

	/* argument sanity checking */
	if (mapping == NULL) {
		fprintf(stderr, gettext("Internal Error: mapping is NULL"));
		return (1);
	}
	*mapping = NULL;
	if ((map = calloc(1, sizeof (HBA_FCPTARGETMAPPINGV2))) == NULL) {
		fprintf(stderr,
		    gettext("Internal Error: Unable to calloc map"));
		return (1);
	}
	status = HBA_GetFcpTargetMappingV2(handle, hbaPortWWN, map);
	count = map->NumberOfEntries;
	if (status == HBA_STATUS_ERROR_MORE_DATA) {
		free(map);
		if ((map = calloc(1, (sizeof (HBA_FCPSCSIENTRYV2)*(count-1)) +
				    sizeof (HBA_FCPTARGETMAPPINGV2))) == NULL) {
			fprintf(stderr,
			    gettext("Unable to calloc map of size: %d"), count);
			return (1);
		}
		map->NumberOfEntries = count;
		status = HBA_GetFcpTargetMappingV2(handle, hbaPortWWN, map);
	}
	if (status != HBA_STATUS_OK) {
		fprintf(stderr,
		    gettext("Error: Unable to get Target Mapping\n"));
		printStatus(status);
		fprintf(stderr, "\n");
		free(map);
		return (1);
	}
	*mapping = map;
	return (0);
}

/*
 * This function handles the remoteport object.  It will issue a report lun
 * to determine whether it is a scsi-target and then print the information.
 *
 * Arguments:
 *	handle - a handle to a HBA that we will be processing
 *	portWWN - the port WWN for the HBA port we will be issuing the SCSI
 *	    ReportLUNS through
 *	remotePortWWN - the port WWN we will be issuing the report lun call to
 *	discPort - PORTATTRIBUTES structure for the remotePortWWN
 */
static void
handleRemotePort(HBA_HANDLE handle, HBA_WWN portWWN, HBA_WWN remotePortWWN,
    HBA_PORTATTRIBUTES *discPort)
{
	HBA_STATUS		status;
	int			scsiTargetType;
	uchar_t			raw_luns[LUN_LENGTH];
	HBA_UINT32		responseSize = LUN_LENGTH;
	struct scsi_extended_sense  sense;
	HBA_UINT32		senseSize = sizeof (struct scsi_extended_sense);
	HBA_UINT8		rep_luns_status;

	/* argument checking */
	if (discPort == NULL) {
		return;
	}

	memset(raw_luns, 0, sizeof (raw_luns));
	/* going to issue a report lun to check if this is a scsi-target */
	status = HBA_ScsiReportLUNsV2(handle, portWWN, remotePortWWN,
	    (void *)raw_luns, &responseSize, &rep_luns_status,
	    (void *)&sense, &senseSize);
	if (status == HBA_STATUS_OK) {
		scsiTargetType = SCSI_TARGET_TYPE_YES;
	} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
		scsiTargetType = SCSI_TARGET_TYPE_NO;
	} else {
		scsiTargetType = SCSI_TARGET_TYPE_UNKNOWN;
	}
	printDiscoPortInfo(discPort, scsiTargetType);
}

/*
 * This function will issue the RLS and print out the port statistics for
 * the given destWWN
 *
 * Arguments
 *	handle - a handle to a HBA that we will be processing
 *	hbaPortWWN - the hba port WWN through which the RLS will be sent
 *	destWWN - the remote port to which the RLS will be sent
 */
static void
printLinkStat(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN destWWN)
{
	HBA_STATUS		status;
	fc_rls_acc_t		rls_payload;
	uint32_t		rls_payload_size;

	memset(&rls_payload, 0, sizeof (rls_payload));
	rls_payload_size = sizeof (rls_payload);
	status = HBA_SendRLS(handle, hbaPortWWN, destWWN,
	    &rls_payload, &rls_payload_size);
	if (status != HBA_STATUS_OK) {
		fprintf(stderr, gettext("Error: SendRLS failed for %016llx\n"),
		    wwnConversion(destWWN.wwn));
	} else {
		printPortStat(&rls_payload);
	}
}

int
printHBANPIVPortInfo(HBA_HANDLE handle, int portindex)
{
	HBA_PORTNPIVATTRIBUTES	portattrs;
	HBA_NPIVATTRIBUTES	npivattrs;
	HBA_STATUS		status;
	int			index;
	int			times = 0;

	status = Sun_HBA_GetPortNPIVAttributes(handle, portindex, &portattrs);
	while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
	    status == HBA_STATUS_ERROR_BUSY) {
		(void) sleep(1);
		status = Sun_HBA_GetPortNPIVAttributes(
		    handle, portindex, &portattrs);
		if (times++ > HBA_MAX_RETRIES) {
			break;
		}
	}

	if (status == HBA_STATUS_ERROR_NOT_SUPPORTED) {
		fprintf(stdout, gettext("\tNPIV Not Supported\n"));
		return (0);
	}

	if (status != HBA_STATUS_OK) {
		fprintf(stderr,
		    gettext("Error: Failed to get port (%d) "
		    "npiv attributes reason: "), portindex);
		printStatus(status);
		fprintf(stderr, "\n");
		return (1);
	}
	if (portattrs.MaxNumberOfNPIVPorts) {
		fprintf(stdout, gettext("\tMax NPIV Ports: %d\n"),
		    portattrs.MaxNumberOfNPIVPorts);
	} else {
		fprintf(stdout, gettext("\tNPIV Not Supported\n"));
		return (0);
	}
	fprintf(stdout, gettext("\tNPIV port list:\n"));
	for (index = 0; index < portattrs.NumberOfNPIVPorts; index++) {
		int times = 0;
		status = Sun_HBA_GetNPIVPortInfo(handle,
		    portindex, index, &npivattrs);
		while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
		    status == HBA_STATUS_ERROR_BUSY) {
			(void) sleep(1);
			status = Sun_HBA_GetNPIVPortInfo(handle,
			    portindex, index, &npivattrs);
			if (times++ > HBA_MAX_RETRIES) {
				break;
			}
		}

		if (status != HBA_STATUS_OK) {
			fprintf(stderr,
			    gettext("Error: Failed to get npiv port (%d) "
			    "attributes reason: "), index);
			printStatus(status);
			fprintf(stderr, "\n");
			return (1);
		} else {
			fprintf(stdout,
			    gettext("\t  Virtual Port%d:\n"), index+1);
			fprintf(stdout, gettext("\t\tNode WWN: %016llx\n"),
			    wwnConversion(npivattrs.NodeWWN.wwn));
			fprintf(stdout, gettext("\t\tPort WWN: %016llx\n"),
			    wwnConversion(npivattrs.PortWWN.wwn));
		}
	}
	return (0);
}

/*
 * This function will process hba port, remote port and scsi-target information
 * for the given handle.
 *
 * Arguments:
 *	handle - a handle to a HBA that we will be processing
 *	resourceType - resourceType flag
 *		possible values include: HBA_PORT, REMOTE_PORT
 *	flags - represents options passed in by the user
 *
 *  Return Value:
 *	    0		sucessfully processed handle
 *	    1		error has occured
 */
static int
processHBA(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES attrs, int portIndex,
    HBA_PORTATTRIBUTES port, HBA_FCPTARGETMAPPINGV2 *map,
    int resourceType, int flags, int mode)
{
	HBA_PORTATTRIBUTES	discPort;
	HBA_STATUS		status;
	int			discPortCount;

	if (resourceType == HBA_PORT) {
		if ((flags & PRINT_FCOE) == PRINT_FCOE &&
		    attrs.VendorSpecificID != 0xFC0E) {
			return (0);
		}
		printHBAPortInfo(&port, &attrs, mode);
		if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
			printLinkStat(handle, port.PortWWN, port.PortWWN);
		}
		return (0);
	}
	/*
	 * process each of the remote targets from this hba port
	 */
	for (discPortCount = 0;
	    discPortCount < port.NumberofDiscoveredPorts;
	    discPortCount++) {
		status = HBA_GetDiscoveredPortAttributes(handle,
		    portIndex, discPortCount, &discPort);
		if (status != HBA_STATUS_OK) {
			fprintf(stderr,
			    gettext("Failed to get discovered port (%d)"
				    " attributes reason :"), discPortCount);
			printStatus(status);
			fprintf(stderr, "\n");
			continue;
		}
		if (resourceType == REMOTE_PORT) {
			handleRemotePort(handle, port.PortWWN, discPort.PortWWN,
			    &discPort);
			if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
			    printLinkStat(handle, port.PortWWN,
				discPort.PortWWN);
			}
			if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
				handleScsiTarget(handle, port.PortWWN,
				    discPort.PortWWN, map);
			}
		}
	}
	return (0);
}

/*
 * This function will process remote port information for the given handle.
 *
 * Arguments:
 *	handle - a handle to a HBA that we will be processing
 *	portWWN - the port WWN for the HBA port we will be issuing the SCSI
 *	    ReportLUNS through
 *	wwnCount - the number of wwns in wwn_argv
 *	wwn_argv - argument vector of WWNs
 */
static void
processRemotePort(HBA_HANDLE handle, HBA_WWN portWWN,
    HBA_FCPTARGETMAPPINGV2 *map, int wwnCount, char **wwn_argv, int flags)
{
	int			remote_wwn_counter;
	uint64_t		remotePortWWN;
	HBA_WWN			myremotePortWWN;
	HBA_PORTATTRIBUTES	discPort;
	HBA_STATUS		status;

	for (remote_wwn_counter = 0;
	    remote_wwn_counter < wwnCount;
	    remote_wwn_counter++) {
		int times = 0;
		sscanf(wwn_argv[remote_wwn_counter], "%016llx",
		    &remotePortWWN);
		remotePortWWN = htonll(remotePortWWN);
		memcpy(myremotePortWWN.wwn, &remotePortWWN,
		    sizeof (remotePortWWN));
		memset(&discPort, 0, sizeof (discPort));
		status = HBA_GetPortAttributesByWWN(handle, myremotePortWWN,
		    &discPort);
		while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
		    status == HBA_STATUS_ERROR_BUSY) {
			(void) sleep(1);
			status = HBA_GetPortAttributesByWWN(handle,
			    myremotePortWWN, &discPort);
			if (times++ > HBA_MAX_RETRIES) {
				break;
			}
		}
		if (status != HBA_STATUS_OK) {
			fprintf(stderr, gettext("HBA_GetPortAttributesByWWN "
				    "failed: reason: "));
			printStatus(status);
			fprintf(stderr, "\n");
			continue;
		}
		handleRemotePort(handle, portWWN, myremotePortWWN, &discPort);
		if ((flags & PRINT_LINKSTAT) == PRINT_LINKSTAT) {
			printLinkStat(handle, portWWN, myremotePortWWN);
		}
		if ((flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
			handleScsiTarget(handle, portWWN,
			    myremotePortWWN, map);
		}
	}
}

/*
 * This function handles printing Scsi target information for remote ports
 *
 * Arguments:
 *	handle - a handle to a HBA that we will be processing
 *	hbaPortWWN - the port WWN for the HBA port through which the SCSI call
 *	    is being sent
 *	scsiTargetWWN - target port WWN of the remote target the SCSI call is
 *	    being sent to
 *	map - a pointer to the target mapping structure for the given HBA port
 */
static void
handleScsiTarget(HBA_HANDLE handle, HBA_WWN hbaPortWWN, HBA_WWN scsiTargetWWN,
    HBA_FCPTARGETMAPPINGV2 *map)
{
	HBA_STATUS		    status;
	struct scsi_inquiry	    inq;
	struct scsi_extended_sense  sense;
	HBA_UINT32		    responseSize, senseSize = 0;
	HBA_UINT8		    inq_status;
	uchar_t			    raw_luns[DEFAULT_LUN_LENGTH], *lun_string;
	HBA_UINT8		    rep_luns_status;
	rep_luns_rsp_t		    *lun_resp;
	uint64_t		    fcLUN;
	int			    lunNum, numberOfLun, lunCount, count;
	uint32_t		    lunlength, tmp_lunlength;

	responseSize = DEFAULT_LUN_LENGTH;
	senseSize = sizeof (struct scsi_extended_sense);
	memset(&sense, 0, sizeof (sense));
	status = HBA_ScsiReportLUNsV2(handle, hbaPortWWN,
	    scsiTargetWWN, (void *)raw_luns, &responseSize,
	    &rep_luns_status, (void *)&sense, &senseSize);
	/*
	 * if HBA_STATUS_ERROR_NOT_A_TARGET is return, we can assume this is
	 * a remote HBA and move on
	 */
	if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
		return;
	} else if (status != HBA_STATUS_OK) {
		fprintf(stderr, gettext("Error has occured. "
			    "HBA_ScsiReportLUNsV2 failed.  reason "));
		printStatus(status);
		fprintf(stderr, "\n");
		return;
	}
	lun_resp = (rep_luns_rsp_t *)raw_luns;
	memcpy(&tmp_lunlength, &(lun_resp->length), sizeof (tmp_lunlength));
	lunlength = htonl(tmp_lunlength);
	memcpy(&numberOfLun, &lunlength, sizeof (numberOfLun));
	for (lunCount = 0; lunCount < (numberOfLun / 8); lunCount++) {
		/*
		 * now issue standard inquiry to get Vendor
		 * and product information
		 */
		responseSize = sizeof (struct scsi_inquiry);
		senseSize = sizeof (struct scsi_extended_sense);
		memset(&inq, 0, sizeof (struct scsi_inquiry));
		memset(&sense, 0, sizeof (sense));
		fcLUN = ntohll(wwnConversion(lun_resp->lun[lunCount].val));
		status = HBA_ScsiInquiryV2(
			handle,
			hbaPortWWN,
			scsiTargetWWN,
			fcLUN,
			0, /* EVPD */
			0,
			&inq, &responseSize,
			&inq_status,
			&sense, &senseSize);
		if (status != HBA_STATUS_OK) {
		    fprintf(stderr, gettext("Not able to issue Inquiry.\n"));
		    printStatus(status);
		    fprintf(stderr, "\n");
		    strcpy(inq.inq_vid, "Unknown");
		    strcpy(inq.inq_pid, "Unknown");
		}
		if (map != NULL) {
			for (count = 0; count < map->NumberOfEntries; count++) {
			    if ((memcmp(map->entry[count].FcpId.PortWWN.wwn,
						    scsiTargetWWN.wwn,
						    sizeof (scsiTargetWWN.wwn))
					    == 0) &&
				    (memcmp(&(map->entry[count].FcpId.FcpLun),
					    &fcLUN, sizeof (fcLUN)) == 0)) {
				printLUNInfo(&inq,
				    map->entry[count].ScsiId.ScsiOSLun,
				    map->entry[count].ScsiId.OSDeviceName);
				    break;
			    }
			}
			if (count == map->NumberOfEntries) {
				lun_string = lun_resp->lun[lunCount].val;
				lunNum = ((lun_string[0] & 0x3F) << 8) |
				    lun_string[1];
				printLUNInfo(&inq, lunNum, "Unknown");
			}
		} else {
			/* Not able to get any target mapping information */
			lun_string = lun_resp->lun[lunCount].val;
			lunNum = ((lun_string[0] & 0x3F) << 8) |
			    lun_string[1];
			printLUNInfo(&inq, lunNum, "Unknown");
		}
	}
}

/*
 * function to handle the list remoteport command
 *
 * Arguments:
 *	wwnCount - the number of wwns in wwn_argv
 *	    if wwnCount == 0, then print information on all
 *		remote ports.  wwn_argv will not be used in this case
 *	    if wwnCount > 0, then print information for the WWNs
 *		given in wwn_argv
 *	wwn_argv - argument vector of WWNs
 *	options - any options specified by the caller
 *
 * returns:
 *	0	if successful
 *	1	otherwise
 */
int
fc_util_list_remoteport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
{
	HBA_STATUS		status;
	HBA_FCPTARGETMAPPINGV2	*map = NULL;
	HBA_PORTATTRIBUTES	port;
	HBA_ADAPTERATTRIBUTES	attrs;
	HBA_HANDLE		handle;
	uint64_t		hbaPortWWN;
	HBA_WWN			myhbaPortWWN;
	int			processHBA_flags = 0, portCount = 0;
	int			mode;

	/* grab the hba port wwn from the -p option */
	for (; options->optval; options++) {
		if (options->optval == 'p') {
			sscanf(options->optarg, "%016llx",
			    &hbaPortWWN);
		} else if (options->optval == 's') {
			processHBA_flags |= PRINT_SCSI_TARGET;
		} else if (options->optval == 'l') {
			processHBA_flags |= PRINT_LINKSTAT;
		} else {
			fprintf(stderr, gettext("Error: Illegal option: %c.\n"),
			    options->optval);
			return (1);
		}
	}
	/*
	 * -h option was not specified, this should not happen either.
	 * cmdparse should catch this problem, but checking anyways
	 */
	if (hbaPortWWN == 0) {
		fprintf(stderr,
		    gettext("Error: -p option was not specified.\n"));
		return (1);
	}
	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
		fprintf(stderr,
		    gettext("Failed to load FC-HBA common library\n"));
		printStatus(status);
		fprintf(stderr, "\n");
		return (1);
	}
	hbaPortWWN = htonll(hbaPortWWN);
	memcpy(myhbaPortWWN.wwn, &hbaPortWWN, sizeof (hbaPortWWN));
	if ((status = HBA_OpenAdapterByWWN(&handle, myhbaPortWWN))
	    != HBA_STATUS_OK) {
		status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myhbaPortWWN);
		if (status != HBA_STATUS_OK) {
		    fprintf(stderr,
			gettext("Error: Failed to open adapter port. Reason "));
			printStatus(status);
		    fprintf(stderr, "\n");
		    HBA_FreeLibrary();
		    return (1);
		} else {
		    if ((processHBA_flags & PRINT_SCSI_TARGET) ==
			PRINT_SCSI_TARGET) {
			fprintf(stderr, gettext(
			    "Error: Unsupported option for target mode: %c.\n"),
			    's');
			HBA_FreeLibrary();
			return (1);
		    }
		    mode = TARGET_MODE;
		}
	} else {
	    mode = INITIATOR_MODE;
	}

	if ((processHBA_flags & PRINT_SCSI_TARGET) == PRINT_SCSI_TARGET) {
		getTargetMapping(handle, myhbaPortWWN, &map);
	}
	if (wwnCount == 0) {
		/* get adapater attributes for the given handle */
		memset(&attrs, 0, sizeof (attrs));
		memset(&port, 0, sizeof (port));
		if (retrieveAttrs(handle, myhbaPortWWN, &attrs, &port,
			    &portCount) != 0) {
			if (map != NULL) {
				free(map);
			}
			HBA_CloseAdapter(handle);
			HBA_FreeLibrary();
			return (1);
		}
		processHBA(handle, attrs, portCount, port, map, REMOTE_PORT,
		    processHBA_flags, mode);
	} else {
		processRemotePort(handle, myhbaPortWWN, map, wwnCount,
		    wwn_argv, processHBA_flags);
	}
	if (map != NULL) {
		free(map);
	}
	HBA_CloseAdapter(handle);
	HBA_FreeLibrary();
	return (0);
}

/*
 * process the hbaport object
 *
 * Arguments:
 *	wwnCount - count of the number of WWNs in wwn_argv
 *	    if wwnCount > 0, then we will only print information for
 *		the hba ports listed in wwn_argv
 *	    if wwnCount == 0, then we will print information on all hba ports
 *	wwn_argv - argument array of hba port WWNs
 *	options - any options specified by the caller
 *
 * returns:
 *	0	if successful
 *	1	otherwise
 */
int
fc_util_list_hbaport(int wwnCount, char **wwn_argv, cmdOptions_t *options)
{
	int	port_wwn_counter, numAdapters = 0, numTgtAdapters = 0, i;
	HBA_STATUS		status;
	char			adapterName[256];
	HBA_HANDLE		handle;
	uint64_t		hbaWWN;
	HBA_WWN			myWWN;
	int			processHBA_flags = 0;
	HBA_PORTATTRIBUTES	port;
	HBA_ADAPTERATTRIBUTES	attrs;
	int			portIndex = 0, err_cnt = 0;
	int			mode;

	/* process each of the options */
	for (; options->optval; options++) {
		if (options->optval == 'l') {
			processHBA_flags |= PRINT_LINKSTAT;
		} else if (options->optval == 'i') {
			processHBA_flags |= PRINT_INITIATOR;
		} else if (options->optval == 't') {
			processHBA_flags |= PRINT_TARGET;
		} else if (options->optval == 'e') {
			processHBA_flags |= PRINT_FCOE;
		}
	}

	/*
	 * Print both initiator and target if no initiator/target flag
	 * specified.
	 */
	if (((processHBA_flags & PRINT_INITIATOR) == 0) &&
	    ((processHBA_flags & PRINT_TARGET) == 0)) {
	    processHBA_flags |= PRINT_INITIATOR | PRINT_TARGET;
	}

	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
		fprintf(stderr,
		    gettext("Failed to load FC-HBA common library\n"));
		printStatus(status);
		fprintf(stderr, "\n");
		return (1);
	}
	if (wwnCount > 0) {
		/* list only ports given in wwn_argv */
		for (port_wwn_counter = 0;
		    port_wwn_counter < wwnCount;
		    port_wwn_counter++) {
			sscanf(wwn_argv[port_wwn_counter], "%016llx", &hbaWWN);
			hbaWWN = htonll(hbaWWN);
			memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN));
			/* first check to see if it is an initiator port. */
			if ((processHBA_flags & PRINT_INITIATOR) ==
			    PRINT_INITIATOR) {
			    int times = 0;
			    status = HBA_OpenAdapterByWWN(&handle, myWWN);
			    while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
				status == HBA_STATUS_ERROR_BUSY) {
				(void) sleep(1);
				status = HBA_OpenAdapterByWWN(&handle, myWWN);
				if (times++ > HBA_MAX_RETRIES) {
					break;
				}
			    }
			    if (status != HBA_STATUS_OK) {
				/* now see if it is a target mode FC port */
				if ((processHBA_flags & PRINT_TARGET) ==
				    PRINT_TARGET) {
				    status =
				    Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN);
				    if (status != HBA_STATUS_OK) {
					fprintf(stderr,
					    gettext(
					    "Error: HBA port %s: not found\n"),
					    wwn_argv[port_wwn_counter]);
					    err_cnt++;
					continue;
				    } else {
					/* set the port mode. */
					mode = TARGET_MODE;
				    }
				} else {
				    fprintf(stderr,
					gettext(
					    "Error: HBA port %s: not found\n"),
					    wwn_argv[port_wwn_counter]);
					    err_cnt++;
					continue;
				}
			    } else {
				/* set the port mode. */
				mode = INITIATOR_MODE;
			    }
			/* try target mode discovery if print target is set. */
			} else if ((processHBA_flags & PRINT_TARGET) ==
				PRINT_TARGET) {
			    status =
				Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN);
			    if (status != HBA_STATUS_OK) {
				fprintf(stderr, gettext(
				    "Error: HBA port %s: not found\n"),
				    wwn_argv[port_wwn_counter]);
				    err_cnt++;
				continue;
			    } else {
				/* set the port mode. */
				mode = TARGET_MODE;
			    }
			} else {
			    /* should not get here. */
			    fprintf(stderr, gettext(
				"Error: HBA port %s: not found\n"),
				wwn_argv[port_wwn_counter]);
			    err_cnt++;
			    continue;
			}
			memset(&attrs, 0, sizeof (attrs));
			memset(&port, 0, sizeof (port));
			if (retrieveAttrs(handle, myWWN, &attrs, &port,
				    &portIndex) != 0) {
				HBA_CloseAdapter(handle);
				continue;
			}
			processHBA(handle, attrs, portIndex, port, NULL,
			    HBA_PORT, processHBA_flags, mode);
			if ((processHBA_flags & PRINT_FCOE) != PRINT_FCOE &&
			    attrs.VendorSpecificID != 0xFC0E &&
			    printHBANPIVPortInfo(handle, portIndex) != 0) {
				err_cnt++;
			}
			HBA_CloseAdapter(handle);
		}
	} else {
		/*
		 * if PRINT_INITIATOR is specified, get the list of initiator
		 * mod port.
		 */
		if ((processHBA_flags & PRINT_INITIATOR) == PRINT_INITIATOR) {
		    numAdapters = HBA_GetNumberOfAdapters();
		    if ((numAdapters == 0) &&
			((processHBA_flags & ~PRINT_INITIATOR) == 0)) {
			fprintf(stdout, gettext("No Adapters Found.\n"));
		    }
		    for (i = 0; i < numAdapters; i++) {
			int times = 0;
			status = HBA_GetAdapterName(i, adapterName);
			if (status != HBA_STATUS_OK) {
				fprintf(stderr, gettext(
				    "failed to get adapter %d. Reason: "), i);
				printStatus(status);
				fprintf(stderr, "\n");
				continue;
			}
			if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
				fprintf(stderr, gettext(
					    "Failed to open adapter %s.\n"),
				    adapterName);
				continue;
			}
			/* get adapater attributes for the given handle */
			memset(&attrs, 0, sizeof (attrs));
			status =
			    Sun_HBA_NPIVGetAdapterAttributes(handle,
			    &attrs);
			while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
			    status == HBA_STATUS_ERROR_BUSY) &&
			    times++ < HBA_MAX_RETRIES) {
				(void) sleep(1);
				status =
				    Sun_HBA_NPIVGetAdapterAttributes(handle,
				    &attrs);
				if (status == HBA_STATUS_OK) {
					break;
				}
			}
			if (status != HBA_STATUS_OK) {
				fprintf(stderr,
				    gettext("Failed to get adapter attributes "
					    "handle(%d) Reason: "), handle);
				printStatus(status);
				fprintf(stderr, "\n");
				HBA_CloseAdapter(handle);
				continue;
			}

			/* process each port on the given adatpter */
			for (portIndex = 0;
			    portIndex < attrs.NumberOfPorts;
			    portIndex++) {
				memset(&port, 0, sizeof (port));
				if ((status = HBA_GetAdapterPortAttributes(
						    handle, portIndex, &port))
				    != HBA_STATUS_OK) {
					/*
					 * not able to get port attributes.
					 * print out error * message and move
					 * on to the next port
					 */
					fprintf(stderr,
					    gettext("Error: Failed to get port "
						    "(%d) attributes reason: "),
					    portIndex);
					printStatus(status);
					fprintf(stderr, "\n");
					continue;
				}
				processHBA(handle, attrs, portIndex, port,
				    NULL, HBA_PORT, processHBA_flags,
				    INITIATOR_MODE);
				if ((processHBA_flags & PRINT_FCOE) !=
				    PRINT_FCOE &&
				    attrs.VendorSpecificID != 0xFC0E &&
				    printHBANPIVPortInfo(handle,
				    portIndex) != 0) {
					err_cnt++;
				}
			}
			HBA_CloseAdapter(handle);
		    }
		}

		/*
		 * Get the info on the target mode FC port if PRINT_TARGET
		 * is specified.
		 */
		if ((processHBA_flags & PRINT_TARGET) == PRINT_TARGET) {
		    numTgtAdapters = Sun_HBA_GetNumberOfTgtAdapters();
		    if (numTgtAdapters == 0 && numAdapters == 0) {
			fprintf(stdout,
			    gettext("No Adapters Found.\n"));
		    }
		    for (i = 0; i < numTgtAdapters; i++) {
			status = Sun_HBA_GetTgtAdapterName(i, adapterName);
			if (status != HBA_STATUS_OK) {
			    fprintf(stderr, gettext(
				"failed to get adapter %d. Reason: "), i);
			    printStatus(status);
			    fprintf(stderr, "\n");
			    continue;
			}
			if ((handle = Sun_HBA_OpenTgtAdapter(adapterName))
			    == 0) {
			    fprintf(stderr, gettext(
				"Failed to open adapter %s.\n"), adapterName);
			    continue;
			}
			/* get adapater attributes for the given handle */
			memset(&attrs, 0, sizeof (attrs));
			if ((status = HBA_GetAdapterAttributes(handle, &attrs))
			    != HBA_STATUS_OK) {
				fprintf(stderr,
				    gettext("Failed to get target mode adapter"
					"attributes handle(%d) Reason: "),
					handle);
				printStatus(status);
				fprintf(stderr, "\n");
				continue;
			}

			/* process each port on the given adatpter */
			for (portIndex = 0;
			    portIndex < attrs.NumberOfPorts;
			    portIndex++) {
				memset(&port, 0, sizeof (port));
				if ((status = HBA_GetAdapterPortAttributes(
						    handle, portIndex, &port))
				    != HBA_STATUS_OK) {
					/*
					 * not able to get port attributes.
					 * print out error * message and move
					 * on to the next port
					 */
					fprintf(stderr,
					    gettext("Error: Failed to get port "
						    "(%d) attributes reason: "),
					    portIndex);
					printStatus(status);
					fprintf(stderr, "\n");
					continue;
				}
				processHBA(handle, attrs, portIndex, port,
				    NULL, HBA_PORT, processHBA_flags,
				    TARGET_MODE);
			}
		    HBA_CloseAdapter(handle);
		}
	    }
	}

	HBA_FreeLibrary();

	/*
	 * print additional error msg for partial failure when more than
	 * one wwn is specified.
	 */
	if (err_cnt != 0) {
	    if (wwnCount > 1) {
		if (err_cnt == wwnCount) {
		    fprintf(stderr, gettext(
		    "Error: All specified HBA ports are not found\n"));
		} else {
		    fprintf(stderr, gettext(
		    "Error: Some of specified HBA ports are not found\n"));
		}
	    }
	    return (1);
	}

	return (0);
}

/*
 * Search the existing device list
 *
 * Take one of two actions:
 *
 * Add an entry if an entry doesn't exist
 * Add WWN data to it if an entry does exist
 *
 * Arguments:
 *	devList - OS device path list
 *	map - target mapping data
 *	index - index into target mapping data
 *	initiatorPortWWN - HBA port WWN
 *	verbose - boolean indicating whether to get additional data
 *
 * returns:
 *	none
 */
static void
searchDevice(discoveredDevice **devList, HBA_FCPSCSIENTRYV2 entry,
HBA_WWN initiatorPortWWN, HBA_HANDLE handle, boolean_t verbose)
{
	discoveredDevice *discoveredDevList, *newDevice;
	portWWNList *WWNList, *newWWN;
	tgtPortWWNList *newTgtWWN;
	boolean_t foundDevice = B_FALSE, foundWWN;
	struct scsi_inquiry	    inq;
	struct scsi_extended_sense  sense;
	HBA_UINT32		    responseSize, senseSize = 0;
	HBA_UINT8		    inq_status;
	HBA_STATUS		status;

	for (discoveredDevList = *devList; discoveredDevList != NULL;
	    discoveredDevList = discoveredDevList->next) {
		if (strcmp(entry.ScsiId.OSDeviceName,
		    discoveredDevList->OSDeviceName) == 0) {
			/*
			 * if only device names are requested,
			 * no reason to go any further
			 */
			if (verbose == B_FALSE) {
				return;
			}
			foundDevice = B_TRUE;
			break;
		}
	}
	if (foundDevice == B_TRUE) {
		/* add initiator Port WWN if it doesn't exist */
		for (WWNList = discoveredDevList->HBAPortWWN,
		    foundWWN = B_FALSE; WWNList != NULL;
		    WWNList = WWNList->next) {
			if (memcmp((void *)&(WWNList->portWWN),
			    (void *)&initiatorPortWWN,
			    sizeof (HBA_WWN)) == 0) {
				foundWWN = B_TRUE;
				break;
			}
		}
		if (discoveredDevList->inqSuccess == B_FALSE) {
			responseSize = sizeof (struct scsi_inquiry);
			senseSize = sizeof (struct scsi_extended_sense);
			memset(&inq, 0, sizeof (struct scsi_inquiry));
			memset(&sense, 0, sizeof (sense));
			status = HBA_ScsiInquiryV2(
			    handle,
			    initiatorPortWWN,
			    entry.FcpId.PortWWN,
			    entry.FcpId.FcpLun,
			    0, /* CDB Byte 1 */
			    0, /* CDB Byte 2 */
			    &inq, &responseSize,
			    &inq_status,
			    &sense, &senseSize);
			if (status == HBA_STATUS_OK) {
				memcpy(discoveredDevList->VID, inq.inq_vid,
				    sizeof (discoveredDevList->VID));
				memcpy(discoveredDevList->PID, inq.inq_pid,
				    sizeof (discoveredDevList->PID));
				discoveredDevList->dType = inq.inq_dtype;
				discoveredDevList->inqSuccess = B_TRUE;
			}
		}

		if (foundWWN == B_FALSE) {
			newWWN = (portWWNList *)calloc(1, sizeof (portWWNList));
			if (newWWN == NULL) {
				perror("Out of memory");
				exit(1);
			}

			/* insert at head */
			newWWN->next = discoveredDevList->HBAPortWWN;
			discoveredDevList->HBAPortWWN = newWWN;
			memcpy((void *)&(newWWN->portWWN),
			    (void *)&initiatorPortWWN,
			    sizeof (newWWN->portWWN));
			/* add Target Port */
			newWWN->tgtPortWWN = (tgtPortWWNList *)calloc(1,
			    sizeof (tgtPortWWNList));
			if (newWWN->tgtPortWWN == NULL) {
				perror("Out of memory");
				exit(1);
			}

			memcpy((void *)&(newWWN->tgtPortWWN->portWWN),
			    (void *)&(entry.FcpId.PortWWN),
			    sizeof (newWWN->tgtPortWWN->portWWN));
			/* Set LUN data */
			newWWN->tgtPortWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
		} else { /* add it to existing */
			newTgtWWN = (tgtPortWWNList *)calloc(1,
			    sizeof (tgtPortWWNList));
			if (newTgtWWN == NULL) {
				perror("Out of memory");
				exit(1);
			}
			/* insert at head */
			newTgtWWN->next = WWNList->tgtPortWWN;
			WWNList->tgtPortWWN = newTgtWWN;
			memcpy((void *)&(newTgtWWN->portWWN),
			    (void *)&(entry.FcpId.PortWWN),
			    sizeof (newTgtWWN->portWWN));
			/* Set LUN data */
			newTgtWWN->scsiOSLun = entry.ScsiId.ScsiOSLun;
		}
	} else { /* add new entry */
		newDevice = (discoveredDevice *)calloc(1,
		    sizeof (discoveredDevice));
		if (newDevice == NULL) {
			perror("Out of memory");
			exit(1);
		}
		newDevice->next = *devList; /* insert at head */
		*devList = newDevice; /* set new head */

		/* Copy device name */
		strncpy(newDevice->OSDeviceName, entry.ScsiId.OSDeviceName,
		    sizeof (newDevice->OSDeviceName) - 1);

		/*
		 * if only device names are requested,
		 * no reason to go any further
		 */
		if (verbose == B_FALSE) {
			return;
		}

		/*
		 * copy WWN data
		 */
		newDevice->HBAPortWWN = (portWWNList *)calloc(1,
		    sizeof (portWWNList));
		if (newDevice->HBAPortWWN == NULL) {
			perror("Out of memory");
			exit(1);
		}
		memcpy((void *)&(newDevice->HBAPortWWN->portWWN),
		    (void *)&initiatorPortWWN, sizeof (newWWN->portWWN));

		newDevice->HBAPortWWN->tgtPortWWN =
		    (tgtPortWWNList *)calloc(1, sizeof (tgtPortWWNList));
		if (newDevice->HBAPortWWN->tgtPortWWN == NULL) {
			perror("Out of memory");
			exit(1);
		}

		memcpy((void *)&(newDevice->HBAPortWWN->tgtPortWWN->portWWN),
		    (void *)&(entry.FcpId.PortWWN),
		    sizeof (newDevice->HBAPortWWN->tgtPortWWN->portWWN));

		/* Set LUN data */
		newDevice->HBAPortWWN->tgtPortWWN->scsiOSLun =
		    entry.ScsiId.ScsiOSLun;

		responseSize = sizeof (struct scsi_inquiry);
		senseSize = sizeof (struct scsi_extended_sense);
		memset(&inq, 0, sizeof (struct scsi_inquiry));
		memset(&sense, 0, sizeof (sense));
		status = HBA_ScsiInquiryV2(
		    handle,
		    initiatorPortWWN,
		    entry.FcpId.PortWWN,
		    entry.FcpId.FcpLun,
		    0, /* CDB Byte 1 */
		    0, /* CDB Byte 2 */
		    &inq, &responseSize,
		    &inq_status,
		    &sense, &senseSize);
		if (status != HBA_STATUS_OK) {
			/* initialize VID/PID/dType as "Unknown" */
			strcpy(newDevice->VID, "Unknown");
			strcpy(newDevice->PID, "Unknown");
			newDevice->dType = DTYPE_UNKNOWN;
			/* initialize inq status */
			newDevice->inqSuccess = B_FALSE;
		} else {
			memcpy(newDevice->VID, inq.inq_vid,
			    sizeof (newDevice->VID));
			memcpy(newDevice->PID, inq.inq_pid,
			    sizeof (newDevice->PID));
			newDevice->dType = inq.inq_dtype;
			/* initialize inq status */
			newDevice->inqSuccess = B_TRUE;
		}
	}
}


/*
 * process the logical-unit object
 *
 * Arguments:
 *	luCount - count of the number of device paths in paths_argv
 *	    if pathCount > 0, then we will only print information for
 *		the device paths listed in paths_argv
 *	    if pathCount == 0, then we will print information on all device
 *	        paths
 *	luArgv - argument array of device paths
 *	options - any options specified by the caller
 *
 * returns:
 *	0	if successful
 *	> 0	otherwise
 */
int
fc_util_list_logicalunit(int luCount, char **luArgv, cmdOptions_t *options)
{
	int			pathCtr, numAdapters, i, count;
	HBA_STATUS		status;
	char			adapterName[256];
	HBA_HANDLE		handle;
	HBA_PORTATTRIBUTES	port;
	HBA_ADAPTERATTRIBUTES	attrs;
	int			portIndex = 0;
	int			ret = 0;
	boolean_t		verbose = B_FALSE;
	HBA_FCPTARGETMAPPINGV2	*map = NULL;
	discoveredDevice	*devListWalk, *devList = NULL;
	boolean_t		pathFound;

	/* process each of the options */
	for (; options->optval; options++) {
		if (options->optval == 'v') {
			verbose = B_TRUE;
		}
	}

	if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
		fprintf(stderr,
		    gettext("Failed to load FC-HBA common library\n"));
		printStatus(status);
		fprintf(stderr, "\n");
		return (1);
	}
	/*
	 * Retrieve all device paths. We'll need to traverse the list
	 * until we find the input paths or all paths if none were given. We
	 * cannot print as we go since there can be duplicate paths returned
	 */
	numAdapters = HBA_GetNumberOfAdapters();
	if (numAdapters == 0) {
		return (0);
	}
	for (i = 0; i < numAdapters; i++) {
		int times;
		status = HBA_GetAdapterName(i, adapterName);
		if (status != HBA_STATUS_OK) {
			fprintf(stderr, gettext(
			    "Failed to get adapter %d. Reason: "), i);
			printStatus(status);
			fprintf(stderr, "\n");
			ret++;
			continue;
		}
		if ((handle = HBA_OpenAdapter(adapterName)) == 0) {
			fprintf(stderr, gettext("Failed to open adapter %s\n"),
			    adapterName);
			ret++;
			continue;
		}
		/* get adapter attributes for the given handle */
		memset(&attrs, 0, sizeof (attrs));
		times = 0;
		status = HBA_GetAdapterAttributes(handle, &attrs);
		while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
		    status == HBA_STATUS_ERROR_BUSY) &&
		    times++ < HBA_MAX_RETRIES) {
			(void) sleep(1);
			status = HBA_GetAdapterAttributes(handle, &attrs);
			if (status == HBA_STATUS_OK) {
				break;
			}
		}
		if (status != HBA_STATUS_OK) {
			fprintf(stderr,
			    gettext("Failed to get adapter attributes "
				    "handle(%d) Reason: "), handle);
			printStatus(status);
			fprintf(stderr, "\n");
			ret++;
			HBA_CloseAdapter(handle);
			continue;
		}

		/* process each port on adapter */
		for (portIndex = 0; portIndex < attrs.NumberOfPorts;
		    portIndex++) {
			memset(&port, 0, sizeof (port));
			if ((status = HBA_GetAdapterPortAttributes(handle,
			    portIndex, &port)) != HBA_STATUS_OK) {
				/*
				 * not able to get port attributes.
				 * print out error message and move
				 * on to the next port
				 */
				fprintf(stderr, gettext("Failed to get port "
				    "(%d) attributes reason: "),
				    portIndex);
				printStatus(status);
				fprintf(stderr, "\n");
				ret++;
				continue;
			}

			/* get OS Device Paths */
			getTargetMapping(handle, port.PortWWN, &map);
			if (map != NULL) {
				for (count = 0; count < map->NumberOfEntries;
				    count++) {
					searchDevice(&devList,
					    map->entry[count], port.PortWWN,
					    handle, verbose);
				}
			}
		}
		HBA_CloseAdapter(handle);
	}
	HBA_FreeLibrary();

	if (luCount == 0) {
		/* list all paths */
		for (devListWalk = devList; devListWalk != NULL;
		    devListWalk = devListWalk->next) {
			printOSDeviceNameInfo(devListWalk, verbose);
		}
	} else {
		/*
		 * list any paths not found first
		 * this gives the user cleaner output
		 */
		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
			for (devListWalk = devList, pathFound = B_FALSE;
			    devListWalk != NULL;
			    devListWalk = devListWalk->next) {
				if (strcmp(devListWalk->OSDeviceName,
				    luArgv[pathCtr]) == 0) {
					pathFound = B_TRUE;
				}
			}
			if (pathFound == B_FALSE) {
				fprintf(stderr, "%s: no such path\n",
				    luArgv[pathCtr]);
				ret++;
			}
		}
		/* list all paths requested in order requested */
		for (pathCtr = 0; pathCtr < luCount; pathCtr++) {
			for (devListWalk = devList; devListWalk != NULL;
			    devListWalk = devListWalk->next) {
				if (strcmp(devListWalk->OSDeviceName,
				    luArgv[pathCtr]) == 0) {
					printOSDeviceNameInfo(devListWalk,
					    verbose);
				}
			}
		}
	}
	return (ret);
}