root/usr/src/cmd/fcinfo/fcadm-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 <libscf.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <syslog.h>
#include <strings.h>
#include <ctype.h>
#include <fcinfo.h>


#define FCADM_RETRY_TIMES       10
#define FCADM_SLEEP_TIME        1

static char *
WWN2str(char *buf, HBA_WWN *wwn) {
        int j;
        unsigned char *pc = (unsigned char *)&(wwn->wwn[0]);
        buf[0] = '\0';
        for (j = 0; j < 16; j += 2) {
                sprintf(&buf[j], "%02X", (int)*pc++);
        }
        return (buf);
}

static int
isValidWWN(char *wwn)
{
        int index;

        if (wwn == NULL) {
                return (0);
        }

        if (strlen(wwn) != 16) {
                return (0);
        }

        for (index = 0; index < 16; index++) {
                if (isxdigit(wwn[index])) {
                        continue;
                }
                return (0);
        }
        return (1);
}


/*
 * Initialize scf stmf service access
 * handle - returned handle
 * service - returned service handle
 */
static int
cfgInit(scf_handle_t **handle, scf_service_t **service)
{
        scf_scope_t     *scope = NULL;
        int             ret;

        if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
                /* log error */
                ret = NPIV_ERROR;
                goto err;
        }

        if (scf_handle_bind(*handle) == -1) {
                /* log error */
                ret = NPIV_ERROR;
                goto err;
        }

        if ((*service = scf_service_create(*handle)) == NULL) {
                /* log error */
                ret = NPIV_ERROR;
                goto err;
        }

        if ((scope = scf_scope_create(*handle)) == NULL) {
                /* log error */
                ret = NPIV_ERROR;
                goto err;
        }

        if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
                /* log error */
                ret = NPIV_ERROR;
                goto err;
        }

        if (scf_scope_get_service(scope, NPIV_SERVICE, *service) == -1) {
                /* log error */
                ret = NPIV_ERROR_SERVICE_NOT_FOUND;
                goto err;
        }

        scf_scope_destroy(scope);

        return (NPIV_SUCCESS);

err:
        if (*handle != NULL) {
                scf_handle_destroy(*handle);
        }
        if (*service != NULL) {
                scf_service_destroy(*service);
                *service = NULL;
        }
        if (scope != NULL) {
                scf_scope_destroy(scope);
        }
        return (ret);
}

static int
npivAddRemoveNPIVEntry(char *ppwwn, char *vnwwn,
    char *vpwwn, int vindex, int addRemoveFlag) {
        scf_handle_t    *handle = NULL;
        scf_service_t   *svc = NULL;
        scf_propertygroup_t     *pg = NULL;
        scf_transaction_t       *tran = NULL;
        scf_transaction_entry_t *entry = NULL;
        scf_property_t  *prop = NULL;
        scf_value_t     *valueLookup = NULL;
        scf_iter_t      *valueIter = NULL;
        scf_value_t     **valueSet = NULL;
        int     ret = NPIV_SUCCESS;
        boolean_t       createProp = B_FALSE;
        int     lastAlloc = 0;
        char    buf[NPIV_PORT_LIST_LENGTH] = {0};
        char    memberName[NPIV_PORT_LIST_LENGTH] = {0};
        boolean_t       found = B_FALSE;
        int     i = 0;
        int     valueArraySize = 0;
        int     commitRet;

        if (vnwwn) {
                sprintf(memberName, "%s:%s:%s:%d", ppwwn, vpwwn, vnwwn, vindex);
        } else {
                sprintf(memberName, "%s:%s", ppwwn, vpwwn);
        }

        ret = cfgInit(&handle, &svc);
        if (ret != NPIV_SUCCESS) {
                goto out;
        }

        if (((pg = scf_pg_create(handle)) == NULL) ||
            ((tran = scf_transaction_create(handle)) == NULL) ||
            ((entry = scf_entry_create(handle)) == NULL) ||
            ((prop = scf_property_create(handle)) == NULL) ||
            ((valueIter = scf_iter_create(handle)) == NULL)) {
                ret = NPIV_ERROR;
                goto out;
        }

        /* get property group or create it */
        if (scf_service_get_pg(svc, NPIV_PG_NAME, pg) == -1) {
                if ((scf_error() == SCF_ERROR_NOT_FOUND) &&
                    (addRemoveFlag == NPIV_ADD)) {
                        if (scf_service_add_pg(svc, NPIV_PG_NAME,
                            SCF_GROUP_APPLICATION, 0, pg) == -1) {
                                syslog(LOG_ERR, "add pg failed - %s",
                                    scf_strerror(scf_error()));
                                ret = NPIV_ERROR;
                        } else {
                                createProp = B_TRUE;
                        }
                } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
                        ret = NPIV_ERROR_NOT_FOUND;
                } else {
                        syslog(LOG_ERR, "get pg failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                }
                if (ret != NPIV_SUCCESS) {
                        goto out;
                }
        }

        /* Begin the transaction */
        if (scf_transaction_start(tran, pg) == -1) {
                syslog(LOG_ERR, "start transaction failed - %s",
                    scf_strerror(scf_error()));
                ret = NPIV_ERROR;
                goto out;
        }

        valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
            * (lastAlloc = PORT_LIST_ALLOC));
        if (valueSet == NULL) {
                ret = NPIV_ERROR_NOMEM;
                goto out;
        }

        if (createProp) {
                if (scf_transaction_property_new(tran, entry, NPIV_PORT_LIST,
                    SCF_TYPE_USTRING) == -1) {
                        if (scf_error() == SCF_ERROR_EXISTS) {
                                ret = NPIV_ERROR_EXISTS;
                        } else {
                                syslog(LOG_ERR,
                                    "transaction property new failed - %s",
                                    scf_strerror(scf_error()));
                                ret = NPIV_ERROR;
                        }
                        goto out;
                }
        } else {
                if (scf_transaction_property_change(tran, entry,
                    NPIV_PORT_LIST, SCF_TYPE_USTRING) == -1) {
                        syslog(LOG_ERR,
                            "transaction property change failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                }

                if (scf_pg_get_property(pg, NPIV_PORT_LIST, prop) == -1) {
                        syslog(LOG_ERR, "get property failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                }

                valueLookup = scf_value_create(handle);
                if (valueLookup == NULL) {
                        syslog(LOG_ERR, "scf value alloc failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                }

                if (scf_iter_property_values(valueIter, prop) == -1) {
                        syslog(LOG_ERR, "iter value failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                }

                while (scf_iter_next_value(valueIter, valueLookup) == 1) {
                        bzero(buf, sizeof (buf));
                        if (scf_value_get_ustring(valueLookup,
                            buf, MAXNAMELEN) == -1) {
                                syslog(LOG_ERR, "iter value failed - %s",
                                    scf_strerror(scf_error()));
                                ret = NPIV_ERROR;
                                break;
                        }

                        if ((strlen(buf) >= strlen(memberName)) &&
                            bcmp(buf, memberName, strlen(memberName)) == 0) {
                                if (addRemoveFlag == NPIV_ADD) {
                                        ret = NPIV_ERROR_EXISTS;
                                        break;
                                } else {
                                        found = B_TRUE;
                                        continue;
                                }
                        }

                        valueSet[i] = scf_value_create(handle);
                        if (valueSet[i] == NULL) {
                                syslog(LOG_ERR, "scf value alloc failed - %s",
                                    scf_strerror(scf_error()));
                                ret = NPIV_ERROR;
                                break;
                        }

                        if (scf_value_set_ustring(valueSet[i], buf) == -1) {
                                syslog(LOG_ERR, "set value failed - %s",
                                    scf_strerror(scf_error()));
                                ret = NPIV_ERROR;
                                break;
                        }

                        if (scf_entry_add_value(entry, valueSet[i]) == -1) {
                                syslog(LOG_ERR, "add value failed - %s",
                                    scf_strerror(scf_error()));
                                ret = NPIV_ERROR;
                                break;
                        }

                        i++;

                        if (i >= lastAlloc) {
                                lastAlloc += PORT_LIST_ALLOC;
                                valueSet = realloc(valueSet,
                                    sizeof (*valueSet) * lastAlloc);
                                if (valueSet == NULL) {
                                        ret = NPIV_ERROR;
                                        break;
                                }
                        }
                }
        }

        valueArraySize = i;
        if (!found && (addRemoveFlag == NPIV_REMOVE)) {
                ret = NPIV_ERROR_MEMBER_NOT_FOUND;
        }
        if (ret != NPIV_SUCCESS) {
                goto out;
        }

        if (addRemoveFlag == NPIV_ADD) {
                /*
                 * Now create the new entry
                 */
                valueSet[i] = scf_value_create(handle);
                if (valueSet[i] == NULL) {
                        syslog(LOG_ERR, "scf value alloc failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                } else {
                        valueArraySize++;
                }

                /*
                 * Set the new member name
                 */
                if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
                        syslog(LOG_ERR, "set value failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                }

                /*
                 * Add the new member
                 */
                if (scf_entry_add_value(entry, valueSet[i]) == -1) {
                        syslog(LOG_ERR, "add value failed - %s",
                            scf_strerror(scf_error()));
                        ret = NPIV_ERROR;
                        goto out;
                }
        }

        if ((commitRet = scf_transaction_commit(tran)) != 1) {
                syslog(LOG_ERR, "transaction commit failed - %s",
                    scf_strerror(scf_error()));
                if (commitRet == 0) {
                        ret = NPIV_ERROR_BUSY;
                } else {
                        ret = NPIV_ERROR;
                }
                goto out;
        }

out:
        /*
         * Free resources
         */
        if (handle != NULL) {
                scf_handle_destroy(handle);
        }
        if (svc != NULL) {
                scf_service_destroy(svc);
        }
        if (pg != NULL) {
                scf_pg_destroy(pg);
        }
        if (tran != NULL) {
                scf_transaction_destroy(tran);
        }
        if (entry != NULL) {
                scf_entry_destroy(entry);
        }
        if (prop != NULL) {
                scf_property_destroy(prop);
        }
        if (valueIter != NULL) {
                scf_iter_destroy(valueIter);
        }
        if (valueLookup != NULL) {
                scf_value_destroy(valueLookup);
        }

        /*
         * Free valueSet scf resources
         */
        if (valueArraySize > 0) {
                for (i = 0; i < valueArraySize; i++) {
                        scf_value_destroy(valueSet[i]);
                }
        }
        /*
         * Now free the pointer array to the resources
         */
        if (valueSet != NULL) {
                free(valueSet);
        }

        return (ret);
}

static int
retrieveNPIVAttrs(HBA_HANDLE handle, HBA_WWN portWWN,
    HBA_PORTNPIVATTRIBUTES *npivattrs, HBA_UINT32 *portIndex) {
        HBA_STATUS              status;
        HBA_ADAPTERATTRIBUTES   attrs;
        HBA_PORTATTRIBUTES      portattrs;
        int                     portCtr;
        int                     times = 0;

        /* argument checking */
        if (npivattrs == NULL || portIndex == NULL) {
                return (1);
        }

        memset(&attrs, 0, sizeof (HBA_ADAPTERATTRIBUTES));
        status = HBA_GetAdapterAttributes(handle, &attrs);
        while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
            status == HBA_STATUS_ERROR_BUSY) &&
            times++ < 130) {
                status = HBA_GetAdapterAttributes(handle, &attrs);
                if (status == HBA_STATUS_OK) {
                        break;
                }
                (void) sleep(1);
        }
        if (status != HBA_STATUS_OK) {
                return (1);
        }

        memset(&portattrs, 0, sizeof (HBA_PORTATTRIBUTES));
        for (portCtr = 0; portCtr < attrs.NumberOfPorts; portCtr++) {
                status = HBA_GetAdapterPortAttributes(handle,
                    portCtr, &portattrs);
                times = 0;
                while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
                    status == HBA_STATUS_ERROR_BUSY) &&
                    times++ < HBA_MAX_RETRIES) {
                        status = HBA_GetAdapterPortAttributes(handle,
                            portCtr, &portattrs);
                        if (status == HBA_STATUS_OK) {
                                break;
                        }
                        (void) sleep(1);
                }

                if (status != HBA_STATUS_OK) {
                        return (1);
                }

                if (memcmp(portWWN.wwn, portattrs.PortWWN.wwn,
                    sizeof (portattrs.PortWWN.wwn)) == 0) {
                        break;
                }
        }
        if (portCtr >= attrs.NumberOfPorts) {
                *portIndex = 0;
                return (1);
        }
        *portIndex = portCtr;

        status = Sun_HBA_GetPortNPIVAttributes(handle, portCtr, npivattrs);
        times = 0;
        while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
            status == HBA_STATUS_ERROR_BUSY) &&
            times++ < HBA_MAX_RETRIES) {
                status = Sun_HBA_GetPortNPIVAttributes(handle,
                    portCtr, npivattrs);
                if (status == HBA_STATUS_OK) {
                        break;
                }
                (void) sleep(1);
        }
        if (status != HBA_STATUS_OK) {
                return (1);
        }

        return (0);
}


int
fc_util_delete_npivport(int wwnCount, char **wwn_argv,
    cmdOptions_t *options)
{
        uint64_t        physicalportWWN, virtualportWWN;
        HBA_WWN         portWWN, vportWWN;
        HBA_STATUS      status;
        HBA_HANDLE      handle;
        HBA_PORTNPIVATTRIBUTES  npivattrs;
        HBA_UINT32      portIndex;
        char            pwwn[17];
        int             times;

        if (wwnCount != 1) {
                fprintf(stderr,
                    gettext("Invalid Parameter\n"));
                return (1);
        }

        for (; options->optval; options++) {
                switch (options->optval) {
                case 'p':
                        if (!isValidWWN(options->optarg)) {
                                fprintf(stderr,
                                    gettext("Invalid Port WWN\n"));
                                return (1);
                        }
                        sscanf(options->optarg, "%016llx", &virtualportWWN);
                        break;
                default:
                        return (1);
                }
        }

        if (!isValidWWN(wwn_argv[0])) {
                fprintf(stderr,
                    gettext("Invalid Physical Port WWN\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);
        }
        sscanf(wwn_argv[0], "%016llx", &physicalportWWN);
        physicalportWWN = htonll(physicalportWWN);
        memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN));

        virtualportWWN = htonll(virtualportWWN);
        memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN));

        status = HBA_OpenAdapterByWWN(&handle, portWWN);
        if (status != HBA_STATUS_OK) {
                fprintf(stderr,
                    gettext("Error: HBA port %s: not found\n"),
                    wwn_argv[0]);
                HBA_FreeLibrary();
                return (1);
        }

        /* Get physical port NPIV attributes */
        if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) {
                /* Check port NPIV attributes */
                if (npivattrs.MaxNumberOfNPIVPorts == 0) {
                        fprintf(stderr,
                            gettext("Error: NPIV not Supported\n"));
                        HBA_CloseAdapter(handle);
                        HBA_FreeLibrary();
                        return (1);
                }

                /* Delete a virtual port */
                status = Sun_HBA_DeleteNPIVPort(handle, portIndex,
                    vportWWN);
                times = 0;
                while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
                    status == HBA_STATUS_ERROR_BUSY) &&
                    times++ < HBA_MAX_RETRIES) {
                        (void) sleep(1);
                        status = Sun_HBA_DeleteNPIVPort(handle, portIndex,
                            vportWWN);
                        if (status == HBA_STATUS_OK) {
                                break;
                        }
                }
                if (status != HBA_STATUS_OK) {
                        fprintf(stderr,
                            gettext("Error: failed to delete a npiv port\n"));
                        HBA_CloseAdapter(handle);
                        HBA_FreeLibrary();
                        return (1);
                }
        } else {
                fprintf(stderr,
                    gettext("Error: failed to get port NPIV attributes\n"));
                HBA_CloseAdapter(handle);
                HBA_FreeLibrary();
                return (1);
        }

        HBA_CloseAdapter(handle);
        HBA_FreeLibrary();

        WWN2str(pwwn, &vportWWN);
        npivAddRemoveNPIVEntry(wwn_argv[0],
            NULL, pwwn, 0, NPIV_REMOVE);

        return (0);
}

int
fc_util_create_npivport(int wwnCount,
    char **wwn_argv, cmdOptions_t *options)
{
        uint64_t        physicalportWWN, virtualnodeWWN, virtualportWWN;
        HBA_WWN         portWWN, vnodeWWN, vportWWN;
        HBA_STATUS      status;
        HBA_HANDLE      handle;
        HBA_PORTNPIVATTRIBUTES  npivattrs;
        HBA_UINT32      portIndex;
        HBA_UINT32      npivportIndex = 0;
        char            nwwn[17], pwwn[17];
        int             randomflag = 0;
        int             times;

        if (wwnCount != 1) {
                fprintf(stderr,
                    gettext("Invalid Parameter\n"));
                return (1);
        }

        for (; options->optval; options++) {
                switch (options->optval) {
                case 'p':
                        if (!isValidWWN(options->optarg)) {
                                fprintf(stderr,
                                    gettext("Invalid Port WWN\n"));
                                return (1);
                        }
                        sscanf(options->optarg, "%016llx", &virtualportWWN);
                        randomflag++;
                        break;
                case 'n':
                        if (!isValidWWN(options->optarg)) {
                                fprintf(stderr,
                                    gettext("Invalid Node WWN\n"));
                                return (1);
                        }
                        sscanf(options->optarg, "%016llx", &virtualnodeWWN);
                        randomflag++;
                        break;
                default:
                        return (1);
                }
        }

        if (!isValidWWN(wwn_argv[0])) {
                fprintf(stderr,
                    gettext("Invalid Physical Port WWN\n"));
                wwnCount = 0;
                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);
        }

        sscanf(wwn_argv[0], "%016llx", &physicalportWWN);
        physicalportWWN = htonll(physicalportWWN);
        memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN));

        status = HBA_OpenAdapterByWWN(&handle, portWWN);
        if (status != HBA_STATUS_OK) {
                fprintf(stderr,
                    gettext("Error: HBA port %s: not found\n"),
                    wwn_argv[0]);
                HBA_FreeLibrary();
                return (1);
        }

        if (randomflag != 2) {
                status = Sun_HBA_AdapterCreateWWN(handle, 0,
                    &vnodeWWN, &vportWWN, NULL, HBA_CREATE_WWN_RANDOM);
                if (status != HBA_STATUS_OK) {
                        fprintf(stderr,
                            gettext("Error: Fail to get Random WWN\n"));
                        HBA_CloseAdapter(handle);
                        HBA_FreeLibrary();
                        return (1);
                }
        } else {
                virtualnodeWWN = htonll(virtualnodeWWN);
                memcpy(vnodeWWN.wwn, &virtualnodeWWN, sizeof (virtualnodeWWN));
                virtualportWWN = htonll(virtualportWWN);
                memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN));
        }

        if (memcmp(vnodeWWN.wwn, vportWWN.wwn, 8) == 0) {
                fprintf(stderr,
                    gettext("Error: Port WWN is same as Node WWN\n"));
                HBA_CloseAdapter(handle);
                HBA_FreeLibrary();
                return (1);
        }

        /* Get physical port NPIV attributes */
        if (retrieveNPIVAttrs(handle, portWWN, &npivattrs, &portIndex) == 0) {
                /* Check port NPIV attributes */
                if (npivattrs.MaxNumberOfNPIVPorts == 0) {
                        fprintf(stderr,
                            gettext("Error: NPIV not Supported\n"));
                        HBA_CloseAdapter(handle);
                        HBA_FreeLibrary();
                        return (1);
                }
                if (npivattrs.MaxNumberOfNPIVPorts ==
                    npivattrs.NumberOfNPIVPorts) {
                        fprintf(stderr,
                            gettext("Error: Can not create more NPIV port\n"));
                        HBA_CloseAdapter(handle);
                        HBA_FreeLibrary();
                        return (1);
                }

                /* Create a virtual port */
                status = Sun_HBA_CreateNPIVPort(handle, portIndex,
                    vnodeWWN, vportWWN, &npivportIndex);
                times = 0;
                while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
                    status == HBA_STATUS_ERROR_BUSY) &&
                    times++ < HBA_MAX_RETRIES) {
                        (void) sleep(1);
                        status = Sun_HBA_CreateNPIVPort(handle, portIndex,
                            vnodeWWN, vportWWN, &npivportIndex);
                        if (status == HBA_STATUS_OK) {
                                break;
                        }
                }

                if (status != HBA_STATUS_OK) {
                        fprintf(stderr,
                            gettext("Error: failed to create a npiv port\n"));
                        HBA_CloseAdapter(handle);
                        HBA_FreeLibrary();
                        return (1);
                }
        } else {
                fprintf(stderr,
                    gettext("Error: failed to get port NPIV attributes\n"));
                HBA_CloseAdapter(handle);
                HBA_FreeLibrary();
                return (1);
        }

        HBA_CloseAdapter(handle);
        HBA_FreeLibrary();

        WWN2str(nwwn, &vnodeWWN);
        WWN2str(pwwn, &vportWWN);
        npivAddRemoveNPIVEntry(wwn_argv[0],
            nwwn, pwwn, npivportIndex, NPIV_ADD);

        return (0);
}

int
create_npivport(char *ppwwn_str, char *vnwwn_str,
    char *vpwwn_str, int vindex)
{
        uint64_t        physicalportWWN, virtualnodeWWN, virtualportWWN;
        HBA_WWN         portWWN, vnodeWWN, vportWWN;
        HBA_STATUS      status;
        HBA_HANDLE      handle;
        HBA_PORTNPIVATTRIBUTES  npivattrs;
        HBA_UINT32      portIndex;
        HBA_UINT32      npivportIndex;
        int             times = 0;

        sscanf(ppwwn_str, "%016llx", &physicalportWWN);
        physicalportWWN = htonll(physicalportWWN);
        memcpy(portWWN.wwn, &physicalportWWN, sizeof (physicalportWWN));
        sscanf(vnwwn_str, "%016llx", &virtualnodeWWN);
        virtualnodeWWN = htonll(virtualnodeWWN);
        memcpy(vnodeWWN.wwn, &virtualnodeWWN, sizeof (virtualnodeWWN));
        sscanf(vpwwn_str, "%016llx", &virtualportWWN);
        virtualportWWN = htonll(virtualportWWN);
        memcpy(vportWWN.wwn, &virtualportWWN, sizeof (virtualportWWN));
        npivportIndex = vindex;

        status = HBA_OpenAdapterByWWN(&handle, portWWN);
        while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
            status == HBA_STATUS_ERROR_BUSY) {
                (void) sleep(FCADM_SLEEP_TIME);
                status = HBA_OpenAdapterByWWN(&handle, portWWN);
                if (times++ > FCADM_RETRY_TIMES) {
                        return (1);
                }
        }

        /* Get physical port NPIV attributes */
        if (retrieveNPIVAttrs(handle, portWWN,
            &npivattrs, &portIndex) == 0) {
                /* Check port NPIV attributes */
                if (npivattrs.MaxNumberOfNPIVPorts == 0) {
                        goto failed;
                }
                if (npivattrs.MaxNumberOfNPIVPorts ==
                    npivattrs.NumberOfNPIVPorts) {
                        goto failed;
                }

                /* Create a virtual port */
                status = Sun_HBA_CreateNPIVPort(handle, portIndex,
                    vnodeWWN, vportWWN, &npivportIndex);
                times = 0;
                while (status == HBA_STATUS_ERROR_TRY_AGAIN ||
                    status == HBA_STATUS_ERROR_BUSY) {
                        (void) sleep(FCADM_SLEEP_TIME);
                        status = Sun_HBA_CreateNPIVPort(handle, portIndex,
                            vnodeWWN, vportWWN, &npivportIndex);
                        if (times++ > FCADM_RETRY_TIMES) {
                                goto failed;
                        }
                }
        }

failed:
        HBA_CloseAdapter(handle);

        return (0);
}

int
fc_util_create_portlist()
{
        scf_handle_t    *handle = NULL;
        scf_service_t   *svc = NULL;
        scf_propertygroup_t     *pg = NULL;
        scf_transaction_t       *tran = NULL;
        scf_transaction_entry_t *entry = NULL;
        scf_property_t          *prop = NULL;
        scf_value_t     *valueLookup = NULL;
        scf_iter_t      *valueIter = NULL;
        char            buf[NPIV_PORT_LIST_LENGTH] = {0};
        int             commitRet;

        commitRet = cfgInit(&handle, &svc);
        if (commitRet != NPIV_SUCCESS) {
                goto out;
        }

        if (((pg = scf_pg_create(handle)) == NULL) ||
            ((tran = scf_transaction_create(handle)) == NULL) ||
            ((entry = scf_entry_create(handle)) == NULL) ||
            ((prop = scf_property_create(handle)) == NULL) ||
            ((valueIter = scf_iter_create(handle)) == NULL)) {
                goto out;
        }

        /* get property group or create it */
        if (scf_service_get_pg(svc, NPIV_PG_NAME, pg) == -1) {
                goto out;
        }

        if (scf_pg_get_property(pg, NPIV_PORT_LIST, prop) == -1) {
                syslog(LOG_ERR, "get property failed - %s",
                    scf_strerror(scf_error()));
                goto out;
        }

        valueLookup = scf_value_create(handle);
        if (valueLookup == NULL) {
                syslog(LOG_ERR, "scf value alloc failed - %s",
                    scf_strerror(scf_error()));
                goto out;
        }

        if (scf_iter_property_values(valueIter, prop) == -1) {
                syslog(LOG_ERR, "iter value failed - %s",
                    scf_strerror(scf_error()));
                goto out;
        }

        if (HBA_LoadLibrary() != HBA_STATUS_OK) {
                goto out;
        }
        HBA_GetNumberOfAdapters();

        while (scf_iter_next_value(valueIter, valueLookup) == 1) {
                char ppwwn[17] = {0};
                char vnwwn[17] = {0};
                char vpwwn[17] = {0};
                int vindex = 0;

                bzero(buf, sizeof (buf));
                if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
                        syslog(LOG_ERR, "iter value failed - %s",
                            scf_strerror(scf_error()));
                        break;
                }

                sscanf(buf, "%16s:%16s:%16s:%d", ppwwn, vpwwn, vnwwn, &vindex);
                create_npivport(ppwwn, vnwwn, vpwwn, vindex);
        }

        HBA_FreeLibrary();
out:
        /*
         * Free resources
         */
        if (handle != NULL) {
                scf_handle_destroy(handle);
        }
        if (svc != NULL) {
                scf_service_destroy(svc);
        }
        if (pg != NULL) {
                scf_pg_destroy(pg);
        }
        if (tran != NULL) {
                scf_transaction_destroy(tran);
        }
        if (entry != NULL) {
                scf_entry_destroy(entry);
        }
        if (prop != NULL) {
                scf_property_destroy(prop);
        }
        if (valueIter != NULL) {
                scf_iter_destroy(valueIter);
        }
        if (valueLookup != NULL) {
                scf_value_destroy(valueLookup);
        }

        return (0);
}

/* ARGSUSED */
int
fc_util_force_lip(int objects, char *argv[])
{
        uint64_t        hbaWWN;
        HBA_WWN         myWWN;
        HBA_HANDLE      handle;
        HBA_STATUS      status;
        int             rval = 0;

        if ((status = HBA_LoadLibrary()) != HBA_STATUS_OK) {
                fprintf(stderr, gettext("Failed to load FC-HBA library\n"));
                printStatus(status);
                fprintf(stderr, "\n");
                return (1);
        }

        sscanf(argv[0], "%016llx", &hbaWWN);
        hbaWWN = htonll(hbaWWN);
        memcpy(myWWN.wwn, &hbaWWN, sizeof (hbaWWN));

        /*
         * Try target mode first
         */
        if ((status = Sun_HBA_OpenTgtAdapterByWWN(&handle, myWWN)) !=
            HBA_STATUS_OK) {
                /*
                 * Continue to try initiator mode
                 */
                if ((status = HBA_OpenAdapterByWWN(&handle, myWWN)) !=
                    HBA_STATUS_OK) {
                        fprintf(stderr, gettext("Error: HBA %s not found\n"),
                            argv[0]);
                        return (0);
                }
        }

        status = Sun_HBA_ForceLip(handle, &rval);
        if ((status != HBA_STATUS_OK) || (rval != 0)) {
                fprintf(stderr, gettext("Error: Failed to reinitialize the "
                    "link of HBA %s\n"), argv[0]);
        }

        return (0);
}