diff options
Diffstat (limited to 'usr/src/lib/libstmf/common/stmf.c')
-rw-r--r-- | usr/src/lib/libstmf/common/stmf.c | 3376 |
1 files changed, 3376 insertions, 0 deletions
diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c new file mode 100644 index 0000000000..08a457c78c --- /dev/null +++ b/usr/src/lib/libstmf/common/stmf.c @@ -0,0 +1,3376 @@ +/* + * 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 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#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 <sys/stmf_ioctl.h> + +#define STMF_PATH "/devices/pseudo/stmf@0:admin" + +#define EUI "eui." +#define WWN "wwn." +#define IQN "iqn." +#define WWN_ASCII_SIZE 16 +#define IDENT_LENGTH_BYTE 3 + +#define MAX_LU 2<<16 - 1 +#define MAX_TARGET_PORT 1024 +#define MAX_PROVIDER 1024 +#define MAX_GROUP 1024 +#define MAX_SESSION 1024 +#define MAX_ISCSI_NAME 223 + +#define OPEN_STMF 0 +#define OPEN_EXCL_STMF O_EXCL + +#define LOGICAL_UNIT_TYPE 0 +#define TARGET_TYPE 1 +#define STMF_SERVICE_TYPE 2 + +static int openStmf(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); + +/* + * 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 { + ret = STMF_STATUS_ERROR; + } + syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)", + STMF_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 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; + } + } +done: + return (ret); +} + +/* + * groupIoctl + * + * 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: + ret = STMF_ERROR_BUSY; + break; + 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; + } + } +done: + return (ret); +} + +/* + * 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; + } + + 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; + stmfState state; + + if (targetGroupName == NULL || + (strnlen((char *)targetGroupName, sizeof (stmfGroupName)) + == sizeof (stmfGroupName)) || targetName == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + 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); + } + + /* 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; + } + + 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 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 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 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; + } + } + + 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; + } + + 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); +} + +/* + * 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 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 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 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, 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); +} + +/* + * 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; + + if (hostGroupList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetHostGroupList(hostGroupList); + 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); +} + +/* + * 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 = psGetHostGroupMemberList((char *)groupName, groupProp); + 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, + "stmfGetHostGroupMembers:psGetHostGroupMembers" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + 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); + } + + ret = psGetProviderData(providerName, nvl, providerType, setToken); + 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; + 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, + "stmfGetProviderData:psGetProviderData:error(%d)", + ret); + ret = STMF_STATUS_ERROR; + break; + } + + return (ret); +} + +/* + * 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; + 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 = MAX_SESSION; + fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t)); + fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize); + if (fSessionList == NULL) { + return (STMF_ERROR_NOMEM); + } + + 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 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 > MAX_SESSION) { + fSessionListSize = stmfIoctl.stmf_obuf_max_nentries * + sizeof (slist_scsi_session_t); + fSessionList = realloc(fSessionList, fSessionListSize); + if (fSessionList == NULL) { + return (STMF_ERROR_NOMEM); + } + 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 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); + 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 = psGetTargetGroupList(targetGroupList); + 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, + "stmfGetTargetGroupList:psGetTargetGroupList:" + "error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + 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 = psGetTargetGroupMemberList((char *)groupName, groupProp); + 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, + "stmfGetTargetGroupMembers:psGetTargetGroupMembers:" + "error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + 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; + 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 = MAX_TARGET_PORT * sizeof (slist_target_port_t); + fTargetList = (slist_target_port_t *)calloc(1, fTargetListSize); + if (fTargetList == NULL) { + goto done; + } + + bzero(&stmfIoctl, sizeof (stmfIoctl)); + /* + * Issue ioctl to add to the host group + */ + 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 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 > MAX_TARGET_PORT) { + fTargetListSize = stmfIoctl.stmf_obuf_max_nentries * + sizeof (slist_lu_t); + fTargetList = realloc(fTargetList, fTargetListSize); + if (fTargetList == NULL) { + return (STMF_ERROR_NOMEM); + } + 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 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)); + + (*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(fTargetList); + 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; + + 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 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)); +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, k; + stmf_iocdata_t stmfIoctl; + /* framework lu list */ + slist_lu_t *fLuList; + /* persistent store lu list */ + stmfGuidList *sLuList = NULL; + int finalListSize = 0; + int newAllocSize; + uint32_t fLuListSize; + uint32_t endList; + + 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 = MAX_LU; + fLuListSize = fLuListSize * (sizeof (slist_lu_t)); + fLuList = (slist_lu_t *)calloc(1, fLuListSize); + if (fLuList == NULL) { + return (STMF_ERROR_NOMEM); + } + + 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 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 > MAX_LU) { + fLuListSize = stmfIoctl.stmf_obuf_max_nentries * + sizeof (slist_lu_t); + fLuList = realloc(fLuList, fLuListSize); + if (fLuList == NULL) { + return (STMF_ERROR_NOMEM); + } + 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 EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "stmfGetLogicalUnitList:" + "ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + goto done; + } + } + + ret = psGetLogicalUnitList(&sLuList); + 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, + "stmfGetLogicalUnitList:psGetLogicalUnitList" + ":error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + /* + * 2 lists must be merged + * reallocate the store list to add the list from the + * framework + */ + newAllocSize = sLuList->cnt * sizeof (stmfGuid) + sizeof (stmfGuidList) + + stmfIoctl.stmf_obuf_nentries * sizeof (stmfGuid); + + sLuList = realloc(sLuList, newAllocSize); + if (sLuList == NULL) { + ret = STMF_ERROR_NOMEM; + goto done; + } + + /* + * add list from ioctl. Start from end of list retrieved from store. + */ + endList = sLuList->cnt + stmfIoctl.stmf_obuf_nentries; + for (k = 0, i = sLuList->cnt; i < endList; i++, k++) { + bcopy(&fLuList[k].lu_guid, sLuList->guid[i].guid, + sizeof (stmfGuid)); + } + sLuList->cnt = endList; + + /* + * sort the list for merging + */ + qsort((void *)&(sLuList->guid[0]), sLuList->cnt, + sizeof (stmfGuid), guidCompare); + + /* + * get final list count + */ + for (i = 0; i < sLuList->cnt; i++) { + if ((i + 1) <= sLuList->cnt) { + if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid, + sizeof (stmfGuid)) == 0) { + continue; + } + } + finalListSize++; + } + + /* + * allocate caller's buffer with the final size + */ + *luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) + + finalListSize * sizeof (stmfGuid)); + if (*luList == NULL) { + ret = STMF_ERROR_NOMEM; + goto done; + } + + /* + * copy guids to caller's buffer + */ + for (k = 0, i = 0; i < sLuList->cnt; i++) { + if ((i + 1) <= sLuList->cnt) { + if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid, + sizeof (stmfGuid)) == 0) { + continue; + } + } + bcopy(&(sLuList->guid[i].guid), (*luList)->guid[k++].guid, + sizeof (stmfGuid)); + } + + (*luList)->cnt = finalListSize; + +done: + (void) close(fd); + /* + * free internal buffers + */ + free(fLuList); + free(sLuList); + 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 (luProps == NULL || luProps == NULL) { + ret = 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 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; + + if (lu == NULL || viewEntryList == NULL) { + return (STMF_ERROR_INVALID_ARG); + } + + ret = psGetViewEntryList(lu, 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: + syslog(LOG_DEBUG, + "stmfGetViewEntryList:error(%d)", ret); + ret = STMF_STATUS_ERROR; + break; + } + + 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 = stmfGetHostGroupMembers(&(groupList->name[i]), + &groupProps); + 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 = stmfGetTargetGroupMembers(&(groupList->name[i]), + &groupProps); + 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 = stmfGetHostGroupList(&groupList); + 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 = stmfGetTargetGroupList(&groupList); + 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); + 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); +} + +/* + * stmfLoadConfig + * + * Purpose - load the configuration data from smf into stmf + * + */ +int +stmfLoadConfig(void) +{ + int ret; + int fd; + stmf_state_desc_t stmfStateSet; + stmfState state; + + + /* 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 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); +} + +/* + * 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; + } + + 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; + } + + 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 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; + } + + 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); + + (void) close(fd); + + if (ret != STMF_STATUS_SUCCESS) { + goto done; + } + + /* setting driver provider data successful. Now persist it */ + ret = psSetProviderData(providerName, nvl, providerType, setToken); + 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); +} + +/* + * setProviderData + * + * Purpose: set the provider data + * + * providerName - unique name of provider + * nvl - nvlist to set + * providerType - logical unit or port provider + */ +static int +setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType) +{ + int ret = STMF_STATUS_SUCCESS; + int ioctlRet; + size_t nvlistEncodedSize; + stmf_ppioctl_data_t *ppi = NULL; + 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); + } + + 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; + ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl); + if (ioctlRet != 0) { + switch (errno) { + case EBUSY: + ret = STMF_ERROR_BUSY; + break; + case EACCES: + ret = STMF_ERROR_PERM; + break; + default: + syslog(LOG_DEBUG, + "setProviderData:ioctl errno(%d)", errno); + ret = STMF_STATUS_ERROR; + break; + } + if (ret != STMF_STATUS_SUCCESS) + goto done; + } + +done: + free(ppi); + return (ret); +} |