summaryrefslogtreecommitdiff
path: root/usr/src/lib/libstmf/common/stmf.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-15 14:28:09 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-15 14:28:09 +0400
commit4b587d510fc5e6d58d4b87327224bfe4e8b81c0a (patch)
tree90e40f900bb25680ef56597d4f8d4be04c17de23 /usr/src/lib/libstmf/common/stmf.c
downloadstmf-4b587d510fc5e6d58d4b87327224bfe4e8b81c0a.tar.gz
Initial illumos sourcesillumos
Diffstat (limited to 'usr/src/lib/libstmf/common/stmf.c')
-rw-r--r--usr/src/lib/libstmf/common/stmf.c6949
1 files changed, 6949 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 0000000..e12c189
--- /dev/null
+++ b/usr/src/lib/libstmf/common/stmf.c
@@ -0,0 +1,6949 @@
+/*
+ * 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;
+ }
+ }
+done:
+ 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;
+ }
+ }
+done:
+ 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, 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);
+}