root/usr/src/lib/libstmf/common/stmf.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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2012 Milan Jurik. All rights reserved.
 */

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libintl.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <libnvpair.h>
#include <pthread.h>
#include <syslog.h>
#include <libstmf.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <store.h>
#include <locale.h>
#include <math.h>
#include <libstmf_impl.h>
#include <sys/stmf_ioctl.h>
#include <sys/stmf_sbd_ioctl.h>
#include <sys/pppt_ioctl.h>
#include <macros.h>

#define STMF_PATH    "/devices/pseudo/stmf@0:admin"
#define SBD_PATH    "/devices/pseudo/stmf_sbd@0:admin"
#define PPPT_PATH    "/devices/pseudo/pppt@0:pppt"

#define EUI "eui."
#define WWN "wwn."
#define IQN "iqn."
#define LU_ASCII_GUID_SIZE 32
#define LU_GUID_SIZE 16
#define OUI_ASCII_SIZE 6
#define HOST_ID_ASCII_SIZE 8
#define OUI_SIZE 3
#define HOST_ID_SIZE 4
#define IDENT_LENGTH_BYTE 3

/* various initial allocation values */
#define ALLOC_LU                8192
#define ALLOC_TARGET_PORT       2048
#define ALLOC_PROVIDER          64
#define ALLOC_GROUP             2048
#define ALLOC_SESSION           2048
#define ALLOC_VE                256
#define ALLOC_PP_DATA_SIZE      128*1024
#define ALLOC_GRP_MEMBER        256

#define MAX_ISCSI_NAME  223
#define MAX_SERIAL_SIZE 252 + 1
#define MAX_LU_ALIAS_SIZE 256
#define MAX_SBD_PROPS   MAXPATHLEN + MAX_SERIAL_SIZE + MAX_LU_ALIAS_SIZE

#define OPEN_STMF 0
#define OPEN_EXCL_STMF O_EXCL

#define OPEN_SBD 0
#define OPEN_EXCL_SBD O_EXCL

#define OPEN_PPPT 0
#define OPEN_EXCL_PPPT O_EXCL

#define LOGICAL_UNIT_TYPE 0
#define TARGET_TYPE 1
#define STMF_SERVICE_TYPE 2

#define HOST_GROUP   1
#define TARGET_GROUP 2

/* set default persistence here */
#define STMF_DEFAULT_PERSIST    STMF_PERSIST_SMF

#define MAX_PROVIDER_RETRY 30

static int openStmf(int, int *fd);
static int openSbd(int, int *fd);
static int openPppt(int, int *fd);
static int groupIoctl(int fd, int cmd, stmfGroupName *);
static int loadStore(int fd);
static int initializeConfig();
static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *);
static int guidCompare(const void *, const void *);
static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *);
static int loadHostGroups(int fd, stmfGroupList *);
static int loadTargetGroups(int fd, stmfGroupList *);
static int getStmfState(stmf_state_desc_t *);
static int setStmfState(int fd, stmf_state_desc_t *, int);
static int setProviderData(int fd, char *, nvlist_t *, int, uint64_t *);
static int createDiskResource(luResourceImpl *);
static int createDiskLu(diskResource *, stmfGuid *);
static int deleteDiskLu(stmfGuid *luGuid);
static int getDiskProp(luResourceImpl *, uint32_t, char *, size_t *);
static int getDiskAllProps(stmfGuid *luGuid, luResource *hdl);
static int loadDiskPropsFromDriver(luResourceImpl *, sbd_lu_props_t *);
static int removeGuidFromDiskStore(stmfGuid *);
static int addGuidToDiskStore(stmfGuid *, char *);
static int persistDiskGuid(stmfGuid *, char *, boolean_t);
static int setDiskProp(luResourceImpl *, uint32_t, const char *);
static int getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen);
static int checkHexUpper(char *);
static int strToShift(const char *);
static int niceStrToNum(const char *, uint64_t *);
static void diskError(uint32_t, int *);
static int importDiskLu(char *fname, stmfGuid *);
static int modifyDiskLu(diskResource *, stmfGuid *, const char *);
static int modifyDiskLuProp(stmfGuid *, const char *, uint32_t, const char *);
static int validateModifyDiskProp(uint32_t);
static uint8_t iGetPersistMethod();
static int groupListIoctl(stmfGroupList **, int);
static int iLoadGroupFromPs(stmfGroupList **, int);
static int groupMemberListIoctl(stmfGroupName *, stmfGroupProperties **, int);
static int getProviderData(char *, nvlist_t **, int, uint64_t *);
static int setDiskStandby(stmfGuid *luGuid);
static int setDiskGlobalProp(uint32_t, const char *);
static int viewEntryCompare(const void *, const void *);
static void deleteNonActiveLus();
static int loadStmfProp(int fd);

static pthread_mutex_t persistenceTypeLock = PTHREAD_MUTEX_INITIALIZER;
static int iPersistType = 0;
/* when B_TRUE, no need to access SMF anymore. Just use iPersistType */
static boolean_t iLibSetPersist = B_FALSE;

/*
 * Open for stmf module
 *
 * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
 * fd - pointer to integer. On success, contains the stmf file descriptor
 */
static int
openStmf(int flag, int *fd)
{
        int ret = STMF_STATUS_ERROR;

        if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
                ret = STMF_STATUS_SUCCESS;
        } else {
                if (errno == EBUSY) {
                        ret = STMF_ERROR_BUSY;
                } else if (errno == EACCES) {
                        ret = STMF_ERROR_PERM;
                } else {
                        ret = STMF_STATUS_ERROR;
                }
                syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)",
                    STMF_PATH, errno);
        }

        return (ret);
}

/*
 * Open for sbd module
 *
 * flag - open flag (OPEN_SBD, OPEN_EXCL_SBD)
 * fd - pointer to integer. On success, contains the stmf file descriptor
 */
static int
openSbd(int flag, int *fd)
{
        int ret = STMF_STATUS_ERROR;

        if ((*fd = open(SBD_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
                ret = STMF_STATUS_SUCCESS;
        } else {
                if (errno == EBUSY) {
                        ret = STMF_ERROR_BUSY;
                } else if (errno == EACCES) {
                        ret = STMF_ERROR_PERM;
                } else {
                        ret = STMF_STATUS_ERROR;
                }
                syslog(LOG_DEBUG, "openSbd:open failure:%s:errno(%d)",
                    SBD_PATH, errno);
        }

        return (ret);
}

/*
 * Open for pppt module
 *
 * flag - open flag (OPEN_PPPT, OPEN_EXCL_PPPT)
 * fd - pointer to integer. On success, contains the stmf file descriptor
 */
static int
openPppt(int flag, int *fd)
{
        int ret = STMF_STATUS_ERROR;

        if ((*fd = open(PPPT_PATH, O_RDONLY | flag)) != -1) {
                ret = STMF_STATUS_SUCCESS;
        } else {
                if (errno == EBUSY) {
                        ret = STMF_ERROR_BUSY;
                } else if (errno == EACCES) {
                        ret = STMF_ERROR_PERM;
                } else {
                        ret = STMF_STATUS_ERROR;
                }
                syslog(LOG_DEBUG, "openPppt:open failure:%s:errno(%d)",
                    PPPT_PATH, errno);
        }

        return (ret);
}

/*
 * initializeConfig
 *
 * This routine should be called before any ioctl requiring initialization
 * which is basically everything except stmfGetState(), setStmfState() and
 * stmfLoadConfig().
 */
static int
initializeConfig()
{
        int ret;
        stmfState state;


        ret = stmfGetState(&state);
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /* if we've already initialized or in the process, return success */
        if (state.configState == STMF_CONFIG_STATE_INIT_DONE ||
            state.configState == STMF_CONFIG_STATE_INIT) {
                return (STMF_STATUS_SUCCESS);
        }

        ret = stmfLoadConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                syslog(LOG_DEBUG,
                    "initializeConfig:stmfLoadConfig:error(%d)", ret);
                return (ret);
        }

        ret = stmfGetState(&state);
        if (ret != STMF_STATUS_SUCCESS) {
                syslog(LOG_DEBUG,
                    "initializeConfig:stmfGetState:error(%d)", ret);
                return (ret);
        }

        if (state.configState != STMF_CONFIG_STATE_INIT_DONE) {
                syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)",
                    state.configState);
                ret = STMF_STATUS_ERROR;
        }

        return (ret);
}


/*
 * groupIoctl
 *
 * Purpose: issue ioctl for create/delete on group
 *
 * cmd - valid STMF ioctl group cmd
 * groupName - groupName to create or delete
 */
static int
groupIoctl(int fd, int cmd, stmfGroupName *groupName)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;
        stmf_group_name_t iGroupName;

        bzero(&iGroupName, sizeof (iGroupName));

        bcopy(groupName, &iGroupName.name, strlen((char *)groupName));

        iGroupName.name_size = strlen((char *)groupName);

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to create the host group
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (iGroupName);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_TG_EXISTS:
                                        case STMF_IOCERR_HG_EXISTS:
                                                ret = STMF_ERROR_EXISTS;
                                                break;
                                        case STMF_IOCERR_TG_IN_USE:
                                        case STMF_IOCERR_HG_IN_USE:
                                                ret = STMF_ERROR_GROUP_IN_USE;
                                                break;
                                        case STMF_IOCERR_INVALID_HG:
                                        case STMF_IOCERR_INVALID_TG:
                                                ret = STMF_ERROR_NOT_FOUND;
                                                break;
                                        default:
                                                syslog(LOG_DEBUG,
                                                    "groupIoctl:error(%d)",
                                                    stmfIoctl.stmf_error);
                                                ret = STMF_STATUS_ERROR;
                                                break;
                                }
                                break;
                }
        }
        return (ret);
}

/*
 * groupMemberIoctl
 *
 * Purpose: issue ioctl for add/remove member on group
 *
 * cmd - valid STMF ioctl group member cmd
 * groupName - groupName to add to or remove from
 * devid - group member to add or remove
 */
static int
groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;
        stmf_group_op_data_t stmfGroupData;

        bzero(&stmfGroupData, sizeof (stmfGroupData));

        bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName));

        stmfGroupData.group.name_size = strlen((char *)groupName);
        stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength;
        bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1],
            devid->identLength);

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to add to the host group
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_TG_NEED_TG_OFFLINE:
                                                ret = STMF_ERROR_TG_ONLINE;
                                                break;
                                        default:
                                                ret = STMF_ERROR_BUSY;
                                                break;
                                }
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_TG_ENTRY_EXISTS:
                                        case STMF_IOCERR_HG_ENTRY_EXISTS:
                                                ret = STMF_ERROR_EXISTS;
                                                break;
                                        case STMF_IOCERR_INVALID_TG_ENTRY:
                                        case STMF_IOCERR_INVALID_HG_ENTRY:
                                                ret =
                                                    STMF_ERROR_MEMBER_NOT_FOUND;
                                                break;
                                        case STMF_IOCERR_INVALID_TG:
                                        case STMF_IOCERR_INVALID_HG:
                                                ret =
                                                    STMF_ERROR_GROUP_NOT_FOUND;
                                                break;
                                        default:
                                                syslog(LOG_DEBUG,
                                                    "groupMemberIoctl:error"
                                                    "(%d)",
                                                    stmfIoctl.stmf_error);
                                                ret = STMF_STATUS_ERROR;
                                                break;
                                }
                                break;
                }
        }
        return (ret);
}

/*
 * qsort function
 * sort on veIndex
 */
static int
viewEntryCompare(const void *p1, const void *p2)
{

        stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
        if (v1->veIndex > v2->veIndex)
                return (1);
        if (v1->veIndex < v2->veIndex)
                return (-1);
        return (0);
}

/*
 * guidCompare
 *
 * qsort function
 * sort on guid
 */
static int
guidCompare(const void *p1, const void *p2)
{

        stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2;
        int i;

        for (i = 0; i < sizeof (stmfGuid); i++) {
                if (g1->guid[i] > g2->guid[i])
                        return (1);
                if (g1->guid[i] < g2->guid[i])
                        return (-1);
        }

        return (0);
}

/*
 * stmfAddToHostGroup
 *
 * Purpose: Adds an initiator to an existing host group
 *
 * hostGroupName - name of an existing host group
 * hostName - name of initiator to add
 */
int
stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
{
        int ret;
        int fd;

        if (hostGroupName == NULL ||
            (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
            == sizeof (stmfGroupName)) || hostName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName,
            hostName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psAddHostGroupMember((char *)hostGroupName,
            (char *)hostName->ident);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_EXISTS:
                        ret = STMF_ERROR_EXISTS;
                        break;
                case STMF_PS_ERROR_GROUP_NOT_FOUND:
                        ret = STMF_ERROR_GROUP_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfAddToHostGroup:psAddHostGroupMember:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfAddToTargetGroup
 *
 * Purpose: Adds a local port to an existing target group
 *
 * targetGroupName - name of an existing target group
 * targetName - name of target to add
 */
int
stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
{
        int ret;
        int fd;

        if (targetGroupName == NULL ||
            (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
            == sizeof (stmfGroupName)) || targetName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
            targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psAddTargetGroupMember((char *)targetGroupName,
            (char *)targetName->ident);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_EXISTS:
                        ret = STMF_ERROR_EXISTS;
                        break;
                case STMF_PS_ERROR_GROUP_NOT_FOUND:
                        ret = STMF_ERROR_GROUP_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfAddToTargetGroup:psAddTargetGroupMember:"
                            "error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * addViewEntryIoctl
 *
 * Purpose: Issues ioctl to add a view entry
 *
 * lu - Logical Unit identifier to which the view entry is added
 * viewEntry - view entry to add
 * init - When set to B_TRUE, we are in the init state, i.e. don't call open
 */
static int
addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;
        stmf_view_op_entry_t ioctlViewEntry;

        bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
        /*
         * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
         * false on input
         */
        ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
        ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
        ioctlViewEntry.ve_all_targets = viewEntry->allTargets;

        if (viewEntry->allHosts == B_FALSE) {
                bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
                    sizeof (stmfGroupName));
                ioctlViewEntry.ve_host_group.name_size =
                    strlen((char *)viewEntry->hostGroup);
        }
        if (viewEntry->allTargets == B_FALSE) {
                bcopy(viewEntry->targetGroup,
                    &ioctlViewEntry.ve_target_group.name,
                    sizeof (stmfGroupName));
                ioctlViewEntry.ve_target_group.name_size =
                    strlen((char *)viewEntry->targetGroup);
        }
        if (viewEntry->luNbrValid) {
                bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
                    sizeof (ioctlViewEntry.ve_lu_nbr));
        }
        bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to add to the view entry
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
        stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
        ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                                ret = STMF_ERROR_PERM;
                                break;
                        case EACCES:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
                                                ret = STMF_ERROR_CONFIG_NONE;
                                                break;
                                        default:
                                                ret = STMF_ERROR_PERM;
                                                break;
                                }
                                break;
                        default:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_LU_NUMBER_IN_USE:
                                                ret = STMF_ERROR_LUN_IN_USE;
                                                break;
                                        case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
                                                ret = STMF_ERROR_VE_CONFLICT;
                                                break;
                                        case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
                                                ret = STMF_ERROR_CONFIG_NONE;
                                                break;
                                        case STMF_IOCERR_INVALID_HG:
                                                ret = STMF_ERROR_INVALID_HG;
                                                break;
                                        case STMF_IOCERR_INVALID_TG:
                                                ret = STMF_ERROR_INVALID_TG;
                                                break;
                                        default:
                                                syslog(LOG_DEBUG,
                                                    "addViewEntryIoctl"
                                                    ":error(%d)",
                                                    stmfIoctl.stmf_error);
                                                ret = STMF_STATUS_ERROR;
                                                break;
                                }
                                break;
                }
                goto done;
        }

        /* copy lu nbr back to caller's view entry on success */
        viewEntry->veIndex = ioctlViewEntry.ve_ndx;
        if (ioctlViewEntry.ve_lu_number_valid) {
                bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
                    sizeof (ioctlViewEntry.ve_lu_nbr));
        }
        viewEntry->luNbrValid = B_TRUE;

done:
        return (ret);
}

/*
 * stmfAddViewEntry
 *
 * Purpose: Adds a view entry to a logical unit
 *
 * lu - guid of the logical unit to which the view entry is added
 * viewEntry - view entry structure to add
 */
int
stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
{
        int ret;
        int fd;
        stmfViewEntry iViewEntry;

        if (lu == NULL || viewEntry == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* initialize and set internal view entry */
        bzero(&iViewEntry, sizeof (iViewEntry));

        if (!viewEntry->allHosts) {
                bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
                    sizeof (iViewEntry.hostGroup));
        } else {
                iViewEntry.allHosts = B_TRUE;
        }

        if (!viewEntry->allTargets) {
                bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
                    sizeof (iViewEntry.targetGroup));
        } else {
                iViewEntry.allTargets = B_TRUE;
        }

        if (viewEntry->luNbrValid) {
                iViewEntry.luNbrValid = B_TRUE;
                bcopy(viewEntry->luNbr, iViewEntry.luNbr,
                    sizeof (iViewEntry.luNbr));
        }

        /*
         * set users return view entry index valid flag to false
         * in case of failure
         */
        viewEntry->veIndexValid = B_FALSE;

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * First add the view entry to the driver
         */
        ret = addViewEntryIoctl(fd, lu, &iViewEntry);
        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        /*
         * If the add to driver was successful, add it to the persistent
         * store.
         */
        ret = psAddViewEntry(lu, &iViewEntry);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfAddViewEntry:psAddViewEntry:error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);

        if (ret == STMF_STATUS_SUCCESS) {
                /* set caller's view entry on success */
                viewEntry->veIndexValid = iViewEntry.veIndexValid;
                viewEntry->veIndex = iViewEntry.veIndex;
                viewEntry->luNbrValid = B_TRUE;
                bcopy(iViewEntry.luNbr, viewEntry->luNbr,
                    sizeof (iViewEntry.luNbr));
        }
        return (ret);
}

/*
 * stmfClearProviderData
 *
 * Purpose: delete all provider data for specified provider
 *
 * providerName - name of provider for which data should be deleted
 */
int
stmfClearProviderData(char *providerName, int providerType)
{
        int ret;
        int fd;
        int ioctlRet;
        int savedErrno;
        stmf_iocdata_t stmfIoctl;
        stmf_ppioctl_data_t ppi;

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        if (providerName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (providerType != STMF_LU_PROVIDER_TYPE &&
            providerType != STMF_PORT_PROVIDER_TYPE) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        bzero(&ppi, sizeof (ppi));

        (void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name));

        switch (providerType) {
                case STMF_LU_PROVIDER_TYPE:
                        ppi.ppi_lu_provider = 1;
                        break;
                case STMF_PORT_PROVIDER_TYPE:
                        ppi.ppi_port_provider = 1;
                        break;
                default:
                        ret = STMF_ERROR_INVALID_ARG;
                        goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));

        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;

        ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfClearProviderData:ioctl error(%d)",
                                    ioctlRet);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                if (savedErrno != ENOENT) {
                        goto done;
                }
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psClearProviderData(providerName, providerType);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfClearProviderData:psClearProviderData"
                            ":error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfCreateHostGroup
 *
 * Purpose: Create a new initiator group
 *
 * hostGroupName - name of host group to create
 */
int
stmfCreateHostGroup(stmfGroupName *hostGroupName)
{
        int ret;
        int fd;

        if (hostGroupName == NULL ||
            (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
            == sizeof (stmfGroupName))) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
            hostGroupName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psCreateHostGroup((char *)hostGroupName);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_EXISTS:
                        ret = STMF_ERROR_EXISTS;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfCreateHostGroup:psCreateHostGroup:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfCreateLu
 *
 * Purpose: Create a logical unit
 *
 * hdl - handle to logical unit resource created via stmfCreateLuResource
 *
 * luGuid - If non-NULL, on success, contains the guid of the created logical
 *          unit
 */
int
stmfCreateLu(luResource hdl, stmfGuid *luGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        luResourceImpl *luPropsHdl = hdl;

        if (hdl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (luPropsHdl->type == STMF_DISK) {
                ret = createDiskLu((diskResource *)luPropsHdl->resource,
                    luGuid);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        return (ret);
}

/*
 * stmfCreateLuResource
 *
 * Purpose: Create resource handle for a logical unit
 *
 * dType - Type of logical unit resource to create
 *         Can be: STMF_DISK
 *
 * hdl - pointer to luResource
 */
int
stmfCreateLuResource(uint16_t dType, luResource *hdl)
{
        int ret = STMF_STATUS_SUCCESS;

        if (dType != STMF_DISK || hdl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        *hdl = calloc(1, sizeof (luResourceImpl));
        if (*hdl == NULL) {
                return (STMF_ERROR_NOMEM);
        }

        ret = createDiskResource((luResourceImpl *)*hdl);
        if (ret != STMF_STATUS_SUCCESS) {
                free(*hdl);
                return (ret);
        }

        return (STMF_STATUS_SUCCESS);
}

/*
 * Creates a disk logical unit
 *
 * disk - pointer to diskResource structure that represents the properties
 *        for the disk logical unit to be created.
 */
static int
createDiskLu(diskResource *disk, stmfGuid *createdGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        int dataFileNameLen = 0;
        int metaFileNameLen = 0;
        int serialNumLen = 0;
        int luAliasLen = 0;
        int luMgmtUrlLen = 0;
        int sluBufSize = 0;
        int bufOffset = 0;
        int fd = 0;
        int ioctlRet;
        int savedErrno;
        stmfGuid guid;
        stmf_iocdata_t sbdIoctl = {0};

        sbd_create_and_reg_lu_t *sbdLu = NULL;

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /* data file name must be specified */
        if (disk->luDataFileNameValid) {
                dataFileNameLen = strlen(disk->luDataFileName);
        } else {
                (void) close(fd);
                return (STMF_ERROR_MISSING_PROP_VAL);
        }

        sluBufSize += dataFileNameLen + 1;

        if (disk->luMetaFileNameValid) {
                metaFileNameLen = strlen(disk->luMetaFileName);
                sluBufSize += metaFileNameLen + 1;
        }

        serialNumLen = strlen(disk->serialNum);
        sluBufSize += serialNumLen;

        if (disk->luAliasValid) {
                luAliasLen = strlen(disk->luAlias);
                sluBufSize += luAliasLen + 1;
        }

        if (disk->luMgmtUrlValid) {
                luMgmtUrlLen = strlen(disk->luMgmtUrl);
                sluBufSize += luMgmtUrlLen + 1;
        }

        /*
         * 8 is the size of the buffer set aside for
         * concatenation of variable length fields
         */
        sbdLu = (sbd_create_and_reg_lu_t *)calloc(1,
            sizeof (sbd_create_and_reg_lu_t) + sluBufSize - 8);
        if (sbdLu == NULL) {
                return (STMF_ERROR_NOMEM);
        }

        sbdLu->slu_struct_size = sizeof (sbd_create_and_reg_lu_t) +
            sluBufSize - 8;

        if (metaFileNameLen) {
                sbdLu->slu_meta_fname_valid = 1;
                sbdLu->slu_meta_fname_off = bufOffset;
                bcopy(disk->luMetaFileName, &(sbdLu->slu_buf[bufOffset]),
                    metaFileNameLen + 1);
                bufOffset += metaFileNameLen + 1;
        }

        bcopy(disk->luDataFileName, &(sbdLu->slu_buf[bufOffset]),
            dataFileNameLen + 1);
        sbdLu->slu_data_fname_off = bufOffset;
        bufOffset += dataFileNameLen + 1;

        /* currently, serial # is not passed null terminated to the driver */
        if (disk->serialNumValid) {
                sbdLu->slu_serial_valid = 1;
                sbdLu->slu_serial_off = bufOffset;
                sbdLu->slu_serial_size = serialNumLen;
                bcopy(disk->serialNum, &(sbdLu->slu_buf[bufOffset]),
                    serialNumLen);
                bufOffset += serialNumLen;
        }

        if (disk->luAliasValid) {
                sbdLu->slu_alias_valid = 1;
                sbdLu->slu_alias_off = bufOffset;
                bcopy(disk->luAlias, &(sbdLu->slu_buf[bufOffset]),
                    luAliasLen + 1);
                bufOffset += luAliasLen + 1;
        }

        if (disk->luMgmtUrlValid) {
                sbdLu->slu_mgmt_url_valid = 1;
                sbdLu->slu_mgmt_url_off = bufOffset;
                bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]),
                    luMgmtUrlLen + 1);
                bufOffset += luMgmtUrlLen + 1;
        }

        if (disk->luSizeValid) {
                sbdLu->slu_lu_size_valid = 1;
                sbdLu->slu_lu_size = disk->luSize;
        }

        if (disk->luGuidValid) {
                sbdLu->slu_guid_valid = 1;
                bcopy(disk->luGuid, sbdLu->slu_guid, sizeof (disk->luGuid));
        }

        if (disk->vidValid) {
                sbdLu->slu_vid_valid = 1;
                bcopy(disk->vid, sbdLu->slu_vid, sizeof (disk->vid));
        }

        if (disk->pidValid) {
                sbdLu->slu_pid_valid = 1;
                bcopy(disk->pid, sbdLu->slu_pid, sizeof (disk->pid));
        }

        if (disk->revValid) {
                sbdLu->slu_rev_valid = 1;
                bcopy(disk->rev, sbdLu->slu_rev, sizeof (disk->rev));
        }

        if (disk->companyIdValid) {
                sbdLu->slu_company_id_valid = 1;
                sbdLu->slu_company_id = disk->companyId;
        }

        if (disk->hostIdValid) {
                sbdLu->slu_host_id_valid = 1;
                sbdLu->slu_host_id = disk->hostId;
        }

        if (disk->blkSizeValid) {
                sbdLu->slu_blksize_valid = 1;
                sbdLu->slu_blksize = disk->blkSize;
        }

        if (disk->writeProtectEnableValid) {
                if (disk->writeProtectEnable) {
                        sbdLu->slu_write_protected = 1;
                }
        }

        if (disk->writebackCacheDisableValid) {
                sbdLu->slu_writeback_cache_disable_valid = 1;
                if (disk->writebackCacheDisable) {
                        sbdLu->slu_writeback_cache_disable = 1;
                }
        }

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sbdLu->slu_struct_size;
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
        sbdIoctl.stmf_obuf_size = sbdLu->slu_struct_size;
        sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;

        ioctlRet = ioctl(fd, SBD_IOCTL_CREATE_AND_REGISTER_LU, &sbdIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                diskError(sbdIoctl.stmf_error, &ret);
                                if (ret == STMF_STATUS_ERROR) {
                                        syslog(LOG_DEBUG,
                                        "createDiskLu:ioctl "
                                        "error(%d) (%d) (%d)", ioctlRet,
                                            sbdIoctl.stmf_error, savedErrno);
                                }
                                break;
                }
        }

        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        /*
         * on success, copy the resulting guid into the caller's guid if not
         * NULL
         */
        if (createdGuid) {
                bcopy(sbdLu->slu_guid, createdGuid->guid,
                    sizeof (sbdLu->slu_guid));
        }

        bcopy(sbdLu->slu_guid, guid.guid, sizeof (sbdLu->slu_guid));
        if (disk->luMetaFileNameValid) {
                ret = addGuidToDiskStore(&guid, disk->luMetaFileName);
        } else {
                ret = addGuidToDiskStore(&guid, disk->luDataFileName);
        }
done:
        free(sbdLu);
        (void) close(fd);
        return (ret);
}


/*
 * stmfImportLu
 *
 * Purpose: Import a previously created logical unit
 *
 * dType - Type of logical unit
 *         Can be: STMF_DISK
 *
 * luGuid - If non-NULL, on success, contains the guid of the imported logical
 *          unit
 *
 * fname - A file name where the metadata resides
 *
 */
int
stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid)
{
        int ret = STMF_STATUS_SUCCESS;

        if (dType == STMF_DISK) {
                ret = importDiskLu(fname, luGuid);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        return (ret);
}

/*
 * importDiskLu
 *
 * filename - filename to import
 * createdGuid - if not NULL, on success contains the imported guid
 *
 */
static int
importDiskLu(char *fname, stmfGuid *createdGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd = 0;
        int ioctlRet;
        int savedErrno;
        int metaFileNameLen;
        stmfGuid iGuid;
        int iluBufSize = 0;
        sbd_import_lu_t *sbdLu = NULL;
        stmf_iocdata_t sbdIoctl = {0};

        if (fname == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        metaFileNameLen = strlen(fname);
        iluBufSize += metaFileNameLen + 1;

        /*
         * 8 is the size of the buffer set aside for
         * concatenation of variable length fields
         */
        sbdLu = (sbd_import_lu_t *)calloc(1,
            sizeof (sbd_import_lu_t) + iluBufSize - 8);
        if (sbdLu == NULL) {
                (void) close(fd);
                return (STMF_ERROR_NOMEM);
        }

        /*
         * Accept either a data file or meta data file.
         * sbd will do the right thing here either way.
         * i.e. if it's a data file, it assumes that the
         * meta data is shared with the data.
         */
        (void) strncpy(sbdLu->ilu_meta_fname, fname, metaFileNameLen);

        sbdLu->ilu_struct_size = sizeof (sbd_import_lu_t) + iluBufSize - 8;

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sbdLu->ilu_struct_size;
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
        sbdIoctl.stmf_obuf_size = sbdLu->ilu_struct_size;
        sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;

        ioctlRet = ioctl(fd, SBD_IOCTL_IMPORT_LU, &sbdIoctl);
        if (ioctlRet != 0) {

                if (createdGuid && sbdIoctl.stmf_error ==
                    SBD_RET_FILE_ALREADY_REGISTERED) {
                        bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
                            sizeof (sbdLu->ilu_ret_guid));
                }

                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                diskError(sbdIoctl.stmf_error, &ret);
                                if (ret == STMF_STATUS_ERROR) {
                                        syslog(LOG_DEBUG,
                                        "importDiskLu:ioctl "
                                        "error(%d) (%d) (%d)", ioctlRet,
                                            sbdIoctl.stmf_error, savedErrno);
                                }
                                break;
                }
        }


        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        /*
         * on success, copy the resulting guid into the caller's guid if not
         * NULL and add it to the persistent store for sbd
         */
        if (createdGuid) {
                bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
                    sizeof (sbdLu->ilu_ret_guid));
                ret = addGuidToDiskStore(createdGuid, fname);
        } else {
                bcopy(sbdLu->ilu_ret_guid, iGuid.guid,
                    sizeof (sbdLu->ilu_ret_guid));
                ret = addGuidToDiskStore(&iGuid, fname);
        }
done:
        free(sbdLu);
        (void) close(fd);
        return (ret);
}

/*
 * diskError
 *
 * Purpose: Translate sbd driver error
 */
static void
diskError(uint32_t stmfError, int *ret)
{
        switch (stmfError) {
                case SBD_RET_META_CREATION_FAILED:
                case SBD_RET_ZFS_META_CREATE_FAILED:
                        *ret = STMF_ERROR_META_CREATION;
                        break;
                case SBD_RET_INVALID_BLKSIZE:
                        *ret = STMF_ERROR_INVALID_BLKSIZE;
                        break;
                case SBD_RET_FILE_ALREADY_REGISTERED:
                        *ret = STMF_ERROR_FILE_IN_USE;
                        break;
                case SBD_RET_GUID_ALREADY_REGISTERED:
                        *ret = STMF_ERROR_GUID_IN_USE;
                        break;
                case SBD_RET_META_PATH_NOT_ABSOLUTE:
                case SBD_RET_META_FILE_LOOKUP_FAILED:
                case SBD_RET_META_FILE_OPEN_FAILED:
                case SBD_RET_META_FILE_GETATTR_FAILED:
                case SBD_RET_NO_META:
                        *ret = STMF_ERROR_META_FILE_NAME;
                        break;
                case SBD_RET_DATA_PATH_NOT_ABSOLUTE:
                case SBD_RET_DATA_FILE_LOOKUP_FAILED:
                case SBD_RET_DATA_FILE_OPEN_FAILED:
                case SBD_RET_DATA_FILE_GETATTR_FAILED:
                        *ret = STMF_ERROR_DATA_FILE_NAME;
                        break;
                case SBD_RET_FILE_SIZE_ERROR:
                        *ret = STMF_ERROR_FILE_SIZE_INVALID;
                        break;
                case SBD_RET_SIZE_OUT_OF_RANGE:
                        *ret = STMF_ERROR_SIZE_OUT_OF_RANGE;
                        break;
                case SBD_RET_LU_BUSY:
                        *ret = STMF_ERROR_LU_BUSY;
                        break;
                case SBD_RET_WRITE_CACHE_SET_FAILED:
                        *ret = STMF_ERROR_WRITE_CACHE_SET;
                        break;
                case SBD_RET_ACCESS_STATE_FAILED:
                        *ret = STMF_ERROR_ACCESS_STATE_SET;
                        break;
                default:
                        *ret = STMF_STATUS_ERROR;
                        break;
        }
}

/*
 * Creates a logical unit resource of type STMF_DISK.
 *
 * No defaults should be set here as all defaults are derived from the
 * driver's default settings.
 */
static int
createDiskResource(luResourceImpl *hdl)
{
        hdl->type = STMF_DISK;

        hdl->resource = calloc(1, sizeof (diskResource));
        if (hdl->resource == NULL) {
                return (STMF_ERROR_NOMEM);
        }

        return (STMF_STATUS_SUCCESS);
}

/*
 * stmfDeleteLu
 *
 * Purpose: Delete a logical unit
 *
 * hdl - handle to logical unit resource created via stmfCreateLuResource
 *
 * luGuid - If non-NULL, on success, contains the guid of the created logical
 *          unit
 */
int
stmfDeleteLu(stmfGuid *luGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        stmfLogicalUnitProperties luProps;

        if (luGuid == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check logical unit provider name to call correct dtype function */
        if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
            != STMF_STATUS_SUCCESS) {
                return (ret);
        } else {
                if (strcmp(luProps.providerName, "sbd") == 0) {
                        ret = deleteDiskLu(luGuid);
                } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
                        return (STMF_ERROR_NOT_FOUND);
                } else {
                        return (STMF_ERROR_INVALID_ARG);
                }
        }

        return (ret);
}

static int
deleteDiskLu(stmfGuid *luGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        int savedErrno;
        int ioctlRet;
        sbd_delete_lu_t deleteLu = {0};

        stmf_iocdata_t sbdIoctl = {0};

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        ret = removeGuidFromDiskStore(luGuid);
        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        bcopy(luGuid, deleteLu.dlu_guid, sizeof (deleteLu.dlu_guid));
        deleteLu.dlu_by_guid = 1;

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sizeof (deleteLu);
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&deleteLu;
        ioctlRet = ioctl(fd, SBD_IOCTL_DELETE_LU, &sbdIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case ENOENT:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "deleteDiskLu:ioctl error(%d) (%d) (%d)",
                                    ioctlRet, sbdIoctl.stmf_error, savedErrno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfLuStandby
 *
 * Purpose: Sets access state to standby
 *
 * luGuid - guid of registered logical unit
 *
 */
int
stmfLuStandby(stmfGuid *luGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        stmfLogicalUnitProperties luProps;

        if (luGuid == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check logical unit provider name to call correct dtype function */
        if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
            != STMF_STATUS_SUCCESS) {
                return (ret);
        } else {
                if (strcmp(luProps.providerName, "sbd") == 0) {
                        ret = setDiskStandby(luGuid);
                } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
                        return (STMF_ERROR_NOT_FOUND);
                } else {
                        return (STMF_ERROR_INVALID_ARG);
                }
        }

        return (ret);
}

static int
setDiskStandby(stmfGuid *luGuid)
{
        int ret = STMF_STATUS_SUCCESS;
        stmf_iocdata_t sbdIoctl = {0};
        sbd_set_lu_standby_t sbdLu = {0};
        int ioctlRet;
        int savedErrno;
        int fd = 0;

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        bcopy(luGuid, &sbdLu.stlu_guid, sizeof (stmfGuid));

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sizeof (sbd_set_lu_standby_t);
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&sbdLu;

        ioctlRet = ioctl(fd, SBD_IOCTL_SET_LU_STANDBY, &sbdIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                diskError(sbdIoctl.stmf_error, &ret);
                                if (ret == STMF_STATUS_ERROR) {
                                        syslog(LOG_DEBUG,
                                        "setDiskStandby:ioctl "
                                        "error(%d) (%d) (%d)", ioctlRet,
                                            sbdIoctl.stmf_error, savedErrno);
                                }
                                break;
                }
        }
        (void) close(fd);
        return (ret);
}

/*
 * stmfModifyLu
 *
 * Purpose: Modify properties of a logical unit
 *
 * luGuid - guid of registered logical unit
 * prop - property to modify
 * propVal - property value to set
 *
 */
int
stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        stmfLogicalUnitProperties luProps;

        if (luGuid == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check logical unit provider name to call correct dtype function */
        if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
            != STMF_STATUS_SUCCESS) {
                return (ret);
        } else {
                if (strcmp(luProps.providerName, "sbd") == 0) {
                        ret = modifyDiskLuProp(luGuid, NULL, prop, propVal);
                } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
                        return (STMF_ERROR_NOT_FOUND);
                } else {
                        return (STMF_ERROR_INVALID_ARG);
                }
        }

        return (ret);
}

/*
 * stmfModifyLuByFname
 *
 * Purpose: Modify a device by filename. Device does not need to be registered.
 *
 * dType - type of device to modify
 *         STMF_DISK
 *
 * fname - filename or meta filename
 * prop - valid property identifier
 * propVal - property value
 *
 */
int
stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
    const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        if (fname == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (dType == STMF_DISK) {
                ret = modifyDiskLuProp(NULL, fname, prop, propVal);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        return (ret);
}

static int
modifyDiskLuProp(stmfGuid *luGuid, const char *fname, uint32_t prop,
    const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        luResource hdl = NULL;
        luResourceImpl *luPropsHdl;

        ret = stmfCreateLuResource(STMF_DISK, &hdl);
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }
        ret = validateModifyDiskProp(prop);
        if (ret != STMF_STATUS_SUCCESS) {
                (void) stmfFreeLuResource(hdl);
                return (STMF_ERROR_INVALID_PROP);
        }
        ret = stmfSetLuProp(hdl, prop, propVal);
        if (ret != STMF_STATUS_SUCCESS) {
                (void) stmfFreeLuResource(hdl);
                return (ret);
        }
        luPropsHdl = hdl;
        ret = modifyDiskLu((diskResource *)luPropsHdl->resource, luGuid, fname);
        (void) stmfFreeLuResource(hdl);
        return (ret);
}

static int
validateModifyDiskProp(uint32_t prop)
{
        switch (prop) {
                case STMF_LU_PROP_ALIAS:
                case STMF_LU_PROP_SIZE:
                case STMF_LU_PROP_MGMT_URL:
                case STMF_LU_PROP_WRITE_PROTECT:
                case STMF_LU_PROP_WRITE_CACHE_DISABLE:
                        return (STMF_STATUS_SUCCESS);
                default:
                        return (STMF_STATUS_ERROR);
        }
}

static int
modifyDiskLu(diskResource *disk, stmfGuid *luGuid, const char *fname)
{
        int ret = STMF_STATUS_SUCCESS;
        int luAliasLen = 0;
        int luMgmtUrlLen = 0;
        int mluBufSize = 0;
        int bufOffset = 0;
        int fd = 0;
        int ioctlRet;
        int savedErrno;
        int fnameSize = 0;
        stmf_iocdata_t sbdIoctl = {0};

        sbd_modify_lu_t *sbdLu = NULL;

        if (luGuid == NULL && fname == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (fname) {
                fnameSize = strlen(fname) + 1;
                mluBufSize += fnameSize;
        }

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        if (disk->luAliasValid) {
                luAliasLen = strlen(disk->luAlias);
                mluBufSize += luAliasLen + 1;
        }

        if (disk->luMgmtUrlValid) {
                luMgmtUrlLen = strlen(disk->luMgmtUrl);
                mluBufSize += luMgmtUrlLen + 1;
        }

        /*
         * 8 is the size of the buffer set aside for
         * concatenation of variable length fields
         */
        sbdLu = (sbd_modify_lu_t *)calloc(1,
            sizeof (sbd_modify_lu_t) + mluBufSize - 8 + fnameSize);
        if (sbdLu == NULL) {
                (void) close(fd);
                return (STMF_ERROR_NOMEM);
        }

        sbdLu->mlu_struct_size = sizeof (sbd_modify_lu_t) +
            mluBufSize - 8 + fnameSize;

        if (disk->luAliasValid) {
                sbdLu->mlu_alias_valid = 1;
                sbdLu->mlu_alias_off = bufOffset;
                bcopy(disk->luAlias, &(sbdLu->mlu_buf[bufOffset]),
                    luAliasLen + 1);
                bufOffset += luAliasLen + 1;
        }

        if (disk->luMgmtUrlValid) {
                sbdLu->mlu_mgmt_url_valid = 1;
                sbdLu->mlu_mgmt_url_off = bufOffset;
                bcopy(disk->luMgmtUrl, &(sbdLu->mlu_buf[bufOffset]),
                    luMgmtUrlLen + 1);
                bufOffset += luMgmtUrlLen + 1;
        }

        if (disk->luSizeValid) {
                sbdLu->mlu_lu_size_valid = 1;
                sbdLu->mlu_lu_size = disk->luSize;
        }

        if (disk->writeProtectEnableValid) {
                sbdLu->mlu_write_protected_valid = 1;
                if (disk->writeProtectEnable) {
                        sbdLu->mlu_write_protected = 1;
                }
        }

        if (disk->writebackCacheDisableValid) {
                sbdLu->mlu_writeback_cache_disable_valid = 1;
                if (disk->writebackCacheDisable) {
                        sbdLu->mlu_writeback_cache_disable = 1;
                }
        }

        if (luGuid) {
                bcopy(luGuid, sbdLu->mlu_input_guid, sizeof (stmfGuid));
                sbdLu->mlu_by_guid = 1;
        } else {
                sbdLu->mlu_fname_off = bufOffset;
                bcopy(fname, &(sbdLu->mlu_buf[bufOffset]), fnameSize + 1);
                sbdLu->mlu_by_fname = 1;
        }

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sbdLu->mlu_struct_size;
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;

        ioctlRet = ioctl(fd, SBD_IOCTL_MODIFY_LU, &sbdIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                diskError(sbdIoctl.stmf_error, &ret);
                                if (ret == STMF_STATUS_ERROR) {
                                        syslog(LOG_DEBUG,
                                        "modifyDiskLu:ioctl "
                                        "error(%d) (%d) (%d)", ioctlRet,
                                            sbdIoctl.stmf_error, savedErrno);
                                }
                                break;
                }
        }

        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

done:
        free(sbdLu);
        (void) close(fd);
        return (ret);
}

/*
 * removeGuidFromDiskStore
 *
 * Purpose: delete a logical unit from the sbd provider data
 */
static int
removeGuidFromDiskStore(stmfGuid *guid)
{
        return (persistDiskGuid(guid, NULL, B_FALSE));
}


/*
 * addGuidToDiskStore
 *
 * Purpose: add a logical unit to the sbd provider data
 */
static int
addGuidToDiskStore(stmfGuid *guid, char *filename)
{
        return (persistDiskGuid(guid, filename, B_TRUE));
}


/*
 * persistDiskGuid
 *
 * Purpose: Persist or unpersist a guid for the sbd provider data
 *
 */
static int
persistDiskGuid(stmfGuid *guid, char *filename, boolean_t persist)
{
        char        guidAsciiBuf[LU_ASCII_GUID_SIZE + 1] = {0};
        nvlist_t    *nvl = NULL;

        uint64_t    setToken;
        boolean_t   retryGetProviderData = B_FALSE;
        boolean_t   newData = B_FALSE;
        int         ret = STMF_STATUS_SUCCESS;
        int         retryCnt = 0;
        int         stmfRet;

        /* if we're persisting a guid, there must be a filename */
        if (persist && !filename) {
                return (1);
        }

        /* guid is stored in lowercase ascii hex */
        (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
            "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
            "%02x%02x%02x%02x%02x%02x",
            guid->guid[0], guid->guid[1], guid->guid[2], guid->guid[3],
            guid->guid[4], guid->guid[5], guid->guid[6], guid->guid[7],
            guid->guid[8], guid->guid[9], guid->guid[10], guid->guid[11],
            guid->guid[12], guid->guid[13], guid->guid[14], guid->guid[15]);


        do {
                retryGetProviderData = B_FALSE;
                stmfRet = stmfGetProviderDataProt("sbd", &nvl,
                    STMF_LU_PROVIDER_TYPE, &setToken);
                if (stmfRet != STMF_STATUS_SUCCESS) {
                        if (persist && stmfRet == STMF_ERROR_NOT_FOUND) {
                                ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
                                if (ret != 0) {
                                        syslog(LOG_DEBUG,
                                            "unpersistGuid:nvlist_alloc(%d)",
                                            ret);
                                        ret = STMF_STATUS_ERROR;
                                        goto done;
                                }
                                newData = B_TRUE;
                        } else {
                                /*
                                 * if we're persisting the data, it's
                                 * an error. Otherwise, just return
                                 */
                                if (persist) {
                                        ret = stmfRet;
                                }
                                goto done;
                        }
                }
                if (persist) {
                        ret = nvlist_add_string(nvl, guidAsciiBuf, filename);
                } else {
                        ret = nvlist_remove(nvl, guidAsciiBuf,
                            DATA_TYPE_STRING);
                        if (ret == ENOENT) {
                                ret = 0;
                        }
                }
                if (ret == 0) {
                        if (newData) {
                                stmfRet = stmfSetProviderDataProt("sbd", nvl,
                                    STMF_LU_PROVIDER_TYPE, NULL);
                        } else {
                                stmfRet = stmfSetProviderDataProt("sbd", nvl,
                                    STMF_LU_PROVIDER_TYPE, &setToken);
                        }
                        if (stmfRet != STMF_STATUS_SUCCESS) {
                                if (stmfRet == STMF_ERROR_BUSY) {
                                        /* get/set failed, try again */
                                        retryGetProviderData = B_TRUE;
                                        if (retryCnt++ > MAX_PROVIDER_RETRY) {
                                                ret = stmfRet;
                                                break;
                                        }
                                        continue;
                                } else if (stmfRet ==
                                    STMF_ERROR_PROV_DATA_STALE) {
                                        /* update failed, try again */
                                        nvlist_free(nvl);
                                        nvl = NULL;
                                        retryGetProviderData = B_TRUE;
                                        if (retryCnt++ > MAX_PROVIDER_RETRY) {
                                                ret = stmfRet;
                                                break;
                                        }
                                        continue;
                                } else {
                                        syslog(LOG_DEBUG,
                                            "unpersistGuid:error(%x)", stmfRet);
                                        ret = stmfRet;
                                }
                                break;
                        }
                } else {
                        syslog(LOG_DEBUG,
                            "unpersistGuid:error nvlist_add/remove(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                }
        } while (retryGetProviderData);

done:
        nvlist_free(nvl);
        return (ret);
}


/*
 * stmfGetLuProp
 *
 * Purpose: Get current value for a resource property
 *
 * hdl - luResource from a previous call to stmfCreateLuResource
 *
 * resourceProp - a valid resource property type
 *
 * propVal - void pointer to a pointer of the value to be retrieved
 */
int
stmfGetLuProp(luResource hdl, uint32_t prop, char *propVal, size_t *propLen)
{
        int ret = STMF_STATUS_SUCCESS;
        luResourceImpl *luPropsHdl = hdl;
        if (hdl == NULL || propLen == NULL || propVal == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (luPropsHdl->type == STMF_DISK) {
                ret = getDiskProp(luPropsHdl, prop, propVal, propLen);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        return (ret);
}

/*
 * stmfGetLuResource
 *
 * Purpose: Get a logical unit resource handle for a given logical unit.
 *
 * hdl - pointer to luResource
 */
int
stmfGetLuResource(stmfGuid *luGuid, luResource *hdl)
{
        int ret = STMF_STATUS_SUCCESS;
        stmfLogicalUnitProperties luProps;

        if (hdl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check logical unit provider name to call correct dtype function */
        if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
            != STMF_STATUS_SUCCESS) {
                return (ret);
        } else {
                if (strcmp(luProps.providerName, "sbd") == 0) {
                        ret = getDiskAllProps(luGuid, hdl);
                } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
                        return (STMF_ERROR_NOT_FOUND);
                } else {
                        return (STMF_ERROR_INVALID_ARG);
                }
        }

        return (ret);
}

/*
 * getDiskAllProps
 *
 * Purpose: load all disk properties from sbd driver
 *
 * luGuid - guid of disk device for which properties are to be retrieved
 * hdl - allocated luResource into which properties are to be copied
 *
 */
static int
getDiskAllProps(stmfGuid *luGuid, luResource *hdl)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        sbd_lu_props_t *sbdProps;
        int ioctlRet;
        int savedErrno;
        int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
        stmf_iocdata_t sbdIoctl = {0};

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);


        *hdl = calloc(1, sizeof (luResourceImpl));
        if (*hdl == NULL) {
                (void) close(fd);
                return (STMF_ERROR_NOMEM);
        }

        sbdProps = calloc(1, sbdPropsSize);
        if (sbdProps == NULL) {
                free(*hdl);
                (void) close(fd);
                return (STMF_ERROR_NOMEM);
        }

        ret = createDiskResource((luResourceImpl *)*hdl);
        if (ret != STMF_STATUS_SUCCESS) {
                free(*hdl);
                free(sbdProps);
                (void) close(fd);
                return (ret);
        }

        sbdProps->slp_input_guid = 1;
        bcopy(luGuid, sbdProps->slp_guid, sizeof (sbdProps->slp_guid));

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sbdPropsSize;
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdProps;
        sbdIoctl.stmf_obuf_size = sbdPropsSize;
        sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
        ioctlRet = ioctl(fd, SBD_IOCTL_GET_LU_PROPS, &sbdIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case ENOENT:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "getDiskAllProps:ioctl error(%d) (%d) (%d)",
                                    ioctlRet, sbdIoctl.stmf_error, savedErrno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }

        if (ret == STMF_STATUS_SUCCESS) {
                ret = loadDiskPropsFromDriver((luResourceImpl *)*hdl, sbdProps);
        }

        free(sbdProps);
        (void) close(fd);
        return (ret);
}

/*
 * loadDiskPropsFromDriver
 *
 * Purpose: Retrieve all disk type properties from sbd driver
 *
 * hdl - Allocated luResourceImpl
 * sbdProps - sbd_lu_props_t structure returned from sbd driver
 *
 */
static int
loadDiskPropsFromDriver(luResourceImpl *hdl, sbd_lu_props_t *sbdProps)
{
        int ret = STMF_STATUS_SUCCESS;
        diskResource *diskLu = hdl->resource;
        /* copy guid */
        diskLu->luGuidValid = B_TRUE;
        bcopy(sbdProps->slp_guid, diskLu->luGuid, sizeof (sbdProps->slp_guid));

        if (sbdProps->slp_separate_meta && sbdProps->slp_meta_fname_valid) {
                diskLu->luMetaFileNameValid = B_TRUE;
                if (strlcpy(diskLu->luMetaFileName,
                    (char *)&(sbdProps->slp_buf[sbdProps->slp_meta_fname_off]),
                    sizeof (diskLu->luMetaFileName)) >=
                    sizeof (diskLu->luMetaFileName)) {
                        return (STMF_STATUS_ERROR);
                }
        }

        if (sbdProps->slp_data_fname_valid) {
                diskLu->luDataFileNameValid = B_TRUE;
                if (strlcpy(diskLu->luDataFileName,
                    (char *)&(sbdProps->slp_buf[sbdProps->slp_data_fname_off]),
                    sizeof (diskLu->luDataFileName)) >=
                    sizeof (diskLu->luDataFileName)) {
                        return (STMF_STATUS_ERROR);
                }
        }

        if (sbdProps->slp_serial_valid) {
                diskLu->serialNumValid = B_TRUE;
                bcopy(&(sbdProps->slp_buf[sbdProps->slp_serial_off]),
                    diskLu->serialNum, sbdProps->slp_serial_size);
        }

        if (sbdProps->slp_mgmt_url_valid) {
                diskLu->luMgmtUrlValid = B_TRUE;
                if (strlcpy(diskLu->luMgmtUrl,
                    (char *)&(sbdProps->slp_buf[sbdProps->slp_mgmt_url_off]),
                    sizeof (diskLu->luMgmtUrl)) >=
                    sizeof (diskLu->luMgmtUrl)) {
                        return (STMF_STATUS_ERROR);
                }
        }

        if (sbdProps->slp_alias_valid) {
                diskLu->luAliasValid = B_TRUE;
                if (strlcpy(diskLu->luAlias,
                    (char *)&(sbdProps->slp_buf[sbdProps->slp_alias_off]),
                    sizeof (diskLu->luAlias)) >=
                    sizeof (diskLu->luAlias)) {
                        return (STMF_STATUS_ERROR);
                }
        } else { /* set alias to data filename if not set */
                if (sbdProps->slp_data_fname_valid) {
                        diskLu->luAliasValid = B_TRUE;
                        if (strlcpy(diskLu->luAlias,
                            (char *)&(sbdProps->slp_buf[
                            sbdProps->slp_data_fname_off]),
                            sizeof (diskLu->luAlias)) >=
                            sizeof (diskLu->luAlias)) {
                                return (STMF_STATUS_ERROR);
                        }
                }
        }

        diskLu->vidValid = B_TRUE;
        bcopy(sbdProps->slp_vid, diskLu->vid, sizeof (diskLu->vid));

        diskLu->pidValid = B_TRUE;
        bcopy(sbdProps->slp_pid, diskLu->pid, sizeof (diskLu->pid));

        diskLu->revValid = B_TRUE;
        bcopy(sbdProps->slp_rev, diskLu->rev, sizeof (diskLu->rev));

        diskLu->writeProtectEnableValid = B_TRUE;
        if (sbdProps->slp_write_protected) {
                diskLu->writeProtectEnable = B_TRUE;
        }

        diskLu->writebackCacheDisableValid = B_TRUE;
        if (sbdProps->slp_writeback_cache_disable_cur) {
                diskLu->writebackCacheDisable = B_TRUE;
        }

        diskLu->blkSizeValid = B_TRUE;
        diskLu->blkSize = sbdProps->slp_blksize;

        diskLu->luSizeValid = B_TRUE;
        diskLu->luSize = sbdProps->slp_lu_size;

        diskLu->accessState = sbdProps->slp_access_state;

        return (ret);
}

/*
 * stmfGetGlobalLuProp
 *
 * Purpose: get a global property for a device type
 *
 */
int
stmfGetGlobalLuProp(uint16_t dType, uint32_t prop, char *propVal,
    size_t *propLen)
{
        int ret = STMF_STATUS_SUCCESS;
        if (dType != STMF_DISK || propVal == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = getDiskGlobalProp(prop, propVal, propLen);

        return (ret);
}

/*
 * getDiskGlobalProp
 *
 * Purpose: get global property from sbd driver
 *
 */
static int
getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        sbd_global_props_t *sbdProps;
        void *sbd_realloc;
        int retryCnt = 0;
        boolean_t retry;
        int ioctlRet;
        int savedErrno;
        int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
        stmf_iocdata_t sbdIoctl = {0};
        size_t reqLen;

        switch (prop) {
                case STMF_LU_PROP_MGMT_URL:
                        break;
                default:
                        return (STMF_ERROR_INVALID_PROP);
        }

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        sbdProps = calloc(1, sbdPropsSize);
        if (sbdProps == NULL) {
                (void) close(fd);
                return (STMF_ERROR_NOMEM);
        }

        do {
                retry = B_FALSE;
                sbdIoctl.stmf_version = STMF_VERSION_1;
                sbdIoctl.stmf_obuf_size = sbdPropsSize;
                sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
                ioctlRet = ioctl(fd, SBD_IOCTL_GET_GLOBAL_LU, &sbdIoctl);
                if (ioctlRet != 0) {
                        savedErrno = errno;
                        switch (savedErrno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                case ENOMEM:
                                        if (sbdIoctl.stmf_error ==
                                            SBD_RET_INSUFFICIENT_BUF_SPACE &&
                                            retryCnt++ < 3) {
                                                sbdPropsSize =
                                                    sizeof (*sbdProps) +
                                                    sbdProps->
                                                    mlu_buf_size_needed;

                                                sbd_realloc = sbdProps;
                                                sbdProps = realloc(sbdProps,
                                                    sbdPropsSize);
                                                if (sbdProps == NULL) {
                                                        free(sbd_realloc);
                                                        ret = STMF_ERROR_NOMEM;
                                                        break;
                                                }
                                                retry = B_TRUE;
                                        } else {
                                                ret = STMF_ERROR_NOMEM;
                                        }
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "getDiskGlobalProp:ioctl error(%d)"
                                            "(%d)(%d)", ioctlRet,
                                            sbdIoctl.stmf_error, savedErrno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }

                }
        } while (retry);

        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        switch (prop) {
                case STMF_LU_PROP_MGMT_URL:
                        if (sbdProps->mlu_mgmt_url_valid == 0) {
                                ret = STMF_ERROR_NO_PROP;
                                goto done;
                        }
                        if ((reqLen = strlcpy(propVal, (char *)&(
                            sbdProps->mlu_buf[sbdProps->mlu_mgmt_url_off]),
                            *propLen)) >= *propLen) {
                                *propLen = reqLen + 1;
                                ret = STMF_ERROR_INVALID_ARG;
                                goto done;
                        }
                        break;
        }

done:
        free(sbdProps);
        (void) close(fd);
        return (ret);
}

/*
 * stmfSetGlobalLuProp
 *
 * Purpose: set a global property for a device type
 *
 */
int
stmfSetGlobalLuProp(uint16_t dType, uint32_t prop, const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        if (dType != STMF_DISK || propVal == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = setDiskGlobalProp(prop, propVal);

        return (ret);
}

/*
 * setDiskGlobalProp
 *
 * Purpose: set properties for resource of type disk
 *
 * resourceProp - valid resource identifier
 * propVal - valid resource value
 */
static int
setDiskGlobalProp(uint32_t resourceProp, const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        sbd_global_props_t *sbdGlobalProps = NULL;
        int sbdGlobalPropsSize = 0;
        int propLen;
        int mluBufSize = 0;
        int fd;
        int savedErrno;
        int ioctlRet;
        stmf_iocdata_t sbdIoctl = {0};

        switch (resourceProp) {
                case STMF_LU_PROP_MGMT_URL:
                        break;
                default:
                        return (STMF_ERROR_INVALID_PROP);
        }

        /*
         * Open control node for sbd
         */
        if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        propLen = strlen(propVal);
        mluBufSize += propLen + 1;
        sbdGlobalPropsSize += sizeof (sbd_global_props_t) - 8 +
            max(8, mluBufSize);
        /*
         * 8 is the size of the buffer set aside for
         * concatenation of variable length fields
         */
        sbdGlobalProps = (sbd_global_props_t *)calloc(1, sbdGlobalPropsSize);
        if (sbdGlobalProps == NULL) {
                (void) close(fd);
                return (STMF_ERROR_NOMEM);
        }

        sbdGlobalProps->mlu_struct_size = sbdGlobalPropsSize;

        switch (resourceProp) {
                case STMF_LU_PROP_MGMT_URL:
                        sbdGlobalProps->mlu_mgmt_url_valid = 1;
                        bcopy(propVal, &(sbdGlobalProps->mlu_buf),
                            propLen + 1);
                        break;
                default:
                        ret = STMF_ERROR_NO_PROP;
                        goto done;
        }

        sbdIoctl.stmf_version = STMF_VERSION_1;
        sbdIoctl.stmf_ibuf_size = sbdGlobalProps->mlu_struct_size;
        sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdGlobalProps;

        ioctlRet = ioctl(fd, SBD_IOCTL_SET_GLOBAL_LU, &sbdIoctl);
        if (ioctlRet != 0) {
                savedErrno = errno;
                switch (savedErrno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                diskError(sbdIoctl.stmf_error, &ret);
                                if (ret == STMF_STATUS_ERROR) {
                                        syslog(LOG_DEBUG,
                                        "modifyDiskLu:ioctl "
                                        "error(%d) (%d) (%d)", ioctlRet,
                                            sbdIoctl.stmf_error, savedErrno);
                                }
                                break;
                }
        }

done:
        free(sbdGlobalProps);
        (void) close(fd);
        return (ret);
}


/*
 * stmfSetLuProp
 *
 * Purpose: set a property on an luResource
 *
 * hdl - allocated luResource
 * prop - property identifier
 * propVal - property value to be set
 */
int
stmfSetLuProp(luResource hdl, uint32_t prop, const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        luResourceImpl *luPropsHdl = hdl;
        if (hdl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (luPropsHdl->type == STMF_DISK) {
                ret = setDiskProp(luPropsHdl, prop, propVal);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        return (ret);
}

/*
 * getDiskProp
 *
 * Purpose: retrieve a given property from a logical unit resource of type disk
 *
 * hdl - allocated luResourceImpl
 * prop - property identifier
 * propVal - pointer to character to contain the retrieved property value
 * propLen - On input this is the length of propVal. On failure, it contains the
 *           number of bytes required for propVal
 */
static int
getDiskProp(luResourceImpl *hdl, uint32_t prop, char *propVal, size_t *propLen)
{
        int ret = STMF_STATUS_SUCCESS;
        diskResource *diskLu = hdl->resource;
        char accessState[20];
        size_t reqLen;

        if (prop == STMF_LU_PROP_ACCESS_STATE) {
                if (diskLu->accessState == SBD_LU_ACTIVE) {
                        (void) strlcpy(accessState, STMF_ACCESS_ACTIVE,
                            sizeof (accessState));
                } else if (diskLu->accessState == SBD_LU_TRANSITION_TO_ACTIVE) {
                        (void) strlcpy(accessState,
                            STMF_ACCESS_STANDBY_TO_ACTIVE,
                            sizeof (accessState));
                } else if (diskLu->accessState == SBD_LU_STANDBY) {
                        (void) strlcpy(accessState, STMF_ACCESS_STANDBY,
                            sizeof (accessState));
                } else if (diskLu->accessState ==
                    SBD_LU_TRANSITION_TO_STANDBY) {
                        (void) strlcpy(accessState,
                            STMF_ACCESS_ACTIVE_TO_STANDBY,
                            sizeof (accessState));
                }
                if ((reqLen = strlcpy(propVal, accessState,
                    *propLen)) >= *propLen) {
                        *propLen = reqLen + 1;
                        return (STMF_ERROR_INVALID_ARG);
                }
                return (0);
        }

        if (diskLu->accessState != SBD_LU_ACTIVE) {
                return (STMF_ERROR_NO_PROP_STANDBY);
        }

        switch (prop) {
                case STMF_LU_PROP_BLOCK_SIZE:
                        if (diskLu->blkSizeValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        reqLen = snprintf(propVal, *propLen, "%llu",
                            (u_longlong_t)diskLu->blkSize);
                        if (reqLen >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_FILENAME:
                        if (diskLu->luDataFileNameValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if ((reqLen = strlcpy(propVal, diskLu->luDataFileName,
                            *propLen)) >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_META_FILENAME:
                        if (diskLu->luMetaFileNameValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if ((reqLen = strlcpy(propVal, diskLu->luMetaFileName,
                            *propLen)) >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_MGMT_URL:
                        if (diskLu->luMgmtUrlValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl,
                            *propLen)) >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_GUID:
                        if (diskLu->luGuidValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        reqLen = snprintf(propVal, *propLen,
                            "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
                            "%02X%02X%02X%02X",
                            diskLu->luGuid[0], diskLu->luGuid[1],
                            diskLu->luGuid[2], diskLu->luGuid[3],
                            diskLu->luGuid[4], diskLu->luGuid[5],
                            diskLu->luGuid[6], diskLu->luGuid[7],
                            diskLu->luGuid[8], diskLu->luGuid[9],
                            diskLu->luGuid[10], diskLu->luGuid[11],
                            diskLu->luGuid[12], diskLu->luGuid[13],
                            diskLu->luGuid[14], diskLu->luGuid[15]);
                        if (reqLen >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_SERIAL_NUM:
                        if (diskLu->serialNumValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if ((reqLen = strlcpy(propVal, diskLu->serialNum,
                            *propLen)) >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_SIZE:
                        if (diskLu->luSizeValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        (void) snprintf(propVal, *propLen, "%llu",
                            (u_longlong_t)diskLu->luSize);
                        break;
                case STMF_LU_PROP_ALIAS:
                        if (diskLu->luAliasValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if ((reqLen = strlcpy(propVal, diskLu->luAlias,
                            *propLen)) >= *propLen) {
                                *propLen = reqLen + 1;
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        break;
                case STMF_LU_PROP_VID:
                        if (diskLu->vidValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if (*propLen <= sizeof (diskLu->vid)) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        bcopy(diskLu->vid, propVal, sizeof (diskLu->vid));
                        propVal[sizeof (diskLu->vid)] = 0;
                        break;
                case STMF_LU_PROP_PID:
                        if (diskLu->pidValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if (*propLen <= sizeof (diskLu->pid)) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        bcopy(diskLu->pid, propVal, sizeof (diskLu->pid));
                        propVal[sizeof (diskLu->pid)] = 0;
                        break;
                case STMF_LU_PROP_WRITE_PROTECT:
                        if (diskLu->writeProtectEnableValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if (diskLu->writeProtectEnable) {
                                if ((reqLen = strlcpy(propVal, "true",
                                    *propLen)) >= *propLen) {
                                        *propLen = reqLen + 1;
                                        return (STMF_ERROR_INVALID_ARG);
                                }
                        } else {
                                if ((reqLen = strlcpy(propVal, "false",
                                    *propLen)) >= *propLen) {
                                        *propLen = reqLen + 1;
                                        return (STMF_ERROR_INVALID_ARG);
                                }
                        }
                        break;
                case STMF_LU_PROP_WRITE_CACHE_DISABLE:
                        if (diskLu->writebackCacheDisableValid == B_FALSE) {
                                return (STMF_ERROR_NO_PROP);
                        }
                        if (diskLu->writebackCacheDisable) {
                                if ((reqLen = strlcpy(propVal, "true",
                                    *propLen)) >= *propLen) {
                                        *propLen = reqLen + 1;
                                        return (STMF_ERROR_INVALID_ARG);
                                }
                        } else {
                                if ((reqLen = strlcpy(propVal, "false",
                                    *propLen)) >= *propLen) {
                                        *propLen = reqLen + 1;
                                        return (STMF_ERROR_INVALID_ARG);
                                }
                        }
                        break;
                default:
                        ret = STMF_ERROR_INVALID_PROP;
                        break;
        }

        return (ret);
}

/*
 * setDiskProp
 *
 * Purpose: set properties for resource of type disk
 *
 * hdl - allocated luResourceImpl
 * resourceProp - valid resource identifier
 * propVal - valid resource value
 */
static int
setDiskProp(luResourceImpl *hdl, uint32_t resourceProp, const char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        int i;
        diskResource *diskLu = hdl->resource;
        unsigned long long numericProp = 0;
        char guidProp[LU_ASCII_GUID_SIZE + 1];
        char ouiProp[OUI_ASCII_SIZE + 1];
        char hostIdProp[HOST_ID_ASCII_SIZE + 1];
        unsigned int oui[OUI_SIZE];
        unsigned int hostId[HOST_ID_SIZE];
        unsigned int guid[LU_GUID_SIZE];
        int propSize;


        if (propVal == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        switch (resourceProp) {
                case STMF_LU_PROP_ALIAS:
                        if (strlcpy(diskLu->luAlias, propVal,
                            sizeof (diskLu->luAlias)) >=
                            sizeof (diskLu->luAlias)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        diskLu->luAliasValid = B_TRUE;
                        break;
                case STMF_LU_PROP_BLOCK_SIZE: {
                        const char *tmp = propVal;
                        while (*tmp) {
                                if (!isdigit(*tmp++)) {
                                        return (STMF_ERROR_INVALID_ARG);
                                }
                        }
                        (void) sscanf(propVal, "%llu", &numericProp);
                        if (numericProp > UINT16_MAX) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        diskLu->blkSize = numericProp;
                        diskLu->blkSizeValid = B_TRUE;
                        break;
                }
                case STMF_LU_PROP_COMPANY_ID:
                        if ((strlcpy(ouiProp, propVal, sizeof (ouiProp))) >=
                            sizeof (ouiProp)) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        if (checkHexUpper(ouiProp) != 0) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        (void) sscanf(ouiProp, "%2X%2X%2X",
                            &oui[0], &oui[1], &oui[2]);

                        diskLu->companyId = 0;
                        diskLu->companyId += oui[0] << 16;
                        diskLu->companyId += oui[1] << 8;
                        diskLu->companyId += oui[2];
                        if (diskLu->companyId == 0) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        diskLu->companyIdValid = B_TRUE;
                        break;
                case STMF_LU_PROP_HOST_ID:
                        if ((strlcpy(hostIdProp, propVal,
                            sizeof (hostIdProp))) >= sizeof (hostIdProp)) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        if (checkHexUpper(hostIdProp) != 0) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        (void) sscanf(hostIdProp, "%2X%2X%2X%2X",
                            &hostId[0], &hostId[1], &hostId[2], &hostId[3]);

                        diskLu->hostId = 0;
                        diskLu->hostId += hostId[0] << 24;
                        diskLu->hostId += hostId[1] << 16;
                        diskLu->hostId += hostId[2] << 8;
                        diskLu->hostId += hostId[3];
                        if (diskLu->hostId == 0) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        diskLu->hostIdValid = B_TRUE;
                        break;
                case STMF_LU_PROP_GUID:
                        if (strlen(propVal) != LU_ASCII_GUID_SIZE) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }

                        if ((strlcpy(guidProp, propVal, sizeof (guidProp))) >=
                            sizeof (guidProp)) {
                                return (STMF_ERROR_INVALID_ARG);
                        }

                        if (checkHexUpper(guidProp) != 0) {
                                return (STMF_ERROR_INVALID_ARG);
                        }

                        (void) sscanf(guidProp,
                            "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
                            &guid[0], &guid[1], &guid[2], &guid[3], &guid[4],
                            &guid[5], &guid[6], &guid[7], &guid[8], &guid[9],
                            &guid[10], &guid[11], &guid[12], &guid[13],
                            &guid[14], &guid[15]);
                        for (i = 0; i < sizeof (diskLu->luGuid); i++) {
                                diskLu->luGuid[i] = guid[i];
                        }
                        diskLu->luGuidValid = B_TRUE;
                        break;
                case STMF_LU_PROP_FILENAME:
                        if ((strlcpy(diskLu->luDataFileName, propVal,
                            sizeof (diskLu->luDataFileName))) >=
                            sizeof (diskLu->luDataFileName)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        diskLu->luDataFileNameValid = B_TRUE;
                        break;
                case STMF_LU_PROP_META_FILENAME:
                        if ((strlcpy(diskLu->luMetaFileName, propVal,
                            sizeof (diskLu->luMetaFileName))) >=
                            sizeof (diskLu->luMetaFileName)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        diskLu->luMetaFileNameValid = B_TRUE;
                        break;
                case STMF_LU_PROP_MGMT_URL:
                        if ((strlcpy(diskLu->luMgmtUrl, propVal,
                            sizeof (diskLu->luMgmtUrl))) >=
                            sizeof (diskLu->luMgmtUrl)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        diskLu->luMgmtUrlValid = B_TRUE;
                        break;
                case STMF_LU_PROP_PID:
                        if ((propSize = strlen(propVal)) >
                            sizeof (diskLu->pid)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        (void) strncpy(diskLu->pid, propVal, propSize);
                        diskLu->pidValid = B_TRUE;
                        break;
                case STMF_LU_PROP_SERIAL_NUM:
                        if ((propSize = strlen(propVal)) >
                            (sizeof (diskLu->serialNum) - 1)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        (void) strncpy(diskLu->serialNum, propVal, propSize);
                        diskLu->serialNumValid = B_TRUE;
                        break;
                case STMF_LU_PROP_SIZE:
                        if ((niceStrToNum(propVal, &diskLu->luSize) != 0)) {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        diskLu->luSizeValid = B_TRUE;
                        break;
                case STMF_LU_PROP_VID:
                        if ((propSize = strlen(propVal)) >
                            sizeof (diskLu->vid)) {
                                return (STMF_ERROR_INVALID_PROPSIZE);
                        }
                        (void) strncpy(diskLu->vid, propVal, propSize);
                        diskLu->vidValid = B_TRUE;
                        break;
                case STMF_LU_PROP_WRITE_PROTECT:
                        if (strcasecmp(propVal, "TRUE") == 0) {
                                diskLu->writeProtectEnable = B_TRUE;
                        } else if (strcasecmp(propVal, "FALSE") == 0) {
                                diskLu->writeProtectEnable = B_FALSE;
                        } else {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        diskLu->writeProtectEnableValid = B_TRUE;
                        break;
                case STMF_LU_PROP_WRITE_CACHE_DISABLE:
                        if (strcasecmp(propVal, "TRUE") == 0) {
                                diskLu->writebackCacheDisable = B_TRUE;
                        } else if (strcasecmp(propVal, "FALSE") == 0) {
                                diskLu->writebackCacheDisable = B_FALSE;
                        } else {
                                return (STMF_ERROR_INVALID_ARG);
                        }
                        diskLu->writebackCacheDisableValid = B_TRUE;
                        break;
                case STMF_LU_PROP_ACCESS_STATE:
                        ret = STMF_ERROR_INVALID_PROP;
                        break;
                default:
                        ret = STMF_ERROR_INVALID_PROP;
                        break;
        }
        return (ret);
}

static int
checkHexUpper(char *buf)
{
        int i;

        for (i = 0; i < strlen(buf); i++) {
                if (isxdigit(buf[i])) {
                        buf[i] = toupper(buf[i]);
                        continue;
                }
                return (-1);
        }

        return (0);
}

/*
 * Given a numeric suffix, convert the value into a number of bits that the
 * resulting value must be shifted.
 * Code lifted from libzfs_util.c
 */
static int
strToShift(const char *buf)
{
        const char *ends = "BKMGTPE";
        int i;

        if (buf[0] == '\0')
                return (0);

        for (i = 0; i < strlen(ends); i++) {
                if (toupper(buf[0]) == ends[i])
                        return (10*i);
        }

        return (-1);
}

int
stmfFreeLuResource(luResource hdl)
{
        int ret = STMF_STATUS_SUCCESS;
        if (hdl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        luResourceImpl *hdlImpl = hdl;
        free(hdlImpl->resource);
        free(hdlImpl);
        return (ret);
}

/*
 * Convert a string of the form '100G' into a real number. Used when setting
 * the size of a logical unit.
 * Code lifted from libzfs_util.c
 */
static int
niceStrToNum(const char *value, uint64_t *num)
{
        char *end;
        int shift;

        *num = 0;

        /* Check to see if this looks like a number.  */
        if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
                return (-1);
        }

        /* Rely on stroull() to process the numeric portion.  */
        errno = 0;
        *num = strtoull(value, &end, 10);

        /*
         * Check for ERANGE, which indicates that the value is too large to fit
         * in a 64-bit value.
         */
        if (errno == ERANGE) {
                return (-1);
        }

        /*
         * If we have a decimal value, then do the computation with floating
         * point arithmetic.  Otherwise, use standard arithmetic.
         */
        if (*end == '.') {
                double fval = strtod(value, &end);

                if ((shift = strToShift(end)) == -1) {
                        return (-1);
                }

                fval *= pow(2, shift);

                if (fval > UINT64_MAX) {
                        return (-1);
                }

                *num = (uint64_t)fval;
        } else {
                if ((shift = strToShift(end)) == -1) {
                        return (-1);
                }

                /* Check for overflow */
                if (shift >= 64 || (*num << shift) >> shift != *num) {
                        return (-1);
                }

                *num <<= shift;
        }

        return (0);
}

/*
 * stmfCreateTargetGroup
 *
 * Purpose: Create a local port group
 *
 * targetGroupName - name of local port group to create
 */
int
stmfCreateTargetGroup(stmfGroupName *targetGroupName)
{
        int ret;
        int fd;

        if (targetGroupName == NULL ||
            (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
            == sizeof (stmfGroupName))) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Add the group to the driver
         */
        if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
            targetGroupName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        /*
         * If the add to the driver was successful, add it to the persistent
         * store.
         */
        ret = psCreateTargetGroup((char *)targetGroupName);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_EXISTS:
                        ret = STMF_ERROR_EXISTS;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfCreateTargetGroup:psCreateTargetGroup"
                            ":error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfDeleteHostGroup
 *
 * Purpose: Delete an initiator or local port group
 *
 * hostGroupName - group to delete
 */
int
stmfDeleteHostGroup(stmfGroupName *hostGroupName)
{
        int ret;
        int fd;

        if (hostGroupName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Remove the group from the driver
         */
        if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP,
            hostGroupName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        /*
         * If the remove from the driver was successful, remove it from the
         * persistent store.
         */
        ret = psDeleteHostGroup((char *)hostGroupName);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfDeleteTargetGroup
 *
 * Purpose: Delete an initiator or local port group
 *
 * targetGroupName - group to delete
 */
int
stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;

        if (targetGroupName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Remove the group from the driver
         */
        if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP,
            targetGroupName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        /*
         * If the remove from the driver was successful, remove it from the
         * persistent store.
         */
        ret = psDeleteTargetGroup((char *)targetGroupName);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfDeleteTargetGroup:psDeleteTargetGroup"
                            ":error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfDevidFromIscsiName
 *
 * Purpose: convert an iSCSI name to an stmf devid
 *
 * iscsiName - unicode nul terminated utf-8 encoded iSCSI name
 * devid - on success, contains the converted iscsi name
 */
int
stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid)
{
        if (devid == NULL || iscsiName == NULL)
                return (STMF_ERROR_INVALID_ARG);

        bzero(devid, sizeof (stmfDevid));

        /* Validate size of target */
        if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME ||
            devid->identLength < strlen(EUI) ||
            devid->identLength < strlen(IQN)) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) &&
            strncmp(iscsiName, IQN, strlen(IQN)) != 0) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* copy UTF-8 bytes to ident */
        bcopy(iscsiName, devid->ident, devid->identLength);

        return (STMF_STATUS_SUCCESS);
}

/*
 * stmfDevidFromWwn
 *
 * Purpose: convert a WWN to an stmf devid
 *
 * wwn - 8-byte wwn identifier
 * devid - on success, contains the converted wwn
 */
int
stmfDevidFromWwn(uchar_t wwn[8], stmfDevid *devid)
{
        if (wwn == NULL || devid == NULL)
                return (STMF_ERROR_INVALID_ARG);

        bzero(devid, sizeof (stmfDevid));

        /* Copy eui prefix */
        (void) bcopy(WWN, devid->ident, strlen(WWN));

        /* Convert to ASCII uppercase hexadecimal string */
        (void) snprintf((char *)&devid->ident[strlen(WWN)],
            sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X",
            wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);

        devid->identLength = strlen((char *)devid->ident);

        return (STMF_STATUS_SUCCESS);
}

/*
 * stmfFreeMemory
 *
 * Purpose: Free memory allocated by this library
 *
 * memory - previously allocated pointer of memory managed by library
 */
void
stmfFreeMemory(void *memory)
{
        free(memory);
}

/*
 * get host group, target group list from stmf
 *
 * groupType - HOST_GROUP, TARGET_GROUP
 */
static int
groupListIoctl(stmfGroupList **groupList, int groupType)
{
        int ret;
        int fd;
        int ioctlRet;
        int i;
        int cmd;
        stmf_iocdata_t stmfIoctl;
        /* framework group list */
        stmf_group_name_t *iGroupList = NULL;
        uint32_t groupListSize;

        if (groupList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (groupType == HOST_GROUP) {
                cmd = STMF_IOCTL_GET_HG_LIST;
        } else if (groupType == TARGET_GROUP) {
                cmd = STMF_IOCTL_GET_TG_LIST;
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Allocate ioctl input buffer
         */
        groupListSize = ALLOC_GROUP;
        groupListSize = groupListSize * (sizeof (stmf_group_name_t));
        iGroupList = (stmf_group_name_t *)calloc(1, groupListSize);
        if (iGroupList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to get the group list
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_obuf_size = groupListSize;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "groupListIoctl:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }
        /*
         * Check whether input buffer was large enough
         */
        if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GROUP) {
                groupListSize = stmfIoctl.stmf_obuf_max_nentries *
                    sizeof (stmf_group_name_t);
                iGroupList = realloc(iGroupList, groupListSize);
                if (iGroupList == NULL) {
                        ret = STMF_ERROR_NOMEM;
                        goto done;
                }
                stmfIoctl.stmf_obuf_size = groupListSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
                ioctlRet = ioctl(fd, cmd, &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "groupListIoctl:ioctl errno(%d)",
                                            errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        goto done;
                }
        }

        /* allocate and copy to caller's buffer */
        *groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
            sizeof (stmfGroupName) * stmfIoctl.stmf_obuf_nentries);
        if (*groupList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }
        (*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
        for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
                bcopy(iGroupList[i].name, (*groupList)->name[i],
                    sizeof (stmfGroupName));
        }

done:
        free(iGroupList);
        (void) close(fd);
        return (ret);
}

/*
 * get host group members, target group members from stmf
 *
 * groupProps - allocated on success
 *
 * groupType - HOST_GROUP, TARGET_GROUP
 */
static int
groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
    int groupType)
{
        int ret;
        int fd;
        int ioctlRet;
        int i;
        int cmd;
        stmf_iocdata_t stmfIoctl;
        /* framework group list */
        stmf_group_name_t iGroupName;
        stmf_ge_ident_t *iGroupMembers;
        uint32_t groupListSize;

        if (groupName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (groupType == HOST_GROUP) {
                cmd = STMF_IOCTL_GET_HG_ENTRIES;
        } else if (groupType == TARGET_GROUP) {
                cmd = STMF_IOCTL_GET_TG_ENTRIES;
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        bzero(&iGroupName, sizeof (iGroupName));

        bcopy(groupName, &iGroupName.name, strlen((char *)groupName));

        iGroupName.name_size = strlen((char *)groupName);

        /*
         * Allocate ioctl input buffer
         */
        groupListSize = ALLOC_GRP_MEMBER;
        groupListSize = groupListSize * (sizeof (stmf_ge_ident_t));
        iGroupMembers = (stmf_ge_ident_t *)calloc(1, groupListSize);
        if (iGroupMembers == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to get the group list
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
        stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
        stmfIoctl.stmf_obuf_size = groupListSize;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "groupListIoctl:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }
        /*
         * Check whether input buffer was large enough
         */
        if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GRP_MEMBER) {
                groupListSize = stmfIoctl.stmf_obuf_max_nentries *
                    sizeof (stmf_ge_ident_t);
                iGroupMembers = realloc(iGroupMembers, groupListSize);
                if (iGroupMembers == NULL) {
                        ret = STMF_ERROR_NOMEM;
                        goto done;
                }
                stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
                stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
                stmfIoctl.stmf_obuf_size = groupListSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
                ioctlRet = ioctl(fd, cmd, &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "groupListIoctl:ioctl errno(%d)",
                                            errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        goto done;
                }
        }

        /* allocate and copy to caller's buffer */
        *groupProps = (stmfGroupProperties *)calloc(1,
            sizeof (stmfGroupProperties) +
            sizeof (stmfDevid) * stmfIoctl.stmf_obuf_nentries);
        if (*groupProps == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }
        (*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
        for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
                (*groupProps)->name[i].identLength =
                    iGroupMembers[i].ident_size;
                bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident,
                    iGroupMembers[i].ident_size);
        }

done:
        free(iGroupMembers);
        (void) close(fd);
        return (ret);
}

/*
 * Purpose: access persistent config data for host groups and target groups
 */
static int
iLoadGroupFromPs(stmfGroupList **groupList, int type)
{
        int ret;

        if (groupList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (type == HOST_GROUP) {
                ret = psGetHostGroupList(groupList);
        } else if (type == TARGET_GROUP) {
                ret = psGetTargetGroupList(groupList);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfGetHostGroupList:psGetHostGroupList:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

        return (ret);
}

/*
 * stmfGetHostGroupList
 *
 * Purpose: Retrieves the list of initiator group oids
 *
 * hostGroupList - pointer to pointer to hostGroupList structure
 *                 on success, this contains the host group list.
 */
int
stmfGetHostGroupList(stmfGroupList **hostGroupList)
{
        int ret = STMF_STATUS_ERROR;

        if (hostGroupList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = groupListIoctl(hostGroupList, HOST_GROUP);
        return (ret);
}


/*
 * Purpose: access persistent config data for host groups and target groups
 */
static int
iLoadGroupMembersFromPs(stmfGroupName *groupName,
    stmfGroupProperties **groupProp, int type)
{
        int ret;

        if (groupName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (type == HOST_GROUP) {
                ret = psGetHostGroupMemberList((char *)groupName, groupProp);
        } else if (type == TARGET_GROUP) {
                ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
        } else {
                return (STMF_ERROR_INVALID_ARG);
        }
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "iLoadGroupMembersFromPs:psGetHostGroupList:"
                            "error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

        return (ret);
}

/*
 * stmfGetHostGroupMembers
 *
 * Purpose: Retrieves the group properties for a host group
 *
 * groupName - name of group for which to retrieve host group members.
 * groupProp - pointer to pointer to stmfGroupProperties structure
 *             on success, this contains the list of group members.
 */
int
stmfGetHostGroupMembers(stmfGroupName *groupName,
    stmfGroupProperties **groupProp)
{
        int ret;

        if (groupName == NULL || groupProp == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = groupMemberListIoctl(groupName, groupProp, HOST_GROUP);

        return (ret);
}

/*
 * stmfGetProviderData
 *
 * Purpose: Get provider data list
 *
 * providerName - name of provider for which to retrieve the data
 * nvl - pointer to nvlist_t pointer which will contain the nvlist data
 *       retrieved.
 * providerType - type of provider for which to retrieve data.
 *                  STMF_LU_PROVIDER_TYPE
 *                  STMF_PORT_PROVIDER_TYPE
 */
int
stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType)
{
        return (stmfGetProviderDataProt(providerName, nvl, providerType,
            NULL));
}

/*
 * stmfGetProviderDataProt
 *
 * Purpose: Get provider data list with token
 *
 * providerName - name of provider for which to retrieve the data
 * nvl - pointer to nvlist_t pointer which will contain the nvlist data
 *       retrieved.
 * providerType - type of provider for which to retrieve data.
 *                  STMF_LU_PROVIDER_TYPE
 *                  STMF_PORT_PROVIDER_TYPE
 * setToken - Returns the stale data token
 */
int
stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
    uint64_t *setToken)
{
        int ret;

        if (providerName == NULL || nvl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }
        if (providerType != STMF_LU_PROVIDER_TYPE &&
            providerType != STMF_PORT_PROVIDER_TYPE) {
                return (STMF_ERROR_INVALID_ARG);
        }
        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }
        return (getProviderData(providerName, nvl, providerType, setToken));
}

/*
 * stmfGetProviderDataList
 *
 * Purpose: Get the list of providers currently persisting data
 *
 * providerList - pointer to pointer to an stmfProviderList structure allocated
 *                by the caller. Will contain the list of providers on success.
 */
int
stmfGetProviderDataList(stmfProviderList **providerList)
{
        int ret;

        ret = psGetProviderDataList(providerList);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfGetProviderDataList:psGetProviderDataList"
                            ":error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

        return (ret);
}


/*
 * stmfGetSessionList
 *
 * Purpose: Retrieves the session list for a target (devid)
 *
 * devid - devid of target for which to retrieve session information.
 * sessionList - pointer to pointer to stmfSessionList structure
 *             on success, this contains the list of initiator sessions.
 */
int
stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        int ioctlRet;
        int cmd = STMF_IOCTL_SESSION_LIST;
        int i;
        stmf_iocdata_t stmfIoctl;
        slist_scsi_session_t *fSessionList, *fSessionListP = NULL;
        uint8_t ident[260];
        uint32_t fSessionListSize;

        if (sessionList == NULL || devid == NULL) {
                ret = STMF_ERROR_INVALID_ARG;
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Allocate ioctl input buffer
         */
        fSessionListSize = ALLOC_SESSION;
        fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
        fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
        fSessionListP = fSessionList;
        if (fSessionList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        ident[IDENT_LENGTH_BYTE] = devid->identLength;
        bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1],
            devid->identLength);

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to get the session list
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident;
        stmfIoctl.stmf_ibuf_size = sizeof (ident);
        stmfIoctl.stmf_obuf_size = fSessionListSize;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfGetSessionList:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }
        /*
         * Check whether input buffer was large enough
         */
        if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_SESSION) {
                fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
                    sizeof (slist_scsi_session_t);
                fSessionList = realloc(fSessionList, fSessionListSize);
                if (fSessionList == NULL) {
                        ret = STMF_ERROR_NOMEM;
                        goto done;
                }
                fSessionListP = fSessionList;
                stmfIoctl.stmf_obuf_size = fSessionListSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
                ioctlRet = ioctl(fd, cmd, &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "stmfGetSessionList:ioctl "
                                            "errno(%d)", errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        goto done;
                }
        }

        /*
         * allocate caller's buffer with the final size
         */
        *sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) +
            stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession));
        if (*sessionList == NULL) {
                ret = STMF_ERROR_NOMEM;
                free(sessionList);
                goto done;
        }

        (*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries;

        /*
         * copy session info to caller's buffer
         */
        for (i = 0; i < (*sessionList)->cnt; i++) {
                (*sessionList)->session[i].initiator.identLength =
                    fSessionList->initiator[IDENT_LENGTH_BYTE];
                bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]),
                    (*sessionList)->session[i].initiator.ident,
                    STMF_IDENT_LENGTH);
                bcopy(&(fSessionList->alias),
                    &((*sessionList)->session[i].alias),
                    sizeof ((*sessionList)->session[i].alias));
                bcopy(&(fSessionList++->creation_time),
                    &((*sessionList)->session[i].creationTime),
                    sizeof (time_t));
        }
done:
        (void) close(fd);
        free(fSessionListP);
        return (ret);
}

/*
 * stmfGetTargetGroupList
 *
 * Purpose: Retrieves the list of target groups
 *
 * targetGroupList - pointer to a pointer to an stmfGroupList structure. On
 *                   success, it contains the list of target groups.
 */
int
stmfGetTargetGroupList(stmfGroupList **targetGroupList)
{
        int ret;

        if (targetGroupList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = groupListIoctl(targetGroupList, TARGET_GROUP);
        return (ret);
}

/*
 * stmfGetTargetGroupMembers
 *
 * Purpose: Retrieves the group members for a target group
 *
 * groupName - name of target group for which to retrieve members.
 * groupProp - pointer to pointer to stmfGroupProperties structure
 *             on success, this contains the list of group members.
 */
int
stmfGetTargetGroupMembers(stmfGroupName *groupName,
    stmfGroupProperties **groupProp)
{
        int ret;

        if (groupName == NULL || groupProp == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = groupMemberListIoctl(groupName, groupProp, TARGET_GROUP);

        return (ret);
}

/*
 * stmfGetTargetList
 *
 * Purpose: Retrieves the list of target ports
 *
 * targetList - pointer to a pointer to an stmfDevidList structure.
 *                  On success, it contains the list of local ports (target).
 */
int
stmfGetTargetList(stmfDevidList **targetList)
{
        int ret;
        int fd;
        int ioctlRet;
        int i;
        stmf_iocdata_t stmfIoctl;
        /* framework target port list */
        slist_target_port_t *fTargetList, *fTargetListP = NULL;
        uint32_t fTargetListSize;

        if (targetList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Allocate ioctl input buffer
         */
        fTargetListSize = ALLOC_TARGET_PORT * sizeof (slist_target_port_t);
        fTargetListP = fTargetList =
            (slist_target_port_t *)calloc(1, fTargetListSize);
        if (fTargetList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to retrieve target list
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_obuf_size = fTargetListSize;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
        ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfGetTargetList:ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }
        /*
         * Check whether input buffer was large enough
         */
        if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_TARGET_PORT) {
                fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
                    sizeof (slist_target_port_t);
                fTargetListP = fTargetList =
                    realloc(fTargetList, fTargetListSize);
                if (fTargetList == NULL) {
                        ret = STMF_ERROR_NOMEM;
                        goto done;
                }
                stmfIoctl.stmf_obuf_size = fTargetListSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
                ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST,
                    &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "stmfGetTargetList:ioctl errno(%d)",
                                            errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        goto done;
                }
        }

        *targetList = (stmfDevidList *)calloc(1,
            stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
            sizeof (stmfDevidList));
        if (*targetList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        (*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
        for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
                (*targetList)->devid[i].identLength =
                    fTargetList->target[IDENT_LENGTH_BYTE];
                bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1],
                    &(*targetList)->devid[i].ident,
                    fTargetList->target[IDENT_LENGTH_BYTE]);
        }

done:
        (void) close(fd);
        free(fTargetListP);
        return (ret);
}

/*
 * stmfGetTargetProperties
 *
 * Purpose:  Retrieves the properties for a logical unit
 *
 * devid - devid of the target for which to retrieve properties
 * targetProps - pointer to an stmfTargetProperties structure.
 *              On success, it contains the target properties for
 *              the specified devid.
 */
int
stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;
        sioc_target_port_props_t targetProperties;
        scsi_devid_desc_t *scsiDevid;

        if (devid == NULL || targetProps == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength;
        bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1],
            devid->identLength);

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to add to the host group
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties;
        stmfIoctl.stmf_obuf_size = sizeof (targetProperties);
        ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES,
            &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case ENOENT:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfGetTargetProperties:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }

        bcopy(targetProperties.tgt_provider_name, targetProps->providerName,
            sizeof (targetProperties.tgt_provider_name));
        if (targetProperties.tgt_state == STMF_STATE_ONLINE) {
                targetProps->status = STMF_TARGET_PORT_ONLINE;
        } else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) {
                targetProps->status = STMF_TARGET_PORT_OFFLINE;
        } else if (targetProperties.tgt_state == STMF_STATE_ONLINING) {
                targetProps->status = STMF_TARGET_PORT_ONLINING;
        } else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) {
                targetProps->status = STMF_TARGET_PORT_OFFLINING;
        }
        bcopy(targetProperties.tgt_alias, targetProps->alias,
            sizeof (targetProps->alias));

        scsiDevid = (scsi_devid_desc_t *)&targetProperties.tgt_id;
        targetProps->protocol = scsiDevid->protocol_id;

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfGetLogicalUnitList
 *
 * Purpose: Retrieves list of logical unit Object IDs
 *
 * luList - pointer to a pointer to a stmfGuidList structure. On success,
 *          it contains the list of logical unit guids.
 *
 */
int
stmfGetLogicalUnitList(stmfGuidList **luList)
{
        int ret;
        int fd;
        int ioctlRet;
        int cmd = STMF_IOCTL_LU_LIST;
        int i;
        stmf_iocdata_t stmfIoctl;
        slist_lu_t *fLuList;
        uint32_t fLuListSize;
        uint32_t listCnt;

        if (luList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Allocate ioctl input buffer
         */
        fLuListSize = ALLOC_LU;
        fLuListSize = fLuListSize * (sizeof (slist_lu_t));
        fLuList = (slist_lu_t *)calloc(1, fLuListSize);
        if (fLuList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to get the LU list
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_obuf_size = fLuListSize;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfGetLogicalUnitList:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }
        /*
         * Check whether input buffer was large enough
         */
        if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_LU) {
                fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
                    sizeof (slist_lu_t);
                free(fLuList);
                fLuList = (slist_lu_t *)calloc(1, fLuListSize);
                if (fLuList == NULL) {
                        ret = STMF_ERROR_NOMEM;
                        goto done;
                }
                stmfIoctl.stmf_obuf_size = fLuListSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
                ioctlRet = ioctl(fd, cmd, &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "stmfGetLogicalUnitList:"
                                            "ioctl errno(%d)", errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        goto done;
                }
        }

        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        listCnt = stmfIoctl.stmf_obuf_nentries;

        /*
         * allocate caller's buffer with the final size
         */
        *luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
            listCnt * sizeof (stmfGuid));
        if (*luList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        (*luList)->cnt = listCnt;

        /* copy to caller's buffer */
        for (i = 0; i < listCnt; i++) {
                bcopy(&fLuList[i].lu_guid, (*luList)->guid[i].guid,
                    sizeof (stmfGuid));
        }

        /*
         * sort the list. This gives a consistent view across gets
         */
        qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
            sizeof (stmfGuid), guidCompare);

done:
        (void) close(fd);
        /*
         * free internal buffers
         */
        free(fLuList);
        return (ret);
}

/*
 * stmfGetLogicalUnitProperties
 *
 * Purpose:  Retrieves the properties for a logical unit
 *
 * lu - guid of the logical unit for which to retrieve properties
 * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success,
 *               it contains the logical unit properties for the specified guid.
 */
int
stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
{
        int ret = STMF_STATUS_SUCCESS;
        int stmfRet;
        int fd;
        int ioctlRet;
        int cmd = STMF_IOCTL_GET_LU_PROPERTIES;
        stmfViewEntryList *viewEntryList = NULL;
        stmf_iocdata_t stmfIoctl;
        sioc_lu_props_t fLuProps;

        if (lu == NULL || luProps == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        bzero(luProps, sizeof (stmfLogicalUnitProperties));

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to add to the host group
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps;
        stmfIoctl.stmf_obuf_size = sizeof (fLuProps);
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case ENOENT:
                                stmfRet = stmfGetViewEntryList(lu,
                                    &viewEntryList);
                                if (stmfRet == STMF_STATUS_SUCCESS) {
                                        luProps->status =
                                            STMF_LOGICAL_UNIT_UNREGISTERED;
                                        if (viewEntryList->cnt > 0) {
                                                ret = STMF_STATUS_SUCCESS;
                                        } else {
                                                ret = STMF_ERROR_NOT_FOUND;
                                        }
                                } else {
                                        ret = STMF_ERROR_NOT_FOUND;
                                }
                                stmfFreeMemory(viewEntryList);
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfGetLogicalUnit:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }

        bcopy(fLuProps.lu_provider_name, luProps->providerName,
            sizeof (fLuProps.lu_provider_name));
        if (fLuProps.lu_state == STMF_STATE_ONLINE) {
                luProps->status = STMF_LOGICAL_UNIT_ONLINE;
        } else if (fLuProps.lu_state == STMF_STATE_OFFLINE) {
                luProps->status = STMF_LOGICAL_UNIT_OFFLINE;
        } else if (fLuProps.lu_state == STMF_STATE_ONLINING) {
                luProps->status = STMF_LOGICAL_UNIT_ONLINING;
        } else if (fLuProps.lu_state == STMF_STATE_OFFLINING) {
                luProps->status = STMF_LOGICAL_UNIT_OFFLINING;
        }
        bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias));
done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfGetState
 *
 * Purpose: retrieve the current state of the stmf module
 *
 * state - pointer to stmfState structure allocated by the caller
 *         On success, contains the state of stmf
 */
int
stmfGetState(stmfState *state)
{
        int ret;
        stmf_state_desc_t iState;

        if (state == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        ret = getStmfState(&iState);
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }
        switch (iState.state) {
                case STMF_STATE_ONLINE:
                        state->operationalState =
                            STMF_SERVICE_STATE_ONLINE;
                        break;
                case STMF_STATE_OFFLINE:
                        state->operationalState =
                            STMF_SERVICE_STATE_OFFLINE;
                        break;
                case STMF_STATE_ONLINING:
                        state->operationalState =
                            STMF_SERVICE_STATE_ONLINING;
                        break;
                case STMF_STATE_OFFLINING:
                        state->operationalState =
                            STMF_SERVICE_STATE_OFFLINING;
                        break;
                default:
                        state->operationalState =
                            STMF_SERVICE_STATE_UNKNOWN;
                        break;
        }
        switch (iState.config_state) {
                case STMF_CONFIG_NONE:
                        state->configState = STMF_CONFIG_STATE_NONE;
                        break;
                case STMF_CONFIG_INIT:
                        state->configState = STMF_CONFIG_STATE_INIT;
                        break;
                case STMF_CONFIG_INIT_DONE:
                        state->configState =
                            STMF_CONFIG_STATE_INIT_DONE;
                        break;
                default:
                        state->configState =
                            STMF_CONFIG_STATE_UNKNOWN;
                        break;
        }
        return (STMF_STATUS_SUCCESS);
}

/*
 * stmfGetViewEntryList
 *
 * Purpose: Retrieves the list of view entries for the specified
 *          logical unit.
 *
 * lu - the guid of the logical unit for which to retrieve the view entry list
 * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On
 *                 success, contains the list of view entries.
 */
int
stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
{
        int ret;
        int fd;
        int ioctlRet;
        int cmd = STMF_IOCTL_LU_VE_LIST;
        int i;
        stmf_iocdata_t stmfIoctl;
        stmf_view_op_entry_t *fVeList;
        uint32_t fVeListSize;
        uint32_t listCnt;

        if (lu == NULL || viewEntryList == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Allocate ioctl input buffer
         */
        fVeListSize = ALLOC_VE;
        fVeListSize = fVeListSize * (sizeof (stmf_view_op_entry_t));
        fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
        if (fVeList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to get the LU list
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
        stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
        stmfIoctl.stmf_obuf_size = fVeListSize;
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfGetViewEntryList:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }
        /*
         * Check whether input buffer was large enough
         */
        if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_VE) {
                bzero(&stmfIoctl, sizeof (stmfIoctl));
                fVeListSize = stmfIoctl.stmf_obuf_max_nentries *
                    sizeof (stmf_view_op_entry_t);
                free(fVeList);
                fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
                if (fVeList == NULL) {
                        return (STMF_ERROR_NOMEM);
                }
                stmfIoctl.stmf_obuf_size = fVeListSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
                ioctlRet = ioctl(fd, cmd, &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "stmfGetLogicalUnitList:"
                                            "ioctl errno(%d)", errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        goto done;
                }
        }

        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        listCnt = stmfIoctl.stmf_obuf_nentries;

        /*
         * allocate caller's buffer with the final size
         */
        *viewEntryList = (stmfViewEntryList *)calloc(1,
            sizeof (stmfViewEntryList) + listCnt * sizeof (stmfViewEntry));
        if (*viewEntryList == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        (*viewEntryList)->cnt = listCnt;

        /* copy to caller's buffer */
        for (i = 0; i < listCnt; i++) {
                (*viewEntryList)->ve[i].veIndexValid = B_TRUE;
                (*viewEntryList)->ve[i].veIndex = fVeList[i].ve_ndx;
                if (fVeList[i].ve_all_hosts == 1) {
                        (*viewEntryList)->ve[i].allHosts = B_TRUE;
                } else {
                        bcopy(fVeList[i].ve_host_group.name,
                            (*viewEntryList)->ve[i].hostGroup,
                            fVeList[i].ve_host_group.name_size);
                }
                if (fVeList[i].ve_all_targets == 1) {
                        (*viewEntryList)->ve[i].allTargets = B_TRUE;
                } else {
                        bcopy(fVeList[i].ve_target_group.name,
                            (*viewEntryList)->ve[i].targetGroup,
                            fVeList[i].ve_target_group.name_size);
                }
                bcopy(fVeList[i].ve_lu_nbr, (*viewEntryList)->ve[i].luNbr,
                    sizeof ((*viewEntryList)->ve[i].luNbr));
                (*viewEntryList)->ve[i].luNbrValid = B_TRUE;
        }

        /*
         * sort the list. This gives a consistent view across gets
         */
        qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
            sizeof (stmfViewEntry), viewEntryCompare);

done:
        (void) close(fd);
        /*
         * free internal buffers
         */
        free(fVeList);
        return (ret);
}


/*
 * loadHostGroups
 *
 * Purpose - issues the ioctl to load the host groups into stmf
 *
 * fd - file descriptor for the control node of stmf.
 * groupList - populated host group list
 */
static int
loadHostGroups(int fd, stmfGroupList *groupList)
{
        int i, j;
        int ret = STMF_STATUS_SUCCESS;
        stmfGroupProperties *groupProps = NULL;

        for (i = 0; i < groupList->cnt; i++) {
                if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
                    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
                        goto out;
                }
                ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
                    &groupProps, HOST_GROUP);
                for (j = 0; j < groupProps->cnt; j++) {
                        if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
                            &(groupList->name[i]), &(groupProps->name[j])))
                            != STMF_STATUS_SUCCESS) {
                                goto out;
                        }
                }
        }


out:
        stmfFreeMemory(groupProps);
        return (ret);
}

/*
 * loadTargetGroups
 *
 * Purpose - issues the ioctl to load the target groups into stmf
 *
 * fd - file descriptor for the control node of stmf.
 * groupList - populated target group list.
 */
static int
loadTargetGroups(int fd, stmfGroupList *groupList)
{
        int i, j;
        int ret = STMF_STATUS_SUCCESS;
        stmfGroupProperties *groupProps = NULL;

        for (i = 0; i < groupList->cnt; i++) {
                if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
                    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
                        goto out;
                }
                ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
                    &groupProps, TARGET_GROUP);
                for (j = 0; j < groupProps->cnt; j++) {
                        if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
                            &(groupList->name[i]), &(groupProps->name[j])))
                            != STMF_STATUS_SUCCESS) {
                                goto out;
                        }
                }
        }


out:
        stmfFreeMemory(groupProps);
        return (ret);
}


/*
 * loadStore
 *
 * Purpose: Load the configuration data from the store
 *
 * First load the host groups and target groups, then the view entries
 * and finally the provider data
 *
 * fd - file descriptor of control node for stmf.
 */
static int
loadStore(int fd)
{
        int ret;
        int i, j;
        stmfGroupList *groupList = NULL;
        stmfGuidList *guidList = NULL;
        stmfViewEntryList *viewEntryList = NULL;
        stmfProviderList *providerList = NULL;
        int providerType;
        nvlist_t *nvl = NULL;



        /* load host groups */
        ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }
        ret = loadHostGroups(fd, groupList);
        if (ret != STMF_STATUS_SUCCESS) {
                goto out;
        }

        stmfFreeMemory(groupList);
        groupList = NULL;

        /* load target groups */
        ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
        if (ret != STMF_STATUS_SUCCESS) {
                goto out;
        }
        ret = loadTargetGroups(fd, groupList);
        if (ret != STMF_STATUS_SUCCESS) {
                goto out;
        }

        stmfFreeMemory(groupList);
        groupList = NULL;

        /* Get the guid list */
        ret = psGetLogicalUnitList(&guidList);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        ret = STMF_STATUS_ERROR;
                        break;
        }

        if (ret != STMF_STATUS_SUCCESS) {
                goto out;
        }

        /*
         * We have the guid list, now get the corresponding
         * view entries for each guid
         */
        for (i = 0; i < guidList->cnt; i++) {
                ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList);
                switch (ret) {
                        case STMF_PS_SUCCESS:
                                ret = STMF_STATUS_SUCCESS;
                                break;
                        case STMF_PS_ERROR_NOT_FOUND:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        case STMF_PS_ERROR_BUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                                ret = STMF_ERROR_SERVICE_NOT_FOUND;
                                break;
                        case STMF_PS_ERROR_VERSION_MISMATCH:
                                ret = STMF_ERROR_SERVICE_DATA_VERSION;
                                break;
                        default:
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                if (ret != STMF_STATUS_SUCCESS) {
                        goto out;
                }
                for (j = 0; j < viewEntryList->cnt; j++) {
                        ret = addViewEntryIoctl(fd, &guidList->guid[i],
                            &viewEntryList->ve[j]);
                        if (ret != STMF_STATUS_SUCCESS) {
                                goto out;
                        }
                }
        }

        /* get the list of providers that have data */
        ret = psGetProviderDataList(&providerList);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        ret = STMF_STATUS_ERROR;
                        break;
        }
        if (ret != STMF_STATUS_SUCCESS) {
                goto out;
        }

        for (i = 0; i < providerList->cnt; i++) {
                providerType = providerList->provider[i].providerType;
                ret = psGetProviderData(providerList->provider[i].name,
                    &nvl, providerType, NULL);
                switch (ret) {
                        case STMF_PS_SUCCESS:
                                ret = STMF_STATUS_SUCCESS;
                                break;
                        case STMF_PS_ERROR_NOT_FOUND:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        case STMF_PS_ERROR_BUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                                ret = STMF_ERROR_SERVICE_NOT_FOUND;
                                break;
                        case STMF_PS_ERROR_VERSION_MISMATCH:
                                ret = STMF_ERROR_SERVICE_DATA_VERSION;
                                break;
                        default:
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                if (ret != STMF_STATUS_SUCCESS) {
                        goto out;
                }

                /* call setProviderData */
                ret = setProviderData(fd, providerList->provider[i].name, nvl,
                    providerType, NULL);
                switch (ret) {
                        case STMF_PS_SUCCESS:
                                ret = STMF_STATUS_SUCCESS;
                                break;
                        case STMF_PS_ERROR_NOT_FOUND:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        case STMF_PS_ERROR_BUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                                ret = STMF_ERROR_SERVICE_NOT_FOUND;
                                break;
                        case STMF_PS_ERROR_VERSION_MISMATCH:
                                ret = STMF_ERROR_SERVICE_DATA_VERSION;
                                break;
                        default:
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                if (ret != STMF_STATUS_SUCCESS) {
                        goto out;
                }

                nvlist_free(nvl);
                nvl = NULL;
        }
out:
        if (groupList != NULL) {
                free(groupList);
        }
        if (guidList != NULL) {
                free(guidList);
        }
        if (viewEntryList != NULL) {
                free(viewEntryList);
        }
        if (nvl != NULL) {
                nvlist_free(nvl);
        }
        return (ret);
}

/*
 * stmfGetAluaState
 *
 * Purpose - Get the alua state
 *
 */
int
stmfGetAluaState(boolean_t *enabled, uint32_t *node)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        stmf_iocdata_t stmfIoctl = {0};
        stmf_alua_state_desc_t alua_state = {0};
        int ioctlRet;

        if (enabled == NULL || node == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Issue ioctl to get the stmf state
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_obuf_size = sizeof (alua_state);
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&alua_state;
        ioctlRet = ioctl(fd, STMF_IOCTL_GET_ALUA_STATE, &stmfIoctl);

        (void) close(fd);

        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "getStmfState:ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        } else {
                if (alua_state.alua_state == 1) {
                        *enabled = B_TRUE;
                } else {
                        *enabled = B_FALSE;
                }
                *node = alua_state.alua_node;
        }

        return (ret);
}

/*
 * stmfSetAluaState
 *
 * Purpose - set the alua state to enabled/disabled
 *
 */
int
stmfSetAluaState(boolean_t enabled, uint32_t node)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        stmf_iocdata_t stmfIoctl = {0};
        stmf_alua_state_desc_t alua_state = {0};
        int ioctlRet;

        if ((enabled != B_TRUE && enabled != B_FALSE) || (node > 1)) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (enabled) {
                alua_state.alua_state = 1;
        }

        alua_state.alua_node = node;

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Issue ioctl to get the stmf state
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (alua_state);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&alua_state;
        ioctlRet = ioctl(fd, STMF_IOCTL_SET_ALUA_STATE, &stmfIoctl);

        (void) close(fd);

        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "getStmfState:ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }
        if (!enabled && ret == STMF_STATUS_SUCCESS) {
                deleteNonActiveLus();
        }

        return (ret);
}

static void
deleteNonActiveLus()
{
        int stmfRet;
        int i;
        stmfGuidList *luList;
        luResource hdl = NULL;
        char propVal[10];
        size_t propValSize = sizeof (propVal);

        stmfRet = stmfGetLogicalUnitList(&luList);
        if (stmfRet != STMF_STATUS_SUCCESS) {
                return;
        }

        for (i = 0; i < luList->cnt; i++) {
                stmfRet = stmfGetLuResource(&luList->guid[i], &hdl);
                if (stmfRet != STMF_STATUS_SUCCESS) {
                        goto err;
                }
                stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
                    &propValSize);
                if (stmfRet != STMF_STATUS_SUCCESS) {
                        goto err;
                }
                if (propVal[0] == '0') {
                        (void) stmfFreeLuResource(hdl);
                        hdl = NULL;
                        continue;
                }
                (void) stmfDeleteLu(&luList->guid[i]);
                (void) stmfFreeLuResource(hdl);
                hdl = NULL;
        }

err:
        stmfFreeMemory(luList);
        (void) stmfFreeLuResource(hdl);
}

/*
 * stmfLoadConfig
 *
 * Purpose - load the configuration data from smf into stmf
 *
 */
int
stmfLoadConfig(void)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        stmf_state_desc_t stmfStateSet;
        stmfState state;

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                stmfStateSet.state = STMF_STATE_OFFLINE;

                if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
                    != STMF_STATUS_SUCCESS) {
                        return (ret);
                }
                /*
                 * Configuration not stored persistently; nothing to
                 * initialize so do not set to STMF_CONFIG_INIT.
                 */
                stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
                goto done;
        }

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        ret = stmfGetState(&state);
        if (ret == STMF_STATUS_SUCCESS) {
                if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
                        return (STMF_ERROR_SERVICE_ONLINE);
                }
        } else {
                return (STMF_STATUS_ERROR);
        }


        stmfStateSet.state = STMF_STATE_OFFLINE;
        stmfStateSet.config_state = STMF_CONFIG_INIT;

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        /* Load the persistent configuration data */
        ret = loadStore(fd);
        if (ret != 0) {
                goto done;
        }

        stmfStateSet.state = STMF_STATE_OFFLINE;
        stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;

done:
        if (ret == STMF_STATUS_SUCCESS) {
                ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
        }
        (void) close(fd);
        return (ret);
}


/*
 * getStmfState
 *
 * stmfState - pointer to stmf_state_desc_t structure. Will contain the state
 *             information of the stmf service on success.
 */
static int
getStmfState(stmf_state_desc_t *stmfState)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to get the stmf state
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
        stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t);
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState;
        ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl);

        (void) close(fd);

        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "getStmfState:ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }
        return (ret);
}


/*
 * setStmfState
 *
 * stmfState - pointer to caller set state structure
 * objectType - one of:
 *              LOGICAL_UNIT_TYPE
 *              TARGET_TYPE
 *              STMF_SERVICE_TYPE
 */
static int
setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        int cmd;
        stmf_iocdata_t stmfIoctl;

        switch (objectType) {
                case LOGICAL_UNIT_TYPE:
                        cmd = STMF_IOCTL_SET_LU_STATE;
                        break;
                case TARGET_TYPE:
                        cmd = STMF_IOCTL_SET_TARGET_PORT_STATE;
                        break;
                case STMF_SERVICE_TYPE:
                        cmd = STMF_IOCTL_SET_STMF_STATE;
                        break;
                default:
                        ret = STMF_STATUS_ERROR;
                        goto done;
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to set the stmf state
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
        ioctlRet = ioctl(fd, cmd, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case ENOENT:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "setStmfState:ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }
done:
        return (ret);
}
int
stmfSetStmfProp(uint8_t propType, char *propVal)
{
        int ret = STMF_STATUS_SUCCESS;
        switch (propType) {
                case STMF_DEFAULT_LU_STATE:
                        break;
                case STMF_DEFAULT_TARGET_PORT_STATE:
                        break;
                default:
                        return (STMF_ERROR_INVALID_ARG);
        }
        ret = psSetStmfProp(propType, propVal);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfSetStmfProp:psSetStmfProp:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }
        return (ret);
}


int
stmfGetStmfProp(uint8_t propType, char *propVal, size_t *propLen)
{
        int ret = STMF_STATUS_SUCCESS;
        char prop[MAXNAMELEN] = {0};
        size_t reqLen;

        if (propVal == NULL || propLen == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }
        switch (propType) {
                case STMF_DEFAULT_LU_STATE:
                        break;
                case STMF_DEFAULT_TARGET_PORT_STATE:
                        break;
                default:
                        return (STMF_ERROR_INVALID_ARG);
        }
        ret = psGetStmfProp(propType, prop);
        if ((reqLen = strlcpy(propVal, prop, *propLen)) >= *propLen) {
                *propLen = reqLen + 1;
                return (STMF_ERROR_INVALID_ARG);
        }

        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfGetStmfProp:psGetStmfProp:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }
        return (ret);
}

static int
setStmfProp(stmf_set_props_t *stmf_set_props)
{
        char propVal[MAXNAMELEN] = {0};
        int ret;
        if ((ret = psGetStmfProp(STMF_DEFAULT_LU_STATE, propVal)) ==
            STMF_PS_SUCCESS) {
                if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
                        stmf_set_props->default_lu_state_value =
                            STMF_STATE_OFFLINE;
                } else {
                        stmf_set_props->default_lu_state_value =
                            STMF_STATE_ONLINE;
                }
        } else {
                syslog(LOG_DEBUG,
                    "DefaultLuState:psSetStmfProp:error(%d)", ret);
                goto done;
        }

        if ((ret = psGetStmfProp(STMF_DEFAULT_TARGET_PORT_STATE, propVal)) ==
            STMF_PS_SUCCESS) {
                if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
                        stmf_set_props->default_target_state_value =
                            STMF_STATE_OFFLINE;
                } else {
                        stmf_set_props->default_target_state_value =
                            STMF_STATE_ONLINE;
                }
        } else {
                syslog(LOG_DEBUG,
                    "DefaultTargetPortState:psSetStmfProp:error(%d)", ret);
                goto done;
        }
done:
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                default:
                        ret = STMF_STATUS_ERROR;
                        break;
        }
        return (ret);
}

static int
loadStmfProp(int fd)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl = {0};
        stmf_set_props_t *stmf_set_props = NULL;

        stmf_set_props = (stmf_set_props_t *)
            calloc(1, (sizeof (stmf_set_props_t)));
        if (stmf_set_props == NULL) {
                ret = STMF_ERROR_NOMEM;
                goto done;
        }

        /* Loading the default property values from smf */

        if ((ret = setStmfProp(stmf_set_props)) != STMF_STATUS_SUCCESS)
                goto done;

        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (stmf_set_props_t);
        stmfIoctl.stmf_ibuf =
            (uint64_t)(unsigned long)stmf_set_props;

        ioctlRet = ioctl(fd, STMF_IOCTL_SET_STMF_PROPS,
            &stmfIoctl);

        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case ENOENT:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "setDefaultStmfState:"
                                    "ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }
done:
        if (stmf_set_props != NULL) {
                free(stmf_set_props);
        }
        return (ret);
}

int
stmfLoadStmfProps(void)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        /* open control node for stmf */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
            != STMF_STATUS_SUCCESS) {
                goto done;
        }
        ret = loadStmfProp(fd);

        (void) close(fd);
done:
        if (ret != STMF_STATUS_SUCCESS) {
                syslog(LOG_DEBUG,
                    "stmfLoadStmfProps:Failed");
        }
        return (ret);
}

/*
 * stmfOnline
 *
 * Purpose: Online stmf service
 *
 */
int
stmfOnline(void)
{
        int ret;
        int fd;
        stmfState state;
        stmf_state_desc_t iState;

        ret = stmfGetState(&state);
        if (ret == STMF_STATUS_SUCCESS) {
                if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
                        return (STMF_ERROR_SERVICE_ONLINE);
                }
        } else {
                return (STMF_STATUS_ERROR);
        }
        iState.state = STMF_STATE_ONLINE;
        iState.config_state = STMF_CONFIG_NONE;
        /*
         * Open control node for stmf
         * to make call to setStmfState()
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);
        ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
        (void) close(fd);
        return (ret);
}

/*
 * stmfOffline
 *
 * Purpose: Offline stmf service
 *
 */
int
stmfOffline(void)
{
        int ret;
        int fd;
        stmfState state;
        stmf_state_desc_t iState;

        ret = stmfGetState(&state);
        if (ret == STMF_STATUS_SUCCESS) {
                if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
                        return (STMF_ERROR_SERVICE_OFFLINE);
                }
        } else {
                return (STMF_STATUS_ERROR);
        }
        iState.state = STMF_STATE_OFFLINE;
        iState.config_state = STMF_CONFIG_NONE;

        /*
         * Open control node for stmf
         * to make call to setStmfState()
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);
        ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
        (void) close(fd);
        return (ret);
}


/*
 * stmfOfflineTarget
 *
 * Purpose: Change state of target to offline
 *
 * devid - devid of the target to offline
 */
int
stmfOfflineTarget(stmfDevid *devid)
{
        stmf_state_desc_t targetState;
        int ret = STMF_STATUS_SUCCESS;
        int fd;

        if (devid == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }
        bzero(&targetState, sizeof (targetState));

        targetState.state = STMF_STATE_OFFLINE;
        targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
        bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
            devid->identLength);
        /*
         * Open control node for stmf
         * to make call to setStmfState()
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);
        ret = setStmfState(fd, &targetState, TARGET_TYPE);
        (void) close(fd);
        return (ret);
}

/*
 * stmfOfflineLogicalUnit
 *
 * Purpose: Change state of logical unit to offline
 *
 * lu - guid of the logical unit to offline
 */
int
stmfOfflineLogicalUnit(stmfGuid *lu)
{
        stmf_state_desc_t luState;
        int ret = STMF_STATUS_SUCCESS;
        int fd;

        if (lu == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        bzero(&luState, sizeof (luState));

        luState.state = STMF_STATE_OFFLINE;
        bcopy(lu, &luState.ident, sizeof (stmfGuid));
        /*
         * Open control node for stmf
         * to make call to setStmfState()
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);
        ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
        (void) close(fd);
        return (ret);
}

/*
 * stmfOnlineTarget
 *
 * Purpose: Change state of target to online
 *
 * devid - devid of the target to online
 */
int
stmfOnlineTarget(stmfDevid *devid)
{
        stmf_state_desc_t targetState;
        int ret = STMF_STATUS_SUCCESS;
        int fd;

        if (devid == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }
        bzero(&targetState, sizeof (targetState));

        targetState.state = STMF_STATE_ONLINE;
        targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
        bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
            devid->identLength);
        /*
         * Open control node for stmf
         * to make call to setStmfState()
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);
        ret = setStmfState(fd, &targetState, TARGET_TYPE);
        (void) close(fd);
        return (ret);
}

/*
 * stmfOnlineLogicalUnit
 *
 * Purpose: Change state of logical unit to online
 *
 * lu - guid of the logical unit to online
 */
int
stmfOnlineLogicalUnit(stmfGuid *lu)
{
        stmf_state_desc_t luState;
        int ret = STMF_STATUS_SUCCESS;
        int fd;

        if (lu == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        bzero(&luState, sizeof (luState));

        luState.state = STMF_STATE_ONLINE;
        bcopy(lu, &luState.ident, sizeof (stmfGuid));
        /*
         * Open control node for stmf
         * to make call to setStmfState()
         */
        if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);
        ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
        (void) close(fd);
        return (ret);
}

/*
 * stmfRemoveFromHostGroup
 *
 * Purpose: Removes an initiator from an initiator group
 *
 * hostGroupName - name of an initiator group
 * hostName - name of host group member to remove
 */
int
stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
{
        int ret;
        int fd;

        if (hostGroupName == NULL ||
            (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
            == sizeof (stmfGroupName)) || hostName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY,
            hostGroupName, hostName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psRemoveHostGroupMember((char *)hostGroupName,
            (char *)hostName->ident);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_MEMBER_NOT_FOUND:
                        ret = STMF_ERROR_MEMBER_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_GROUP_NOT_FOUND:
                        ret = STMF_ERROR_GROUP_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfRemoveFromHostGroup"
                            "psRemoveHostGroupMember:error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfRemoveFromTargetGroup
 *
 * Purpose: Removes a local port from a local port group
 *
 * targetGroupName - name of a target group
 * targetName - name of target to remove
 */
int
stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
{
        int ret;
        int fd;

        if (targetGroupName == NULL ||
            (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
            == sizeof (stmfGroupName)) || targetName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY,
            targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psRemoveTargetGroupMember((char *)targetGroupName,
            (char *)targetName->ident);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_MEMBER_NOT_FOUND:
                        ret = STMF_ERROR_MEMBER_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_GROUP_NOT_FOUND:
                        ret = STMF_ERROR_GROUP_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfRemoveFromTargetGroup"
                            "psRemoveTargetGroupMember:error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfRemoveViewEntry
 *
 * Purpose: Removes a view entry from a logical unit
 *
 * lu - guid of lu for which view entry is being removed
 * viewEntryIndex - index of view entry to remove
 *
 */
int
stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;
        stmf_view_op_entry_t ioctlViewEntry;

        if (lu == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
        ioctlViewEntry.ve_ndx_valid = B_TRUE;
        ioctlViewEntry.ve_ndx = viewEntryIndex;
        bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to add to the view entry
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
        ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                                ret = STMF_ERROR_PERM;
                                break;
                        case EACCES:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
                                                ret = STMF_ERROR_CONFIG_NONE;
                                                break;
                                        default:
                                                ret = STMF_ERROR_PERM;
                                                break;
                                }
                                break;
                        case ENODEV:
                        case ENOENT:
                                ret = STMF_ERROR_NOT_FOUND;
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "stmfRemoveViewEntry:ioctl errno(%d)",
                                    errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        ret = psRemoveViewEntry(lu, viewEntryIndex);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_NOT_FOUND:
                        ret = STMF_ERROR_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)",
                            ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        (void) close(fd);
        return (ret);
}

/*
 * stmfSetProviderData
 *
 * Purpose: set the provider data
 *
 * providerName - unique name of provider
 * nvl - nvlist to set
 * providerType - type of provider for which to set data
 *              STMF_LU_PROVIDER_TYPE
 *              STMF_PORT_PROVIDER_TYPE
 */
int
stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType)
{
        return (stmfSetProviderDataProt(providerName, nvl, providerType,
            NULL));
}

/*
 * stmfSetProviderDataProt
 *
 * Purpose: set the provider data
 *
 * providerName - unique name of provider
 * nvl - nvlist to set
 * providerType - type of provider for which to set data
 *              STMF_LU_PROVIDER_TYPE
 *              STMF_PORT_PROVIDER_TYPE
 * setToken - Stale data token returned in the stmfGetProviderDataProt()
 *            call or NULL.
 */
int
stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
    uint64_t *setToken)
{
        int ret;
        int fd;

        if (providerName == NULL || nvl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        if (providerType != STMF_LU_PROVIDER_TYPE &&
            providerType != STMF_PORT_PROVIDER_TYPE) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        ret = setProviderData(fd, providerName, nvl, providerType, setToken);

        (void) close(fd);

        if (ret != STMF_STATUS_SUCCESS) {
                goto done;
        }

        if (iGetPersistMethod() == STMF_PERSIST_NONE) {
                goto done;
        }

        /* setting driver provider data successful. Now persist it */
        ret = psSetProviderData(providerName, nvl, providerType, NULL);
        switch (ret) {
                case STMF_PS_SUCCESS:
                        ret = STMF_STATUS_SUCCESS;
                        break;
                case STMF_PS_ERROR_EXISTS:
                        ret = STMF_ERROR_EXISTS;
                        break;
                case STMF_PS_ERROR_BUSY:
                        ret = STMF_ERROR_BUSY;
                        break;
                case STMF_PS_ERROR_SERVICE_NOT_FOUND:
                        ret = STMF_ERROR_SERVICE_NOT_FOUND;
                        break;
                case STMF_PS_ERROR_VERSION_MISMATCH:
                        ret = STMF_ERROR_SERVICE_DATA_VERSION;
                        break;
                case STMF_PS_ERROR_PROV_DATA_STALE:
                        ret = STMF_ERROR_PROV_DATA_STALE;
                        break;
                default:
                        syslog(LOG_DEBUG,
                            "stmfSetProviderData"
                            "psSetProviderData:error(%d)", ret);
                        ret = STMF_STATUS_ERROR;
                        break;
        }

done:
        return (ret);
}

/*
 * getProviderData
 *
 * Purpose: set the provider data from stmf
 *
 * providerName - unique name of provider
 * nvl - nvlist to load/retrieve
 * providerType - logical unit or port provider
 * setToken - returned stale data token
 */
int
getProviderData(char *providerName, nvlist_t **nvl, int providerType,
    uint64_t *setToken)
{
        int ret = STMF_STATUS_SUCCESS;
        int fd;
        int ioctlRet;
        size_t nvlistSize = ALLOC_PP_DATA_SIZE;
        int retryCnt = 0;
        int retryCntMax = MAX_PROVIDER_RETRY;
        stmf_ppioctl_data_t ppi = {0}, *ppi_out = NULL;
        boolean_t retry = B_TRUE;
        stmf_iocdata_t stmfIoctl;

        if (providerName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /* set provider name and provider type */
        if (strlcpy(ppi.ppi_name, providerName,
            sizeof (ppi.ppi_name)) >=
            sizeof (ppi.ppi_name)) {
                ret = STMF_ERROR_INVALID_ARG;
                goto done;
        }
        switch (providerType) {
                case STMF_LU_PROVIDER_TYPE:
                        ppi.ppi_lu_provider = 1;
                        break;
                case STMF_PORT_PROVIDER_TYPE:
                        ppi.ppi_port_provider = 1;
                        break;
                default:
                        ret = STMF_ERROR_INVALID_ARG;
                        goto done;
        }

        do {
                /* allocate memory for ioctl */
                ppi_out = (stmf_ppioctl_data_t *)calloc(1, nvlistSize +
                    sizeof (stmf_ppioctl_data_t));
                if (ppi_out == NULL) {
                        ret = STMF_ERROR_NOMEM;
                        goto done;

                }

                /* set the size of the ioctl data to allocated buffer */
                ppi.ppi_data_size = nvlistSize;

                bzero(&stmfIoctl, sizeof (stmfIoctl));

                stmfIoctl.stmf_version = STMF_VERSION_1;
                stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
                stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
                stmfIoctl.stmf_obuf_size = sizeof (stmf_ppioctl_data_t) +
                    nvlistSize;
                stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)ppi_out;
                ioctlRet = ioctl(fd, STMF_IOCTL_GET_PP_DATA, &stmfIoctl);
                if (ioctlRet != 0) {
                        switch (errno) {
                                case EBUSY:
                                        ret = STMF_ERROR_BUSY;
                                        break;
                                case EPERM:
                                case EACCES:
                                        ret = STMF_ERROR_PERM;
                                        break;
                                case EINVAL:
                                        if (stmfIoctl.stmf_error ==
                                            STMF_IOCERR_INSUFFICIENT_BUF) {
                                                nvlistSize =
                                                    ppi_out->ppi_data_size;
                                                free(ppi_out);
                                                ppi_out = NULL;
                                                if (retryCnt++ > retryCntMax) {
                                                        retry = B_FALSE;
                                                        ret = STMF_ERROR_BUSY;
                                                } else {
                                                        ret =
                                                            STMF_STATUS_SUCCESS;
                                                }
                                        } else {
                                                syslog(LOG_DEBUG,
                                                    "getProviderData:ioctl"
                                                    "unable to retrieve "
                                                    "nvlist");
                                                ret = STMF_STATUS_ERROR;
                                        }
                                        break;
                                case ENOENT:
                                        ret = STMF_ERROR_NOT_FOUND;
                                        break;
                                default:
                                        syslog(LOG_DEBUG,
                                            "getProviderData:ioctl errno(%d)",
                                            errno);
                                        ret = STMF_STATUS_ERROR;
                                        break;
                        }
                        if (ret != STMF_STATUS_SUCCESS)
                                goto done;
                }
        } while (retry && stmfIoctl.stmf_error == STMF_IOCERR_INSUFFICIENT_BUF);

        if ((ret = nvlist_unpack((char *)ppi_out->ppi_data,
            ppi_out->ppi_data_size, nvl, 0)) != 0) {
                ret = STMF_STATUS_ERROR;
                goto done;
        }

        /* caller has asked for new token */
        if (setToken) {
                *setToken = ppi_out->ppi_token;
        }
done:
        free(ppi_out);
        (void) close(fd);
        return (ret);
}

/*
 * setProviderData
 *
 * Purpose: set the provider data in stmf
 *
 * providerName - unique name of provider
 * nvl - nvlist to set
 * providerType - logical unit or port provider
 * setToken - stale data token to check if not NULL
 */
static int
setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType,
    uint64_t *setToken)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        size_t nvlistEncodedSize;
        stmf_ppioctl_data_t *ppi = NULL;
        uint64_t outToken;
        char *allocatedNvBuffer;
        stmf_iocdata_t stmfIoctl;

        if (providerName == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* get size of encoded nvlist */
        if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) {
                return (STMF_STATUS_ERROR);
        }

        /* allocate memory for ioctl */
        ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize +
            sizeof (stmf_ppioctl_data_t));
        if (ppi == NULL) {
                return (STMF_ERROR_NOMEM);
        }

        if (setToken) {
                ppi->ppi_token_valid = 1;
                ppi->ppi_token = *setToken;
        }

        allocatedNvBuffer = (char *)&ppi->ppi_data;
        if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
            NV_ENCODE_XDR, 0) != 0) {
                return (STMF_STATUS_ERROR);
        }

        /* set provider name and provider type */
        (void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name));
        switch (providerType) {
                case STMF_LU_PROVIDER_TYPE:
                        ppi->ppi_lu_provider = 1;
                        break;
                case STMF_PORT_PROVIDER_TYPE:
                        ppi->ppi_port_provider = 1;
                        break;
                default:
                        return (STMF_ERROR_INVALID_ARG);
        }

        /* set the size of the ioctl data to packed data size */
        ppi->ppi_data_size = nvlistEncodedSize;

        bzero(&stmfIoctl, sizeof (stmfIoctl));

        stmfIoctl.stmf_version = STMF_VERSION_1;
        /*
         * Subtracting 8 from the size as that is the size of the last member
         * of the structure where the packed data resides
         */
        stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
            sizeof (stmf_ppioctl_data_t) - 8;
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
        stmfIoctl.stmf_obuf_size = sizeof (uint64_t);
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&outToken;
        ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case EINVAL:
                                if (stmfIoctl.stmf_error ==
                                    STMF_IOCERR_PPD_UPDATED) {
                                        ret = STMF_ERROR_PROV_DATA_STALE;
                                } else {
                                        ret = STMF_STATUS_ERROR;
                                }
                                break;
                        default:
                                syslog(LOG_DEBUG,
                                    "setProviderData:ioctl errno(%d)", errno);
                                ret = STMF_STATUS_ERROR;
                                break;
                }
                if (ret != STMF_STATUS_SUCCESS)
                        goto done;
        }

        /* caller has asked for new token */
        if (setToken) {
                *setToken = outToken;
        }
done:
        free(ppi);
        return (ret);
}

/*
 * set the persistence method in the library only or library and service
 */
int
stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet)
{
        int ret = STMF_STATUS_SUCCESS;
        int oldPersist;

        (void) pthread_mutex_lock(&persistenceTypeLock);
        oldPersist = iPersistType;
        if (persistType == STMF_PERSIST_NONE ||
            persistType == STMF_PERSIST_SMF) {
                iLibSetPersist = B_TRUE;
                iPersistType = persistType;
        } else {
                (void) pthread_mutex_unlock(&persistenceTypeLock);
                return (STMF_ERROR_INVALID_ARG);
        }
        /* Is this for this library open or in SMF */
        if (serviceSet == B_TRUE) {
                ret = psSetServicePersist(persistType);
                if (ret != STMF_PS_SUCCESS) {
                        ret = STMF_ERROR_PERSIST_TYPE;
                        /* Set to old value */
                        iPersistType = oldPersist;
                }
        }
        (void) pthread_mutex_unlock(&persistenceTypeLock);

        return (ret);
}

/*
 * Only returns internal state for persist. If unset, goes to ps. If that
 * fails, returns default setting
 */
static uint8_t
iGetPersistMethod()
{

        uint8_t persistType = 0;

        (void) pthread_mutex_lock(&persistenceTypeLock);
        if (iLibSetPersist) {
                persistType = iPersistType;
        } else {
                int ret;
                ret = psGetServicePersist(&persistType);
                if (ret != STMF_PS_SUCCESS) {
                        /* set to default */
                        persistType = STMF_DEFAULT_PERSIST;
                }
        }
        (void) pthread_mutex_unlock(&persistenceTypeLock);
        return (persistType);
}

/*
 * Returns either library state or persistent config state depending on
 * serviceState
 */
int
stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState)
{
        int ret = STMF_STATUS_SUCCESS;

        if (persistType == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }
        if (serviceState) {
                ret = psGetServicePersist(persistType);
                if (ret != STMF_PS_SUCCESS) {
                        ret = STMF_ERROR_PERSIST_TYPE;
                }
        } else {
                (void) pthread_mutex_lock(&persistenceTypeLock);
                if (iLibSetPersist) {
                        *persistType = iPersistType;
                } else {
                        *persistType = STMF_DEFAULT_PERSIST;
                }
                (void) pthread_mutex_unlock(&persistenceTypeLock);
        }

        return (ret);
}

/*
 * stmfPostProxyMsg
 *
 * Purpose: Post a message to the proxy port provider
 *
 * buf - buffer containing message to post
 * buflen - buffer length
 */
int
stmfPostProxyMsg(int hdl, void *buf, uint32_t buflen)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        pppt_iocdata_t ppptIoctl = {0};

        if (buf == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /*
         * Issue ioctl to post the message
         */
        ppptIoctl.pppt_version = PPPT_VERSION_1;
        ppptIoctl.pppt_buf_size = buflen;
        ppptIoctl.pppt_buf = (uint64_t)(unsigned long)buf;
        ioctlRet = ioctl(hdl, PPPT_MESSAGE, &ppptIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        default:
                                ret = STMF_ERROR_POST_MSG_FAILED;
                                break;
                }
        }

        return (ret);
}

/*
 * stmfInitProxyDoor
 *
 * Purpose: Install door in proxy
 *
 * hdl - pointer to returned handle
 * fd - door from door_create()
 */
int
stmfInitProxyDoor(int *hdl, int door)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        int fd;
        pppt_iocdata_t ppptIoctl = {0};

        if (hdl == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /*
         * Open control node for pppt
         */
        if ((ret = openPppt(OPEN_PPPT, &fd)) != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Issue ioctl to install the door
         */
        ppptIoctl.pppt_version = PPPT_VERSION_1;
        ppptIoctl.pppt_door_fd = (uint32_t)door;
        ioctlRet = ioctl(fd, PPPT_INSTALL_DOOR, &ppptIoctl);
        if (ioctlRet != 0) {
                switch (errno) {
                        case EPERM:
                        case EACCES:
                                ret = STMF_ERROR_PERM;
                                break;
                        case EINVAL:
                                ret = STMF_ERROR_INVALID_ARG;
                                break;
                        case EBUSY:
                                ret = STMF_ERROR_DOOR_INSTALLED;
                                break;
                        default:
                                ret = STMF_STATUS_ERROR;
                                break;
                }
        }

        /* return driver fd to caller */
        *hdl = fd;
        return (ret);
}

void
stmfDestroyProxyDoor(int hdl)
{
        (void) close(hdl);
}

/*
 * validateLunNumIoctl
 *
 * Purpose: Issues ioctl to check and get available lun# in view entry
 *
 * viewEntry - view entry to use
 */
static int
validateLunNumIoctl(int fd, stmfViewEntry *viewEntry)
{
        int ret = STMF_STATUS_SUCCESS;
        int ioctlRet;
        stmf_iocdata_t stmfIoctl;
        stmf_view_op_entry_t ioctlViewEntry;

        bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
        /*
         * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
         * false on input
         */
        ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
        ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
        ioctlViewEntry.ve_all_targets = viewEntry->allTargets;

        if (viewEntry->allHosts == B_FALSE) {
                bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
                    sizeof (stmfGroupName));
                ioctlViewEntry.ve_host_group.name_size =
                    strlen((char *)viewEntry->hostGroup);
        }
        if (viewEntry->allTargets == B_FALSE) {
                bcopy(viewEntry->targetGroup,
                    &ioctlViewEntry.ve_target_group.name,
                    sizeof (stmfGroupName));
                ioctlViewEntry.ve_target_group.name_size =
                    strlen((char *)viewEntry->targetGroup);
        }
        /* Validating the lun number */
        if (viewEntry->luNbrValid) {
                bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
                    sizeof (ioctlViewEntry.ve_lu_nbr));
        }

        bzero(&stmfIoctl, sizeof (stmfIoctl));
        /*
         * Issue ioctl to validate lun# in the view entry
         */
        stmfIoctl.stmf_version = STMF_VERSION_1;
        stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
        stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
        stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
        stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
        ioctlRet = ioctl(fd, STMF_IOCTL_VALIDATE_VIEW, &stmfIoctl);

        /* save available lun number */
        if (!viewEntry->luNbrValid) {
                bcopy(ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
                    sizeof (ioctlViewEntry.ve_lu_nbr));
        }
        if (ioctlRet != 0) {
                switch (errno) {
                        case EBUSY:
                                ret = STMF_ERROR_BUSY;
                                break;
                        case EPERM:
                                ret = STMF_ERROR_PERM;
                                break;
                        case EACCES:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
                                                ret = STMF_ERROR_CONFIG_NONE;
                                                break;
                                        default:
                                                ret = STMF_ERROR_PERM;
                                                break;
                                }
                                break;
                        default:
                                switch (stmfIoctl.stmf_error) {
                                        case STMF_IOCERR_LU_NUMBER_IN_USE:
                                                ret = STMF_ERROR_LUN_IN_USE;
                                                break;
                                        case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
                                                ret = STMF_ERROR_VE_CONFLICT;
                                                break;
                                        case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
                                                ret = STMF_ERROR_CONFIG_NONE;
                                                break;
                                        case STMF_IOCERR_INVALID_HG:
                                                ret = STMF_ERROR_INVALID_HG;
                                                break;
                                        case STMF_IOCERR_INVALID_TG:
                                                ret = STMF_ERROR_INVALID_TG;
                                                break;
                                        default:
                                                syslog(LOG_DEBUG,
                                                    "addViewEntryIoctl"
                                                    ":error(%d)",
                                                    stmfIoctl.stmf_error);
                                                ret = STMF_STATUS_ERROR;
                                                break;
                                }
                                break;
                }
        }
        return (ret);
}

/*
 * stmfValidateView
 *
 * Purpose: Validate or get lun # base on TG, HG of view entry
 *
 * viewEntry - view entry structure to use
 */
int
stmfValidateView(stmfViewEntry *viewEntry)
{
        int ret;
        int fd;
        stmfViewEntry iViewEntry;

        if (viewEntry == NULL) {
                return (STMF_ERROR_INVALID_ARG);
        }

        /* initialize and set internal view entry */
        bzero(&iViewEntry, sizeof (iViewEntry));

        if (!viewEntry->allHosts) {
                bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
                    sizeof (iViewEntry.hostGroup));
        } else {
                iViewEntry.allHosts = B_TRUE;
        }

        if (!viewEntry->allTargets) {
                bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
                    sizeof (iViewEntry.targetGroup));
        } else {
                iViewEntry.allTargets = B_TRUE;
        }

        if (viewEntry->luNbrValid) {
                iViewEntry.luNbrValid = B_TRUE;
                bcopy(viewEntry->luNbr, iViewEntry.luNbr,
                    sizeof (iViewEntry.luNbr));
        }

        /*
         * set users return view entry index valid flag to false
         * in case of failure
         */
        viewEntry->veIndexValid = B_FALSE;

        /* Check to ensure service exists */
        if (psCheckService() != STMF_STATUS_SUCCESS) {
                return (STMF_ERROR_SERVICE_NOT_FOUND);
        }

        /* call init */
        ret = initializeConfig();
        if (ret != STMF_STATUS_SUCCESS) {
                return (ret);
        }

        /*
         * Open control node for stmf
         */
        if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
                return (ret);

        /*
         * Validate lun# in the view entry from the driver
         */
        ret = validateLunNumIoctl(fd, &iViewEntry);
        (void) close(fd);

        /* save available lun number */
        if (!viewEntry->luNbrValid) {
                bcopy(iViewEntry.luNbr, viewEntry->luNbr,
                    sizeof (iViewEntry.luNbr));
        }

        return (ret);
}