root/usr/src/cmd/fcinfo/fcinfo-list.c
/*
 * 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);
}