summaryrefslogtreecommitdiff
path: root/usr/src/lib/libstmf/common
diff options
context:
space:
mode:
authorJohn Forte <John.Forte@Sun.COM>2008-10-14 15:09:13 -0700
committerJohn Forte <John.Forte@Sun.COM>2008-10-14 15:09:13 -0700
commitfcf3ce441efd61da9bb2884968af01cb7c1452cc (patch)
tree0e80d59ad41702571586195bf099ccc14222ce02 /usr/src/lib/libstmf/common
parent247b82a1f1cb5ebd2d163bd9afdb1a3065611962 (diff)
downloadillumos-joyent-fcf3ce441efd61da9bb2884968af01cb7c1452cc.tar.gz
6745433 Merge NWS consolidation into OS/Net consolidation
Diffstat (limited to 'usr/src/lib/libstmf/common')
-rw-r--r--usr/src/lib/libstmf/common/libstmf.h300
-rw-r--r--usr/src/lib/libstmf/common/llib-lstmf30
-rw-r--r--usr/src/lib/libstmf/common/mapfile-vers72
-rw-r--r--usr/src/lib/libstmf/common/stmf.c3376
-rw-r--r--usr/src/lib/libstmf/common/store.c4747
-rw-r--r--usr/src/lib/libstmf/common/store.h81
6 files changed, 8606 insertions, 0 deletions
diff --git a/usr/src/lib/libstmf/common/libstmf.h b/usr/src/lib/libstmf/common/libstmf.h
new file mode 100644
index 0000000000..99d27a705b
--- /dev/null
+++ b/usr/src/lib/libstmf/common/libstmf.h
@@ -0,0 +1,300 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSTMF_H
+#define _LIBSTMF_H
+
+#include <time.h>
+#include <sys/param.h>
+#include <libnvpair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Constants and Types */
+
+/* LU and Local Port states */
+#define STMF_LOGICAL_UNIT_OFFLINE 0
+#define STMF_LOGICAL_UNIT_OFFLINING 1
+#define STMF_LOGICAL_UNIT_ONLINE 2
+#define STMF_LOGICAL_UNIT_ONLINING 3
+#define STMF_LOGICAL_UNIT_UNREGISTERED 4
+#define STMF_TARGET_PORT_OFFLINE 5
+#define STMF_TARGET_PORT_OFFLINING 6
+#define STMF_TARGET_PORT_ONLINE 7
+#define STMF_TARGET_PORT_ONLINING 8
+#define STMF_SERVICE_STATE_ONLINE 9
+#define STMF_SERVICE_STATE_OFFLINE 10
+#define STMF_SERVICE_STATE_ONLINING 11
+#define STMF_SERVICE_STATE_OFFLINING 12
+#define STMF_SERVICE_STATE_UNKNOWN 13
+#define STMF_CONFIG_STATE_NONE 14
+#define STMF_CONFIG_STATE_INIT 15
+#define STMF_CONFIG_STATE_INIT_DONE 16
+#define STMF_CONFIG_STATE_UNKNOWN 17
+
+#define STMF_IDENT_LENGTH 255
+
+/* API status return values */
+#define STMF_STATUS_SUCCESS 0x0000
+#define STMF_STATUS_ERROR 0x8000
+#define STMF_ERROR_BUSY (STMF_STATUS_ERROR | 0x01)
+#define STMF_ERROR_NOT_FOUND (STMF_STATUS_ERROR | 0x02)
+#define STMF_ERROR_MEMBER_NOT_FOUND (STMF_STATUS_ERROR | 0x03)
+#define STMF_ERROR_GROUP_NOT_FOUND (STMF_STATUS_ERROR | 0x04)
+#define STMF_ERROR_PERM (STMF_STATUS_ERROR | 0x05)
+#define STMF_ERROR_NOMEM (STMF_STATUS_ERROR | 0x06)
+#define STMF_ERROR_INVALID_ARG (STMF_STATUS_ERROR | 0x07)
+#define STMF_ERROR_EXISTS (STMF_STATUS_ERROR | 0x08)
+#define STMF_ERROR_SERVICE_NOT_FOUND (STMF_STATUS_ERROR | 0x09)
+#define STMF_ERROR_SERVICE_ONLINE (STMF_STATUS_ERROR | 0x0a)
+#define STMF_ERROR_SERVICE_OFFLINE (STMF_STATUS_ERROR | 0x0b)
+#define STMF_ERROR_GROUP_IN_USE (STMF_STATUS_ERROR | 0x0c)
+#define STMF_ERROR_LUN_IN_USE (STMF_STATUS_ERROR | 0x0d)
+#define STMF_ERROR_VE_CONFLICT (STMF_STATUS_ERROR | 0x0e)
+#define STMF_ERROR_CONFIG_NONE (STMF_STATUS_ERROR | 0x0f)
+#define STMF_ERROR_SERVICE_DATA_VERSION (STMF_STATUS_ERROR | 0x10)
+#define STMF_ERROR_INVALID_HG (STMF_STATUS_ERROR | 0x11)
+#define STMF_ERROR_INVALID_TG (STMF_STATUS_ERROR | 0x12)
+#define STMF_ERROR_PROV_DATA_STALE (STMF_STATUS_ERROR | 0x13)
+
+/* Initiator Name Types */
+#define STMF_FC_PORT_WWN 1
+#define STMF_ISCSI_NAME 2
+
+/* protected data flag for provider store */
+#define STMF_PROTECTED_DATA 0x0001
+
+/* provider types */
+#define STMF_LU_PROVIDER_TYPE 1
+#define STMF_PORT_PROVIDER_TYPE 2
+
+
+/* devid code set and name types */
+#define EUI_64_TYPE 2
+#define NAA_TYPE 3
+#define SCSI_NAME_TYPE 8
+
+#define BINARY_CODE_SET 1
+#define ASCII_CODE_SET 2
+#define UTF_8_CODE_SET 3
+
+typedef enum _stmfProtocol
+{
+ STMF_PROTOCOL_FIBRE_CHANNEL = 0,
+ STMF_PROTOCOL_ISCSI = 1,
+ STMF_PROTOCOL_SAS = 2
+} stmfProtocol;
+
+
+typedef struct _stmfGuid
+{
+ uchar_t guid[16];
+} stmfGuid;
+
+typedef struct _stmfGuidList
+{
+ uint32_t cnt;
+ stmfGuid guid[1];
+} stmfGuidList;
+
+typedef struct _stmfState
+{
+ int operationalState;
+ int configState;
+} stmfState;
+
+typedef struct _stmfDevid
+{
+ uint8_t identLength; /* length of ident */
+ uint8_t ident[STMF_IDENT_LENGTH]; /* SCSI name string ident */
+} stmfDevid;
+
+typedef struct _stmfDevidList
+{
+ uint32_t cnt;
+ stmfDevid devid[1];
+} stmfDevidList;
+
+typedef char stmfGroupName[256];
+typedef char stmfProviderName[256];
+
+typedef struct _stmfGroupList
+{
+ uint32_t cnt;
+ stmfGroupName name[1];
+} stmfGroupList;
+
+typedef struct _stmfProvider
+{
+ int providerType;
+ stmfProviderName name;
+} stmfProvider;
+
+typedef struct _stmfProviderList
+{
+ uint32_t cnt;
+ stmfProvider provider[1];
+} stmfProviderList;
+
+typedef struct _stmfSession
+{
+ stmfDevid initiator;
+ char alias[256];
+ time_t creationTime;
+} stmfSession;
+
+typedef struct _stmfSessionList
+{
+ uint32_t cnt;
+ stmfSession session[1];
+} stmfSessionList;
+
+
+typedef struct _stmfViewEntry
+{
+ boolean_t veIndexValid; /* if B_TRUE, veIndex is valid value */
+ uint32_t veIndex; /* View Entry index */
+ boolean_t allHosts; /* all initiator ports */
+ stmfGroupName hostGroup; /* Host Group Name */
+ boolean_t allTargets; /* B_TRUE = targetGroup is invalid */
+ stmfGroupName targetGroup; /* Target Group Name */
+ boolean_t luNbrValid; /* if B_TRUE, luNbr is a valid value */
+ uchar_t luNbr[8]; /* LU number for this view entry */
+} stmfViewEntry;
+
+typedef struct _stmfViewEntryList
+{
+ uint32_t cnt;
+ stmfViewEntry ve[1];
+} stmfViewEntryList;
+
+typedef struct _stmfViewEntryProperties
+{
+ stmfGuid associatedLogicalUnitGuid;
+ stmfViewEntry viewEntry;
+} stmfViewEntryProperties;
+
+typedef struct _stmfGroupProperties
+{
+ uint32_t cnt;
+ stmfDevid name[1];
+} stmfGroupProperties;
+
+typedef struct _stmfTargetProperties
+{
+ stmfProviderName providerName;
+ char alias[256];
+ uint16_t status;
+ stmfProtocol protocol;
+ stmfDevid devid;
+} stmfTargetProperties;
+
+typedef struct _stmfLogicalUnitProperties
+{
+ char alias[256];
+ uchar_t vendor[8];
+ uchar_t product[16];
+ uchar_t revision[4];
+ uint32_t status;
+ char providerName[256];
+ stmfGuid luid;
+} stmfLogicalUnitProperties;
+
+typedef struct _stmfLogicalUnitProviderProperties
+{
+ char providerName[MAXPATHLEN];
+ uint32_t instance;
+ uint32_t status;
+ uchar_t rsvd[64];
+} stmfLogicalUnitProviderProperties;
+
+typedef struct _stmfLocalPortProviderProperties
+{
+ char providerName[MAXPATHLEN];
+ uint32_t instance;
+ uint32_t status;
+ uchar_t rsvd[64];
+} stmfLocalPortProviderProperties;
+
+
+/* API prototypes */
+int stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *name);
+int stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName);
+int stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry);
+int stmfClearProviderData(char *providerName, int providerType);
+int stmfCreateHostGroup(stmfGroupName *hostGroupName);
+int stmfCreateTargetGroup(stmfGroupName *targetGroupName);
+int stmfDeleteHostGroup(stmfGroupName *hostGroupName);
+int stmfDeleteTargetGroup(stmfGroupName *targetGroupName);
+int stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid);
+int stmfDevidFromWwn(uchar_t wwn[8], stmfDevid *devid);
+void stmfFreeMemory(void *);
+int stmfGetHostGroupList(stmfGroupList **initiatorGroupList);
+int stmfGetHostGroupMembers(stmfGroupName *hostGroupName,
+ stmfGroupProperties **groupProperties);
+int stmfGetLocalPortProviderList(stmfProviderList **localPortProviderList);
+int stmfGetLocalPortProviderProperties(stmfProviderName *providerName,
+ stmfLocalPortProviderProperties *providerProperties);
+int stmfGetLogicalUnitList(stmfGuidList **logicalUnitList);
+int stmfGetLogicalUnitProperties(stmfGuid *logicalUnit,
+ stmfLogicalUnitProperties *logicalUnitProps);
+int stmfGetLogicalUnitProviderList(stmfProviderList **logicalUnitProviderList);
+int stmfGetLogicalUnitProviderProperties(stmfProviderName *providerName,
+ stmfLogicalUnitProviderProperties *providerProperties);
+int stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType);
+int stmfGetProviderDataProt(char *providerName, nvlist_t **nvl,
+ int providerType, uint64_t *setToken);
+int stmfGetSessionList(stmfDevid *target, stmfSessionList **sessionList);
+int stmfGetState(stmfState *);
+int stmfGetTargetGroupList(stmfGroupList **targetGroupList);
+int stmfGetTargetGroupMembers(stmfGroupName *targetGroupName,
+ stmfGroupProperties **groupProperties);
+int stmfGetTargetList(stmfDevidList **targetList);
+int stmfGetTargetProperties(stmfDevid *target,
+ stmfTargetProperties *targetProps);
+int stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList);
+int stmfLoadConfig(void);
+int stmfOffline(void);
+int stmfOfflineTarget(stmfDevid *devid);
+int stmfOfflineLogicalUnit(stmfGuid *logicalUnit);
+int stmfOnline(void);
+int stmfOnlineTarget(stmfDevid *devid);
+int stmfOnlineLogicalUnit(stmfGuid *logicalUnit);
+int stmfRemoveFromHostGroup(stmfGroupName *hostGroupName,
+ stmfDevid *initiatorName);
+int stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName,
+ stmfDevid *targetName);
+int stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex);
+int stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType);
+int stmfSetProviderDataProt(char *providerName, nvlist_t *nvl,
+ int providerType, uint64_t *setToken);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSTMF_H */
diff --git a/usr/src/lib/libstmf/common/llib-lstmf b/usr/src/lib/libstmf/common/llib-lstmf
new file mode 100644
index 0000000000..73d658b7ff
--- /dev/null
+++ b/usr/src/lib/libstmf/common/llib-lstmf
@@ -0,0 +1,30 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libstmf.h>
+#include <store.h>
diff --git a/usr/src/lib/libstmf/common/mapfile-vers b/usr/src/lib/libstmf/common/mapfile-vers
new file mode 100644
index 0000000000..b98f3acbd8
--- /dev/null
+++ b/usr/src/lib/libstmf/common/mapfile-vers
@@ -0,0 +1,72 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+SUNW_1.1 {
+ global:
+ stmfAddToHostGroup;
+ stmfAddToTargetGroup;
+ stmfAddViewEntry;
+ stmfClearProviderData;
+ stmfCreateHostGroup;
+ stmfCreateTargetGroup;
+ stmfDeleteHostGroup;
+ stmfDeleteTargetGroup;
+ stmfDevidFromIscsiName;
+ stmfDevidFromWwn;
+ stmfFreeMemory;
+ stmfGetHostGroupList;
+ stmfGetHostGroupMembers;
+ stmfGetTargetGroupList;
+ stmfGetTargetGroupMembers;
+ stmfGetTargetList;
+ stmfGetTargetProperties;
+ stmfGetLogicalUnitList;
+ stmfGetLogicalUnitProperties;
+ stmfGetProviderData;
+ stmfGetProviderDataList;
+ stmfGetProviderDataProt;
+ stmfGetSessionList;
+ stmfGetState;
+ stmfGetViewEntryList;
+ stmfOfflineTarget;
+ stmfOfflineLogicalUnit;
+ stmfOnlineTarget;
+ stmfOnlineLogicalUnit;
+ stmfRemoveFromHostGroup;
+ stmfRemoveFromTargetGroup;
+ stmfRemoveViewEntry;
+ stmfSetProviderData;
+ stmfSetProviderDataProt;
+ local:
+ *;
+};
+
+SUNWprivate {
+ global:
+ stmfLoadConfig;
+ stmfOffline;
+ stmfOnline;
+ local:
+ *;
+};
+
diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c
new file mode 100644
index 0000000000..08a457c78c
--- /dev/null
+++ b/usr/src/lib/libstmf/common/stmf.c
@@ -0,0 +1,3376 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <libnvpair.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <libstmf.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <store.h>
+#include <locale.h>
+#include <sys/stmf_ioctl.h>
+
+#define STMF_PATH "/devices/pseudo/stmf@0:admin"
+
+#define EUI "eui."
+#define WWN "wwn."
+#define IQN "iqn."
+#define WWN_ASCII_SIZE 16
+#define IDENT_LENGTH_BYTE 3
+
+#define MAX_LU 2<<16 - 1
+#define MAX_TARGET_PORT 1024
+#define MAX_PROVIDER 1024
+#define MAX_GROUP 1024
+#define MAX_SESSION 1024
+#define MAX_ISCSI_NAME 223
+
+#define OPEN_STMF 0
+#define OPEN_EXCL_STMF O_EXCL
+
+#define LOGICAL_UNIT_TYPE 0
+#define TARGET_TYPE 1
+#define STMF_SERVICE_TYPE 2
+
+static int openStmf(int, int *fd);
+static int groupIoctl(int fd, int cmd, stmfGroupName *);
+static int loadStore(int fd);
+static int initializeConfig();
+static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *);
+static int guidCompare(const void *, const void *);
+static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *);
+static int loadHostGroups(int fd, stmfGroupList *);
+static int loadTargetGroups(int fd, stmfGroupList *);
+static int getStmfState(stmf_state_desc_t *);
+static int setStmfState(int fd, stmf_state_desc_t *, int);
+static int setProviderData(int fd, char *, nvlist_t *, int);
+
+/*
+ * Open for stmf module
+ *
+ * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openStmf(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)",
+ STMF_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * initializeConfig
+ *
+ * This routine should be called before any ioctl requiring initialization
+ * which is basically everything except stmfGetState(), setStmfState() and
+ * stmfLoadConfig().
+ */
+static int
+initializeConfig()
+{
+ int ret;
+ stmfState state;
+
+
+ ret = stmfGetState(&state);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /* if we've already initialized or in the process, return success */
+ if (state.configState == STMF_CONFIG_STATE_INIT_DONE ||
+ state.configState == STMF_CONFIG_STATE_INIT) {
+ return (STMF_STATUS_SUCCESS);
+ }
+
+ ret = stmfLoadConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "initializeConfig:stmfLoadConfig:error(%d)", ret);
+ return (ret);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "initializeConfig:stmfGetState:error(%d)", ret);
+ return (ret);
+ }
+
+ if (state.configState != STMF_CONFIG_STATE_INIT_DONE) {
+ syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)",
+ state.configState);
+ ret = STMF_STATUS_ERROR;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * groupIoctl
+ *
+ * Purpose: issue ioctl for create/delete on group
+ *
+ * cmd - valid STMF ioctl group cmd
+ * groupName - groupName to create or delete
+ */
+static int
+groupIoctl(int fd, int cmd, stmfGroupName *groupName)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_group_name_t iGroupName;
+
+ bzero(&iGroupName, sizeof (iGroupName));
+
+ bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
+
+ iGroupName.name_size = strlen((char *)groupName);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to create the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (iGroupName);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_EXISTS:
+ case STMF_IOCERR_HG_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_IOCERR_TG_IN_USE:
+ case STMF_IOCERR_HG_IN_USE:
+ ret = STMF_ERROR_GROUP_IN_USE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupIoctl:error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * groupIoctl
+ *
+ * Purpose: issue ioctl for add/remove member on group
+ *
+ * cmd - valid STMF ioctl group member cmd
+ * groupName - groupName to add to or remove from
+ * devid - group member to add or remove
+ */
+static int
+groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_group_op_data_t stmfGroupData;
+
+ bzero(&stmfGroupData, sizeof (stmfGroupData));
+
+ bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName));
+
+ stmfGroupData.group.name_size = strlen((char *)groupName);
+ stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_ENTRY_EXISTS:
+ case STMF_IOCERR_HG_ENTRY_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_IOCERR_INVALID_TG_ENTRY:
+ case STMF_IOCERR_INVALID_HG_ENTRY:
+ ret =
+ STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ case STMF_IOCERR_INVALID_HG:
+ ret =
+ STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupMemberIoctl:error"
+ "(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * guidCompare
+ *
+ * qsort function
+ * sort on guid
+ */
+static int
+guidCompare(const void *p1, const void *p2)
+{
+
+ stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2;
+ int i;
+
+ for (i = 0; i < sizeof (stmfGuid); i++) {
+ if (g1->guid[i] > g2->guid[i])
+ return (1);
+ if (g1->guid[i] < g2->guid[i])
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * stmfAddToHostGroup
+ *
+ * Purpose: Adds an initiator to an existing host group
+ *
+ * hostGroupName - name of an existing host group
+ * hostName - name of initiator to add
+ */
+int
+stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || hostName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName,
+ hostName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = psAddHostGroupMember((char *)hostGroupName,
+ (char *)hostName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddToHostGroup:psAddHostGroupMember:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfAddToTargetGroup
+ *
+ * Purpose: Adds a local port to an existing target group
+ *
+ * targetGroupName - name of an existing target group
+ * targetName - name of target to add
+ */
+int
+stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
+{
+ int ret;
+ int fd;
+ stmfState state;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || targetName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
+ targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = psAddTargetGroupMember((char *)targetGroupName,
+ (char *)targetName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddToTargetGroup:psAddTargetGroupMember:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * addViewEntryIoctl
+ *
+ * Purpose: Issues ioctl to add a view entry
+ *
+ * lu - Logical Unit identifier to which the view entry is added
+ * viewEntry - view entry to add
+ * init - When set to B_TRUE, we are in the init state, i.e. don't call open
+ */
+static int
+addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ /*
+ * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
+ * false on input
+ */
+ ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
+ ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
+ ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
+
+ if (viewEntry->allHosts == B_FALSE) {
+ bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_host_group.name_size =
+ strlen((char *)viewEntry->hostGroup);
+ }
+ if (viewEntry->allTargets == B_FALSE) {
+ bcopy(viewEntry->targetGroup,
+ &ioctlViewEntry.ve_target_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_target_group.name_size =
+ strlen((char *)viewEntry->targetGroup);
+ }
+ if (viewEntry->luNbrValid) {
+ bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_LU_NUMBER_IN_USE:
+ ret = STMF_ERROR_LUN_IN_USE;
+ break;
+ case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
+ ret = STMF_ERROR_VE_CONFLICT;
+ break;
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ ret = STMF_ERROR_INVALID_HG;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_INVALID_TG;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "addViewEntryIoctl"
+ ":error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ goto done;
+ }
+
+ /* copy lu nbr back to caller's view entry on success */
+ viewEntry->veIndex = ioctlViewEntry.ve_ndx;
+ if (ioctlViewEntry.ve_lu_number_valid) {
+ bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ viewEntry->luNbrValid = B_TRUE;
+
+done:
+ return (ret);
+}
+
+/*
+ * stmfAddViewEntry
+ *
+ * Purpose: Adds a view entry to a logical unit
+ *
+ * lu - guid of the logical unit to which the view entry is added
+ * viewEntry - view entry structure to add
+ */
+int
+stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ int ret;
+ int fd;
+ stmfViewEntry iViewEntry;
+
+ if (lu == NULL || viewEntry == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* initialize and set internal view entry */
+ bzero(&iViewEntry, sizeof (iViewEntry));
+
+ if (!viewEntry->allHosts) {
+ bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
+ sizeof (iViewEntry.hostGroup));
+ } else {
+ iViewEntry.allHosts = B_TRUE;
+ }
+
+ if (!viewEntry->allTargets) {
+ bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
+ sizeof (iViewEntry.targetGroup));
+ } else {
+ iViewEntry.allTargets = B_TRUE;
+ }
+
+ if (viewEntry->luNbrValid) {
+ iViewEntry.luNbrValid = B_TRUE;
+ bcopy(viewEntry->luNbr, iViewEntry.luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ /*
+ * set users return view entry index valid flag to false
+ * in case of failure
+ */
+ viewEntry->veIndexValid = B_FALSE;
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * First add the view entry to the driver
+ */
+ ret = addViewEntryIoctl(fd, lu, &iViewEntry);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * If the add to driver was successful, add it to the persistent
+ * store.
+ */
+ ret = psAddViewEntry(lu, &iViewEntry);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddViewEntry:psAddViewEntry:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+
+ if (ret == STMF_STATUS_SUCCESS) {
+ /* set caller's view entry on success */
+ viewEntry->veIndexValid = iViewEntry.veIndexValid;
+ viewEntry->veIndex = iViewEntry.veIndex;
+ viewEntry->luNbrValid = B_TRUE;
+ bcopy(iViewEntry.luNbr, viewEntry->luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+ return (ret);
+}
+
+/*
+ * stmfClearProviderData
+ *
+ * Purpose: delete all provider data for specified provider
+ *
+ * providerName - name of provider for which data should be deleted
+ */
+int
+stmfClearProviderData(char *providerName, int providerType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int savedErrno;
+ stmf_iocdata_t stmfIoctl;
+ stmf_ppioctl_data_t ppi;
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&ppi, sizeof (ppi));
+
+ (void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name));
+
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi.ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi.ppi_port_provider = 1;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
+
+ ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfClearProviderData:ioctl error(%d)",
+ ioctlRet);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (savedErrno != ENOENT) {
+ goto done;
+ }
+ }
+
+ ret = psClearProviderData(providerName, providerType);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfClearProviderData:psClearProviderData"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfCreateHostGroup
+ *
+ * Purpose: Create a new initiator group
+ *
+ * hostGroupName - name of host group to create
+ */
+int
+stmfCreateHostGroup(stmfGroupName *hostGroupName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName))) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
+ hostGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = psCreateHostGroup((char *)hostGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfCreateHostGroup:psCreateHostGroup:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfCreateTargetGroup
+ *
+ * Purpose: Create a local port group
+ *
+ * targetGroupName - name of local port group to create
+ */
+int
+stmfCreateTargetGroup(stmfGroupName *targetGroupName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName))) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Add the group to the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
+ targetGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * If the add to the driver was successful, add it to the persistent
+ * store.
+ */
+ ret = psCreateTargetGroup((char *)targetGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfCreateTargetGroup:psCreateTargetGroup"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDeleteHostGroup
+ *
+ * Purpose: Delete an initiator or local port group
+ *
+ * hostGroupName - group to delete
+ */
+int
+stmfDeleteHostGroup(stmfGroupName *hostGroupName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Remove the group from the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP,
+ hostGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * If the remove from the driver was successful, remove it from the
+ * persistent store.
+ */
+ ret = psDeleteHostGroup((char *)hostGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDeleteTargetGroup
+ *
+ * Purpose: Delete an initiator or local port group
+ *
+ * targetGroupName - group to delete
+ */
+int
+stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (targetGroupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Remove the group from the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP,
+ targetGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * If the remove from the driver was successful, remove it from the
+ * persistent store.
+ */
+ ret = psDeleteTargetGroup((char *)targetGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfDeleteTargetGroup:psDeleteTargetGroup"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDevidFromIscsiName
+ *
+ * Purpose: convert an iSCSI name to an stmf devid
+ *
+ * iscsiName - unicode nul terminated utf-8 encoded iSCSI name
+ * devid - on success, contains the converted iscsi name
+ */
+int
+stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid)
+{
+ if (devid == NULL || iscsiName == NULL)
+ return (STMF_ERROR_INVALID_ARG);
+
+ bzero(devid, sizeof (stmfDevid));
+
+ /* Validate size of target */
+ if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME ||
+ devid->identLength < strlen(EUI) ||
+ devid->identLength < strlen(IQN)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) &&
+ strncmp(iscsiName, IQN, strlen(IQN)) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* copy UTF-8 bytes to ident */
+ bcopy(iscsiName, devid->ident, devid->identLength);
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfDevidFromWwn
+ *
+ * Purpose: convert a WWN to an stmf devid
+ *
+ * wwn - 8-byte wwn identifier
+ * devid - on success, contains the converted wwn
+ */
+int
+stmfDevidFromWwn(uchar_t *wwn, stmfDevid *devid)
+{
+ if (wwn == NULL || devid == NULL)
+ return (STMF_ERROR_INVALID_ARG);
+
+ bzero(devid, sizeof (stmfDevid));
+
+ /* Copy eui prefix */
+ (void) bcopy(WWN, devid->ident, strlen(WWN));
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf((char *)&devid->ident[strlen(WWN)],
+ sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X",
+ wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
+
+ devid->identLength = strlen((char *)devid->ident);
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfFreeMemory
+ *
+ * Purpose: Free memory allocated by this library
+ *
+ * memory - previously allocated pointer of memory managed by library
+ */
+void
+stmfFreeMemory(void *memory)
+{
+ free(memory);
+}
+
+/*
+ * stmfGetHostGroupList
+ *
+ * Purpose: Retrieves the list of initiator group oids
+ *
+ * hostGroupList - pointer to pointer to hostGroupList structure
+ * on success, this contains the host group list.
+ */
+int
+stmfGetHostGroupList(stmfGroupList **hostGroupList)
+{
+ int ret;
+
+ if (hostGroupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = psGetHostGroupList(hostGroupList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetHostGroupList:psGetHostGroupList:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetHostGroupMembers
+ *
+ * Purpose: Retrieves the group properties for a host group
+ *
+ * groupName - name of group for which to retrieve host group members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ * on success, this contains the list of group members.
+ */
+int
+stmfGetHostGroupMembers(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp)
+{
+ int ret;
+
+ if (groupName == NULL || groupProp == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = psGetHostGroupMemberList((char *)groupName, groupProp);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetHostGroupMembers:psGetHostGroupMembers"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetProviderData
+ *
+ * Purpose: Get provider data list
+ *
+ * providerName - name of provider for which to retrieve the data
+ * nvl - pointer to nvlist_t pointer which will contain the nvlist data
+ * retrieved.
+ * providerType - type of provider for which to retrieve data.
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ */
+int
+stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType)
+{
+ return (stmfGetProviderDataProt(providerName, nvl, providerType,
+ NULL));
+}
+
+/*
+ * stmfGetProviderDataProt
+ *
+ * Purpose: Get provider data list with token
+ *
+ * providerName - name of provider for which to retrieve the data
+ * nvl - pointer to nvlist_t pointer which will contain the nvlist data
+ * retrieved.
+ * providerType - type of provider for which to retrieve data.
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ * setToken - Returns the stale data token
+ */
+int
+stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret;
+
+ if (providerName == NULL || nvl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ ret = psGetProviderData(providerName, nvl, providerType, setToken);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetProviderData:psGetProviderData:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetProviderDataList
+ *
+ * Purpose: Get the list of providers currently persisting data
+ *
+ * providerList - pointer to pointer to an stmfProviderList structure allocated
+ * by the caller. Will contain the list of providers on success.
+ */
+int
+stmfGetProviderDataList(stmfProviderList **providerList)
+{
+ int ret;
+
+ ret = psGetProviderDataList(providerList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetProviderDataList:psGetProviderDataList"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * stmfGetSessionList
+ *
+ * Purpose: Retrieves the session list for a target (devid)
+ *
+ * devid - devid of target for which to retrieve session information.
+ * sessionList - pointer to pointer to stmfSessionList structure
+ * on success, this contains the list of initiator sessions.
+ */
+int
+stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_SESSION_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ slist_scsi_session_t *fSessionList;
+ uint8_t ident[260];
+ uint32_t fSessionListSize;
+
+ if (sessionList == NULL || devid == NULL) {
+ ret = STMF_ERROR_INVALID_ARG;
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fSessionListSize = MAX_SESSION;
+ fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
+ fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
+ if (fSessionList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the session list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident;
+ stmfIoctl.stmf_ibuf_size = sizeof (ident);
+ stmfIoctl.stmf_obuf_size = fSessionListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetSessionList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > MAX_SESSION) {
+ fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_scsi_session_t);
+ fSessionList = realloc(fSessionList, fSessionListSize);
+ if (fSessionList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+ stmfIoctl.stmf_obuf_size = fSessionListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetSessionList:ioctl "
+ "errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) +
+ stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession));
+ if (*sessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ free(sessionList);
+ goto done;
+ }
+
+ (*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
+
+ /*
+ * copy session info to caller's buffer
+ */
+ for (i = 0; i < (*sessionList)->cnt; i++) {
+ (*sessionList)->session[i].initiator.identLength =
+ fSessionList->initiator[IDENT_LENGTH_BYTE];
+ bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]),
+ (*sessionList)->session[i].initiator.ident,
+ STMF_IDENT_LENGTH);
+ bcopy(&(fSessionList->alias),
+ &((*sessionList)->session[i].alias),
+ sizeof ((*sessionList)->session[i].alias));
+ bcopy(&(fSessionList++->creation_time),
+ &((*sessionList)->session[i].creationTime),
+ sizeof (time_t));
+ }
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetGroupList
+ *
+ * Purpose: Retrieves the list of target groups
+ *
+ * targetGroupList - pointer to a pointer to an stmfGroupList structure. On
+ * success, it contains the list of target groups.
+ */
+int
+stmfGetTargetGroupList(stmfGroupList **targetGroupList)
+{
+ int ret;
+
+ if (targetGroupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = psGetTargetGroupList(targetGroupList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetGroupList:psGetTargetGroupList:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetTargetGroupMembers
+ *
+ * Purpose: Retrieves the group members for a target group
+ *
+ * groupName - name of target group for which to retrieve members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ * on success, this contains the list of group members.
+ */
+int
+stmfGetTargetGroupMembers(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp)
+{
+ int ret;
+
+ if (groupName == NULL || groupProp == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetGroupMembers:psGetTargetGroupMembers:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetTargetList
+ *
+ * Purpose: Retrieves the list of target ports
+ *
+ * targetList - pointer to a pointer to an stmfDevidList structure.
+ * On success, it contains the list of local ports (target).
+ */
+int
+stmfGetTargetList(stmfDevidList **targetList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ /* framework target port list */
+ slist_target_port_t *fTargetList;
+ uint32_t fTargetListSize;
+
+ if (targetList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fTargetListSize = MAX_TARGET_PORT * sizeof (slist_target_port_t);
+ fTargetList = (slist_target_port_t *)calloc(1, fTargetListSize);
+ if (fTargetList == NULL) {
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = fTargetListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
+ ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetList:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > MAX_TARGET_PORT) {
+ fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_lu_t);
+ fTargetList = realloc(fTargetList, fTargetListSize);
+ if (fTargetList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+ stmfIoctl.stmf_obuf_size = fTargetListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
+ ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST,
+ &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ *targetList = (stmfDevidList *)calloc(1,
+ stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
+ sizeof (stmfDevidList));
+
+ (*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
+ (*targetList)->devid[i].identLength =
+ fTargetList->target[IDENT_LENGTH_BYTE];
+ bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1],
+ &(*targetList)->devid[i].ident,
+ fTargetList->target[IDENT_LENGTH_BYTE]);
+ }
+
+done:
+ (void) close(fd);
+ free(fTargetList);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetProperties
+ *
+ * Purpose: Retrieves the properties for a logical unit
+ *
+ * devid - devid of the target for which to retrieve properties
+ * targetProps - pointer to an stmfTargetProperties structure.
+ * On success, it contains the target properties for
+ * the specified devid.
+ */
+int
+stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ sioc_target_port_props_t targetProperties;
+
+ if (devid == NULL || targetProps == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties;
+ stmfIoctl.stmf_obuf_size = sizeof (targetProperties);
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES,
+ &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetProperties:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ bcopy(targetProperties.tgt_provider_name, targetProps->providerName,
+ sizeof (targetProperties.tgt_provider_name));
+ if (targetProperties.tgt_state == STMF_STATE_ONLINE) {
+ targetProps->status = STMF_TARGET_PORT_ONLINE;
+ } else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) {
+ targetProps->status = STMF_TARGET_PORT_OFFLINE;
+ } else if (targetProperties.tgt_state == STMF_STATE_ONLINING) {
+ targetProps->status = STMF_TARGET_PORT_ONLINING;
+ } else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) {
+ targetProps->status = STMF_TARGET_PORT_OFFLINING;
+ }
+ bcopy(targetProperties.tgt_alias, targetProps->alias,
+ sizeof (targetProps->alias));
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetLogicalUnitList
+ *
+ * Purpose: Retrieves list of logical unit Object IDs
+ *
+ * luList - pointer to a pointer to a stmfGuidList structure. On success,
+ * it contains the list of logical unit guids.
+ *
+ */
+int
+stmfGetLogicalUnitList(stmfGuidList **luList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_LU_LIST;
+ int i, k;
+ stmf_iocdata_t stmfIoctl;
+ /* framework lu list */
+ slist_lu_t *fLuList;
+ /* persistent store lu list */
+ stmfGuidList *sLuList = NULL;
+ int finalListSize = 0;
+ int newAllocSize;
+ uint32_t fLuListSize;
+ uint32_t endList;
+
+ if (luList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fLuListSize = MAX_LU;
+ fLuListSize = fLuListSize * (sizeof (slist_lu_t));
+ fLuList = (slist_lu_t *)calloc(1, fLuListSize);
+ if (fLuList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the LU list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = fLuListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > MAX_LU) {
+ fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_lu_t);
+ fLuList = realloc(fLuList, fLuListSize);
+ if (fLuList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+ stmfIoctl.stmf_obuf_size = fLuListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ ret = psGetLogicalUnitList(&sLuList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:psGetLogicalUnitList"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * 2 lists must be merged
+ * reallocate the store list to add the list from the
+ * framework
+ */
+ newAllocSize = sLuList->cnt * sizeof (stmfGuid) + sizeof (stmfGuidList)
+ + stmfIoctl.stmf_obuf_nentries * sizeof (stmfGuid);
+
+ sLuList = realloc(sLuList, newAllocSize);
+ if (sLuList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ /*
+ * add list from ioctl. Start from end of list retrieved from store.
+ */
+ endList = sLuList->cnt + stmfIoctl.stmf_obuf_nentries;
+ for (k = 0, i = sLuList->cnt; i < endList; i++, k++) {
+ bcopy(&fLuList[k].lu_guid, sLuList->guid[i].guid,
+ sizeof (stmfGuid));
+ }
+ sLuList->cnt = endList;
+
+ /*
+ * sort the list for merging
+ */
+ qsort((void *)&(sLuList->guid[0]), sLuList->cnt,
+ sizeof (stmfGuid), guidCompare);
+
+ /*
+ * get final list count
+ */
+ for (i = 0; i < sLuList->cnt; i++) {
+ if ((i + 1) <= sLuList->cnt) {
+ if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid,
+ sizeof (stmfGuid)) == 0) {
+ continue;
+ }
+ }
+ finalListSize++;
+ }
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
+ finalListSize * sizeof (stmfGuid));
+ if (*luList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ /*
+ * copy guids to caller's buffer
+ */
+ for (k = 0, i = 0; i < sLuList->cnt; i++) {
+ if ((i + 1) <= sLuList->cnt) {
+ if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid,
+ sizeof (stmfGuid)) == 0) {
+ continue;
+ }
+ }
+ bcopy(&(sLuList->guid[i].guid), (*luList)->guid[k++].guid,
+ sizeof (stmfGuid));
+ }
+
+ (*luList)->cnt = finalListSize;
+
+done:
+ (void) close(fd);
+ /*
+ * free internal buffers
+ */
+ free(fLuList);
+ free(sLuList);
+ return (ret);
+}
+
+/*
+ * stmfGetLogicalUnitProperties
+ *
+ * Purpose: Retrieves the properties for a logical unit
+ *
+ * lu - guid of the logical unit for which to retrieve properties
+ * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success,
+ * it contains the logical unit properties for the specified guid.
+ */
+int
+stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int stmfRet;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_GET_LU_PROPERTIES;
+ stmfViewEntryList *viewEntryList = NULL;
+ stmf_iocdata_t stmfIoctl;
+ sioc_lu_props_t fLuProps;
+
+ if (luProps == NULL || luProps == NULL) {
+ ret = STMF_ERROR_INVALID_ARG;
+ }
+
+ bzero(luProps, sizeof (stmfLogicalUnitProperties));
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps;
+ stmfIoctl.stmf_obuf_size = sizeof (fLuProps);
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ stmfRet = stmfGetViewEntryList(lu,
+ &viewEntryList);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ luProps->status =
+ STMF_LOGICAL_UNIT_UNREGISTERED;
+ if (viewEntryList->cnt > 0) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ ret = STMF_ERROR_NOT_FOUND;
+ }
+ } else {
+ ret = STMF_ERROR_NOT_FOUND;
+ }
+ stmfFreeMemory(viewEntryList);
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnit:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ bcopy(fLuProps.lu_provider_name, luProps->providerName,
+ sizeof (fLuProps.lu_provider_name));
+ if (fLuProps.lu_state == STMF_STATE_ONLINE) {
+ luProps->status = STMF_LOGICAL_UNIT_ONLINE;
+ } else if (fLuProps.lu_state == STMF_STATE_OFFLINE) {
+ luProps->status = STMF_LOGICAL_UNIT_OFFLINE;
+ } else if (fLuProps.lu_state == STMF_STATE_ONLINING) {
+ luProps->status = STMF_LOGICAL_UNIT_ONLINING;
+ } else if (fLuProps.lu_state == STMF_STATE_OFFLINING) {
+ luProps->status = STMF_LOGICAL_UNIT_OFFLINING;
+ }
+ bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias));
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetState
+ *
+ * Purpose: retrieve the current state of the stmf module
+ *
+ * state - pointer to stmfState structure allocated by the caller
+ * On success, contains the state of stmf
+ */
+int
+stmfGetState(stmfState *state)
+{
+ int ret;
+ stmf_state_desc_t iState;
+
+ if (state == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = getStmfState(&iState);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ switch (iState.state) {
+ case STMF_STATE_ONLINE:
+ state->operationalState =
+ STMF_SERVICE_STATE_ONLINE;
+ break;
+ case STMF_STATE_OFFLINE:
+ state->operationalState =
+ STMF_SERVICE_STATE_OFFLINE;
+ break;
+ case STMF_STATE_ONLINING:
+ state->operationalState =
+ STMF_SERVICE_STATE_ONLINING;
+ break;
+ case STMF_STATE_OFFLINING:
+ state->operationalState =
+ STMF_SERVICE_STATE_OFFLINING;
+ break;
+ default:
+ state->operationalState =
+ STMF_SERVICE_STATE_UNKNOWN;
+ break;
+ }
+ switch (iState.config_state) {
+ case STMF_CONFIG_NONE:
+ state->configState = STMF_CONFIG_STATE_NONE;
+ break;
+ case STMF_CONFIG_INIT:
+ state->configState = STMF_CONFIG_STATE_INIT;
+ break;
+ case STMF_CONFIG_INIT_DONE:
+ state->configState =
+ STMF_CONFIG_STATE_INIT_DONE;
+ break;
+ default:
+ state->configState =
+ STMF_CONFIG_STATE_UNKNOWN;
+ break;
+ }
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfGetViewEntryList
+ *
+ * Purpose: Retrieves the list of view entries for the specified
+ * logical unit.
+ *
+ * lu - the guid of the logical unit for which to retrieve the view entry list
+ * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On
+ * success, contains the list of view entries.
+ */
+int
+stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
+{
+ int ret;
+
+ if (lu == NULL || viewEntryList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = psGetViewEntryList(lu, viewEntryList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetViewEntryList:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * loadHostGroups
+ *
+ * Purpose - issues the ioctl to load the host groups into stmf
+ *
+ * fd - file descriptor for the control node of stmf.
+ * groupList - populated host group list
+ */
+static int
+loadHostGroups(int fd, stmfGroupList *groupList)
+{
+ int i, j;
+ int ret = STMF_STATUS_SUCCESS;
+ stmfGroupProperties *groupProps = NULL;
+
+ for (i = 0; i < groupList->cnt; i++) {
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
+ &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = stmfGetHostGroupMembers(&(groupList->name[i]),
+ &groupProps);
+ for (j = 0; j < groupProps->cnt; j++) {
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
+ &(groupList->name[i]), &(groupProps->name[j])))
+ != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+
+out:
+ stmfFreeMemory(groupProps);
+ return (ret);
+}
+
+/*
+ * loadTargetGroups
+ *
+ * Purpose - issues the ioctl to load the target groups into stmf
+ *
+ * fd - file descriptor for the control node of stmf.
+ * groupList - populated target group list.
+ */
+static int
+loadTargetGroups(int fd, stmfGroupList *groupList)
+{
+ int i, j;
+ int ret = STMF_STATUS_SUCCESS;
+ stmfGroupProperties *groupProps = NULL;
+
+ for (i = 0; i < groupList->cnt; i++) {
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
+ &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = stmfGetTargetGroupMembers(&(groupList->name[i]),
+ &groupProps);
+ for (j = 0; j < groupProps->cnt; j++) {
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
+ &(groupList->name[i]), &(groupProps->name[j])))
+ != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+
+out:
+ stmfFreeMemory(groupProps);
+ return (ret);
+}
+
+
+/*
+ * loadStore
+ *
+ * Purpose: Load the configuration data from the store
+ *
+ * First load the host groups and target groups, then the view entries
+ * and finally the provider data
+ *
+ * fd - file descriptor of control node for stmf.
+ */
+static int
+loadStore(int fd)
+{
+ int ret;
+ int i, j;
+ stmfGroupList *groupList = NULL;
+ stmfGuidList *guidList = NULL;
+ stmfViewEntryList *viewEntryList = NULL;
+ stmfProviderList *providerList = NULL;
+ int providerType;
+ nvlist_t *nvl = NULL;
+
+
+
+ /* load host groups */
+ ret = stmfGetHostGroupList(&groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ ret = loadHostGroups(fd, groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ stmfFreeMemory(groupList);
+ groupList = NULL;
+
+ /* load target groups */
+ ret = stmfGetTargetGroupList(&groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = loadTargetGroups(fd, groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ stmfFreeMemory(groupList);
+ groupList = NULL;
+
+ /* Get the guid list */
+ ret = psGetLogicalUnitList(&guidList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * We have the guid list, now get the corresponding
+ * view entries for each guid
+ */
+ for (i = 0; i < guidList->cnt; i++) {
+ ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ for (j = 0; j < viewEntryList->cnt; j++) {
+ ret = addViewEntryIoctl(fd, &guidList->guid[i],
+ &viewEntryList->ve[j]);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+ /* get the list of providers that have data */
+ ret = psGetProviderDataList(&providerList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ for (i = 0; i < providerList->cnt; i++) {
+ providerType = providerList->provider[i].providerType;
+ ret = psGetProviderData(providerList->provider[i].name,
+ &nvl, providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ /* call setProviderData */
+ ret = setProviderData(fd, providerList->provider[i].name, nvl,
+ providerType);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ nvlist_free(nvl);
+ nvl = NULL;
+ }
+out:
+ if (groupList != NULL) {
+ free(groupList);
+ }
+ if (guidList != NULL) {
+ free(guidList);
+ }
+ if (viewEntryList != NULL) {
+ free(viewEntryList);
+ }
+ if (nvl != NULL) {
+ nvlist_free(nvl);
+ }
+ return (ret);
+}
+
+/*
+ * stmfLoadConfig
+ *
+ * Purpose - load the configuration data from smf into stmf
+ *
+ */
+int
+stmfLoadConfig(void)
+{
+ int ret;
+ int fd;
+ stmf_state_desc_t stmfStateSet;
+ stmfState state;
+
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+
+
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+ stmfStateSet.config_state = STMF_CONFIG_INIT;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /* Load the persistent configuration data */
+ ret = loadStore(fd);
+ if (ret != 0) {
+ goto done;
+ }
+
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+ stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
+
+done:
+ if (ret == STMF_STATUS_SUCCESS) {
+ ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+ }
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * getStmfState
+ *
+ * stmfState - pointer to stmf_state_desc_t structure. Will contain the state
+ * information of the stmf service on success.
+ */
+static int
+getStmfState(stmf_state_desc_t *stmfState)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
+ stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+ return (ret);
+}
+
+
+/*
+ * setStmfState
+ *
+ * stmfState - pointer to caller set state structure
+ * objectType - one of:
+ * LOGICAL_UNIT_TYPE
+ * TARGET_TYPE
+ * STMF_SERVICE_TYPE
+ */
+static int
+setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+
+ switch (objectType) {
+ case LOGICAL_UNIT_TYPE:
+ cmd = STMF_IOCTL_SET_LU_STATE;
+ break;
+ case TARGET_TYPE:
+ cmd = STMF_IOCTL_SET_TARGET_PORT_STATE;
+ break;
+ case STMF_SERVICE_TYPE:
+ cmd = STMF_IOCTL_SET_STMF_STATE;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to set the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * stmfOnline
+ *
+ * Purpose: Online stmf service
+ *
+ */
+int
+stmfOnline(void)
+{
+ int ret;
+ int fd;
+ stmfState state;
+ stmf_state_desc_t iState;
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+ iState.state = STMF_STATE_ONLINE;
+ iState.config_state = STMF_CONFIG_NONE;
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOffline
+ *
+ * Purpose: Offline stmf service
+ *
+ */
+int
+stmfOffline(void)
+{
+ int ret;
+ int fd;
+ stmfState state;
+ stmf_state_desc_t iState;
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_OFFLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+ iState.state = STMF_STATE_OFFLINE;
+ iState.config_state = STMF_CONFIG_NONE;
+
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfOfflineTarget
+ *
+ * Purpose: Change state of target to offline
+ *
+ * devid - devid of the target to offline
+ */
+int
+stmfOfflineTarget(stmfDevid *devid)
+{
+ stmf_state_desc_t targetState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (devid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bzero(&targetState, sizeof (targetState));
+
+ targetState.state = STMF_STATE_OFFLINE;
+ targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &targetState, TARGET_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOfflineLogicalUnit
+ *
+ * Purpose: Change state of logical unit to offline
+ *
+ * lu - guid of the logical unit to offline
+ */
+int
+stmfOfflineLogicalUnit(stmfGuid *lu)
+{
+ stmf_state_desc_t luState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(&luState, sizeof (luState));
+
+ luState.state = STMF_STATE_OFFLINE;
+ bcopy(lu, &luState.ident, sizeof (stmfGuid));
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOnlineTarget
+ *
+ * Purpose: Change state of target to online
+ *
+ * devid - devid of the target to online
+ */
+int
+stmfOnlineTarget(stmfDevid *devid)
+{
+ stmf_state_desc_t targetState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (devid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bzero(&targetState, sizeof (targetState));
+
+ targetState.state = STMF_STATE_ONLINE;
+ targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &targetState, TARGET_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOnlineLogicalUnit
+ *
+ * Purpose: Change state of logical unit to online
+ *
+ * lu - guid of the logical unit to online
+ */
+int
+stmfOnlineLogicalUnit(stmfGuid *lu)
+{
+ stmf_state_desc_t luState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(&luState, sizeof (luState));
+
+ luState.state = STMF_STATE_ONLINE;
+ bcopy(lu, &luState.ident, sizeof (stmfGuid));
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveFromHostGroup
+ *
+ * Purpose: Removes an initiator from an initiator group
+ *
+ * hostGroupName - name of an initiator group
+ * hostName - name of host group member to remove
+ */
+int
+stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || hostName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY,
+ hostGroupName, hostName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = psRemoveHostGroupMember((char *)hostGroupName,
+ (char *)hostName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_MEMBER_NOT_FOUND:
+ ret = STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveFromHostGroup"
+ "psRemoveHostGroupMember:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveFromTargetGroup
+ *
+ * Purpose: Removes a local port from a local port group
+ *
+ * targetGroupName - name of a target group
+ * targetName - name of target to remove
+ */
+int
+stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || targetName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY,
+ targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ ret = psRemoveTargetGroupMember((char *)targetGroupName,
+ (char *)targetName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_MEMBER_NOT_FOUND:
+ ret = STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveFromTargetGroup"
+ "psRemoveTargetGroupMember:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveViewEntry
+ *
+ * Purpose: Removes a view entry from a logical unit
+ *
+ * lu - guid of lu for which view entry is being removed
+ * viewEntryIndex - index of view entry to remove
+ *
+ */
+int
+stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ ioctlViewEntry.ve_ndx_valid = B_TRUE;
+ ioctlViewEntry.ve_ndx = viewEntryIndex;
+ bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ case ENODEV:
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveViewEntry:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ ret = psRemoveViewEntry(lu, viewEntryIndex);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfSetProviderData
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - type of provider for which to set data
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ */
+int
+stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType)
+{
+ return (stmfSetProviderDataProt(providerName, nvl, providerType,
+ NULL));
+}
+
+/*
+ * stmfSetProviderDataProt
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - type of provider for which to set data
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ * setToken - Stale data token returned in the stmfGetProviderDataProt()
+ * call or NULL.
+ */
+int
+stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret;
+ int fd;
+
+ if (providerName == NULL || nvl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = setProviderData(fd, providerName, nvl, providerType);
+
+ (void) close(fd);
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /* setting driver provider data successful. Now persist it */
+ ret = psSetProviderData(providerName, nvl, providerType, setToken);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ case STMF_PS_ERROR_PROV_DATA_STALE:
+ ret = STMF_ERROR_PROV_DATA_STALE;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfSetProviderData"
+ "psSetProviderData:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ return (ret);
+}
+
+/*
+ * setProviderData
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - logical unit or port provider
+ */
+static int
+setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ size_t nvlistEncodedSize;
+ stmf_ppioctl_data_t *ppi = NULL;
+ char *allocatedNvBuffer;
+ stmf_iocdata_t stmfIoctl;
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* get size of encoded nvlist */
+ if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* allocate memory for ioctl */
+ ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize +
+ sizeof (stmf_ppioctl_data_t));
+ if (ppi == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ allocatedNvBuffer = (char *)&ppi->ppi_data;
+ if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
+ NV_ENCODE_XDR, 0) != 0) {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* set provider name and provider type */
+ (void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name));
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi->ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi->ppi_port_provider = 1;
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* set the size of the ioctl data to packed data size */
+ ppi->ppi_data_size = nvlistEncodedSize;
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ /*
+ * Subtracting 8 from the size as that is the size of the last member
+ * of the structure where the packed data resides
+ */
+ stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
+ sizeof (stmf_ppioctl_data_t) - 8;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
+ ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setProviderData:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS)
+ goto done;
+ }
+
+done:
+ free(ppi);
+ return (ret);
+}
diff --git a/usr/src/lib/libstmf/common/store.c b/usr/src/lib/libstmf/common/store.c
new file mode 100644
index 0000000000..9e20376233
--- /dev/null
+++ b/usr/src/lib/libstmf/common/store.c
@@ -0,0 +1,4747 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <libscf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <strings.h>
+#include <libstmf.h>
+#include <store.h>
+#include <syslog.h>
+#include <signal.h>
+#include <pthread.h>
+#include <libnvpair.h>
+#include <limits.h>
+#include <unistd.h>
+
+/*
+ * This file's functions are responsible for all store and retrieve operations
+ * against the STMF smf(5) database. The following shows the currently defined
+ * schema for the STMF database:
+ *
+ * Description of property groups for service: svc:/system/stmf
+ *
+ * Stability: Volatile
+ *
+ * 1. Property Group: host_groups
+ * Properties: group_name-<N> where <N> is an unsigned integer
+ * type: ustring
+ * contains: group name
+ * group_name-<N>-member_list where <N> is an unsigned
+ * integer matching a group_name-<N> property.
+ * type: ustring
+ * contains: list of members
+ *
+ * Description:
+ * Contains the host group names as well as the host group members
+ * for each host group.
+ *
+ * 2. Property Group: target_groups
+ * Properties: group_name-<N> where <N> is an unsigned integer
+ * type: ustring
+ * contains: group name
+ * group_name-<N>-member_list where <N> is an unsigned
+ * integer matching a group_name-<N> property.
+ * type: ustring
+ * contains: list of members
+ *
+ * Description:
+ * Contains the target group names as well as the target group
+ * members for each target group.
+ *
+ * 3. Property Group: lu-<GUID>
+ * where <GUID> is a 32 character hexadecimal string.
+ * Properties: ve_cnt
+ * type: count
+ * contains: the number of current view entries
+ * view-entry-<N>-<GUID> where <N> is an unsigned integer
+ * type: ustring
+ * contains: nothing. Used as reference to the view
+ * entry property group
+ *
+ * Description:
+ * Contains the references to each view entry. One lu-<GUID>
+ * property group will exist for each logical unit with 1 or more
+ * view entries.
+ * Potentially can hold any other data that can be managed on a per
+ * logical unit basis.
+ *
+ * 4. Property Group: view_entry-<N>-<GUID> (matches property in lu-<GUID>
+ * property group)
+ * Properties: all_hosts
+ * type: boolean
+ * contains: when true, the value of host_group is
+ * ignored
+ * all_targets
+ * type: boolean
+ * contains: when true, the value of target_group is
+ * ignored
+ * host_group
+ * type: ustring
+ * contains: host group for logical unit mapping and
+ * masking purposes
+ * target_group
+ * type: ustring
+ * contains: target group for logical unit mapping and
+ * masking purposes
+ * lu_nbr
+ * type: opaque
+ * contains: the 8-byte SCSI logical unit number for
+ * mapping and masking purposes
+ * Description:
+ * One "view_entry-<N>-<GUID>" property group will exist for each
+ * view entry in the system. This property group name maps
+ * directly to the "lu-<GUID>" property group with a matching
+ * <GUID>.
+ *
+ * 5. Property Group: provider_data_pg_<provider-name>
+ * where <provider-name> is the name of the provider
+ * registered with stmf.
+ * Properties: provider_data_prop-<N>
+ * where <N> is a sequential identifier for the data
+ * chunk.
+ * type: opaque
+ * contains: up to STMF_PROVIDER_DATA_PROP_SIZE bytes
+ * of nvlist packed data.
+ * provider_data_count
+ * type: count
+ * contains: the number of provider data chunks
+ * provider_data_type
+ * type: integer
+ * contains: STMF_PORT_PROVIDER_TYPE or
+ * STMF_LU_PROVIDER_TYPE
+ *
+ * Description:
+ * Holds the nvlist packed provider data set via
+ * stmfSetProviderData and retrieved via stmfGetProviderData. Data
+ * is stored in STMF_PROVIDER_DATA_PROP_SIZE chunks. On retrieve,
+ * these chunks are reassembled and unpacked.
+ *
+ */
+
+static int iPsInit(scf_handle_t **, scf_service_t **);
+static int iPsCreateDeleteGroup(char *, char *, int);
+static int iPsAddRemoveGroupMember(char *, char *, char *, int);
+static int iPsGetGroupList(char *, stmfGroupList **);
+static int iPsGetGroupMemberList(char *, char *, stmfGroupProperties **);
+static int iPsAddViewEntry(char *, char *, stmfViewEntry *);
+static int iPsAddRemoveLuViewEntry(char *, char *, int);
+static int iPsGetViewEntry(char *, stmfViewEntry *);
+static int iPsGetActualGroupName(char *, char *, char *);
+static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *);
+static int viewEntryCompare(const void *, const void *);
+static int holdSignal(sigset_t *);
+static int releaseSignal(sigset_t *);
+static void sigHandler();
+
+static pthread_mutex_t sigSetLock = PTHREAD_MUTEX_INITIALIZER;
+
+sigset_t sigSet;
+sigset_t signalsCaught;
+
+struct sigaction currentActionQuit;
+struct sigaction currentActionTerm;
+struct sigaction currentActionInt;
+
+boolean_t actionSet = B_FALSE;
+
+/*
+ * Version info for the SMF schema
+ */
+#define STMF_SMF_VERSION 1
+
+/*
+ * Property Group Names and prefixes
+ */
+#define STMF_HOST_GROUPS "host_groups"
+#define STMF_TARGET_GROUPS "target_groups"
+#define STMF_VE_PREFIX "view_entry"
+#define STMF_LU_PREFIX "lu"
+#define STMF_DATA_GROUP "stmf_data"
+
+/*
+ * Property names and prefix for logical unit property group
+ */
+#define STMF_VE_CNT "ve_cnt"
+#define STMF_GROUP_PREFIX "group_name"
+#define STMF_MEMBER_LIST_SUFFIX "member_list"
+#define STMF_VERSION_NAME "version_name"
+
+/*
+ * Property names for view entry
+ */
+#define STMF_VE_ALLHOSTS "all_hosts"
+#define STMF_VE_HOSTGROUP "host_group"
+#define STMF_VE_ALLTARGETS "all_targets"
+#define STMF_VE_TARGETGROUP "target_group"
+#define STMF_VE_LUNBR "lu_nbr"
+
+/* Property group suffix for provider data */
+#define STMF_PROVIDER_DATA_PREFIX "provider_data_pg_"
+#define STMF_PROVIDER_DATA_PROP_PREFIX "provider_data_prop"
+#define STMF_PROVIDER_DATA_PROP_NAME_SIZE 256
+#define STMF_PROVIDER_DATA_PROP_TYPE "provider_type"
+#define STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt"
+#define STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt"
+/*
+ * This is the data chunk size. The current value limit for scf is 4096.
+ * This is defined by REP_PROTOCOL_VALUE_LEN in
+ * OS/Net: usr/src/common/svc/repcache_protocol.h
+ *
+ * Larger data property size = better performance
+ */
+#define STMF_PROVIDER_DATA_PROP_SIZE 4000
+
+#define STMF_SMF_READ_ATTR "solaris.smf.read.stmf"
+
+
+/* service name */
+#define STMF_SERVICE "system/stmf"
+
+/* limits and flag values */
+#define GROUP_MEMBER_ALLOC 100
+#define VIEW_ENTRY_STRUCT_CNT 6
+#define VIEW_ENTRY_PG_SIZE 256
+#define LOGICAL_UNIT_PG_SIZE 256
+#define VIEW_ENTRY_MAX UINT32_MAX
+#define GROUP_MAX UINT64_MAX
+#define ADD 0
+#define REMOVE 1
+
+/*
+ * sigHandler
+ *
+ * Catch the signal and set the global signalsCaught to the signal received
+ *
+ * signalsCaught will be used by releaseSignal to raise this signal when
+ * we're done processing our critical code.
+ *
+ */
+static void
+sigHandler(int sig)
+{
+ (void) sigaddset(&signalsCaught, sig);
+}
+
+/*
+ * iPsAddRemoveGroupMember
+ *
+ * Add or remove a member for a given group
+ *
+ * pgName - Property group name
+ * groupName - group name to which the member is added/removed
+ * memberName - member to be added/removed
+ * addRemoveFlag - ADD/REMOVE
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsAddRemoveGroupMember(char *pgName, char *groupName, char *memberName,
+int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_value_t **valueSet = NULL;
+ scf_iter_t *valueIter = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ int i = 0;
+ int lastAlloc;
+ int valueArraySize = 0;
+ int ret = STMF_PS_SUCCESS;
+ char buf[STMF_IDENT_LENGTH];
+ int commitRet;
+ boolean_t found = B_FALSE;
+
+ assert(pgName != NULL && groupName != NULL && memberName != NULL);
+
+ /*
+ * Init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the service property group handle
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * We're changing an existing property by adding a propval
+ * There are no add semantics in libscf for a property value. We'll
+ * need to read in the current properties and apply them all to the
+ * set and then add the one we were asked to add or omit the one
+ * we were asked to remove.
+ */
+ if (scf_transaction_property_change(tran, entry, groupName,
+ SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
+ } else {
+ ret = STMF_PS_ERROR;
+ syslog(LOG_ERR, "tran property change failed - %s",
+ scf_strerror(scf_error()));
+ }
+ goto out;
+ }
+
+ /*
+ * Get the property handle
+ */
+ if (scf_pg_get_property(pg, groupName, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Value lookup is used to lookup the existing values
+ */
+ valueLookup = scf_value_create(handle);
+ if (valueLookup == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * valueIter is the iterator handle, create the resource
+ */
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Allocate value resource pointers.
+ * We need a value resource for each value as value pointers passed
+ * to libscf cannot be destroyed until the commit or destroy on the
+ * transaction is done.
+ *
+ * We're using GROUP_MEMBER_ALLOC initially. If it's not large
+ * enough, we'll realloc on the fly
+ */
+ valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
+ * (lastAlloc = GROUP_MEMBER_ALLOC));
+ if (valueSet == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * Iterate through the existing values
+ */
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ bzero(buf, sizeof (buf));
+ if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Check for existing
+ * If we're adding, it's an error
+ * If we're removing, we skip it and simply not
+ * add it to the set. Subtraction by omission.
+ */
+ if ((strlen(buf) == strlen(memberName)) &&
+ bcmp(buf, memberName, strlen(buf)) == 0) {
+ if (addRemoveFlag == ADD) {
+ ret = STMF_PS_ERROR_EXISTS;
+ break;
+ } else {
+ found = B_TRUE;
+ continue;
+ }
+ }
+
+ /*
+ * Create the value resource for this iteration
+ */
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Set the value
+ */
+ if (scf_value_set_ustring(valueSet[i], buf) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Now add the value
+ */
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ i++;
+
+ /*
+ * realloc if we've hit the previous alloc size
+ */
+ if (i >= lastAlloc) {
+ lastAlloc += GROUP_MEMBER_ALLOC;
+ valueSet = realloc(valueSet,
+ sizeof (*valueSet) * lastAlloc);
+ if (valueSet == NULL) {
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ }
+ }
+
+ /*
+ * set valueArraySize to final allocated length
+ * so we can use it to destroy the resources correctly
+ */
+ valueArraySize = i;
+
+ if (!found && (addRemoveFlag == REMOVE)) {
+ ret = STMF_PS_ERROR_MEMBER_NOT_FOUND;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * If we're adding, we have one more step. Add the member to the
+ * propval list
+ */
+ if (addRemoveFlag == ADD) {
+ /*
+ * Now create the new entry
+ */
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ valueArraySize++;
+ }
+
+ /*
+ * Set the new member name
+ */
+ if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the new member
+ */
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * Yes, we're finally done. We actually added or removed one entry
+ * from the list.
+ * Woohoo!
+ */
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+
+ /*
+ * Free valueSet scf resources
+ */
+ if (valueArraySize > 0) {
+ for (i = 0; i < valueArraySize; i++) {
+ scf_value_destroy(valueSet[i]);
+ }
+ }
+ /*
+ * Now free the pointer array to the resources
+ */
+ if (valueSet != NULL) {
+ free(valueSet);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsAddRemoveLuViewEntry
+ *
+ * Adds or removes a view entry name property for a given logical unit
+ * property group. There is one logical unit property group for every logical
+ * unit that has one or more associated view entries.
+ *
+ * luPgName - Property group name of logical unit
+ * viewEntryPgName - Property group name of view entry
+ * addRemoveFlag - ADD_VE/REMOVE_VE
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsAddRemoveLuViewEntry(char *luPgName, char *viewEntryPgName,
+ int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_transaction_entry_t *entryVeName = NULL;
+ boolean_t createVeCnt = B_FALSE;
+ uint64_t veCnt = 0;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ assert(luPgName != NULL || viewEntryPgName != NULL);
+ assert(!(addRemoveFlag != ADD && addRemoveFlag != REMOVE));
+
+ /*
+ * Init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* get the LU property group */
+ if (scf_service_get_pg(svc, luPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND &&
+ addRemoveFlag == ADD) {
+ /* if it doesn't exist, create it */
+ if (scf_service_add_pg(svc, luPgName,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ } else {
+ /* we need to create the VE_CNT property */
+ createVeCnt = B_TRUE;
+ ret = STMF_PS_SUCCESS;
+ }
+ } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+ }
+
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+ if (createVeCnt) {
+ /*
+ * Create the STMF_VE_CNT property. This will keep the current
+ * total view entries for this logical unit.
+ */
+ if (scf_transaction_property_new(tran, entry, STMF_VE_CNT,
+ SCF_TYPE_COUNT) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ } else {
+ /*
+ * The STMF_VE_CNT property already exists. Just update
+ * it.
+ */
+ if (scf_transaction_property_change(tran, entry,
+ STMF_VE_CNT, SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_VE_CNT property
+ */
+ if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_VE_CNT value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value, &veCnt) == -1) {
+ syslog(LOG_ERR, "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Reset the value resource as it is used below
+ */
+ scf_value_reset(value);
+ }
+
+ if (addRemoveFlag == ADD) {
+ veCnt++;
+ } else {
+ /* Check if this is the last one being removed */
+ if (veCnt == 1) {
+ /*
+ * Delete the pg and get out if this is the last
+ * view entry
+ */
+ if (scf_pg_delete(pg) == -1) {
+ syslog(LOG_ERR, "delete pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ } else {
+ veCnt--;
+ }
+ }
+
+
+ /*
+ * Set the view entry count
+ */
+ scf_value_set_count(value, veCnt);
+
+ /*
+ * Add the value to the transaction entry
+ */
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Create a transaction entry resource for the view entry name
+ */
+ entryVeName = scf_entry_create(handle);
+ if (entryVeName == NULL) {
+ syslog(LOG_ERR, "scf transaction entry alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (addRemoveFlag == ADD) {
+ /*
+ * If adding, create a property with the view entry name
+ */
+ if (scf_transaction_property_new(tran, entryVeName,
+ viewEntryPgName, SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ } else {
+ /*
+ * If removing, delete the existing property with the view
+ * entry name
+ */
+ if (scf_transaction_property_delete(tran, entryVeName,
+ viewEntryPgName) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property delete failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ }
+
+ /*
+ * Commit property transaction
+ */
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (entryVeName != NULL) {
+ scf_entry_destroy(entryVeName);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsAddViewEntry
+ *
+ * Add a view entry property group and optionally, a logical unit property
+ * group if it does not exist.
+ *
+ * luName - ascii hexadecimal logical unit identifier
+ * viewEntryName - name of view entry (VIEW_ENTRY_nn)
+ * viewEntry - pointer to stmfViewEntry structure
+ */
+static int
+iPsAddViewEntry(char *luPgName, char *viewEntryPgName, stmfViewEntry *viewEntry)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_value_t *value[VIEW_ENTRY_STRUCT_CNT];
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry[VIEW_ENTRY_STRUCT_CNT];
+ int i = 0;
+ int j = 0;
+ int ret;
+ uint8_t scfBool;
+ boolean_t createdVePg = B_FALSE;
+ int backoutRet;
+ int commitRet;
+
+ assert(luPgName != NULL || viewEntryPgName != NULL ||
+ viewEntry == NULL);
+
+ bzero(value, sizeof (value));
+ bzero(entry, sizeof (entry));
+
+ /*
+ * Init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * allocate value and entry resources for scf
+ */
+ for (i = 0; i < VIEW_ENTRY_STRUCT_CNT; i++) {
+ if (((value[i] = scf_value_create(handle)) == NULL) ||
+ ((entry[i] = scf_entry_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ i = 0;
+
+ /*
+ * Create the View Entry property group
+ */
+ if (scf_service_add_pg(svc, viewEntryPgName, SCF_GROUP_APPLICATION,
+ 0, pg) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ createdVePg = B_TRUE;
+
+ /*
+ * Add the view entry as properties on the view entry group
+ */
+
+ /*
+ * Begin property update transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add allHosts property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_ALLHOSTS, SCF_TYPE_BOOLEAN) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /* Set the allHosts value */
+ scfBool = viewEntry->allHosts;
+ scf_value_set_boolean(value[i], scfBool);
+
+ /*
+ * Add the allHosts value to the transaction
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create hostGroup property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_HOSTGROUP, SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the value for hostGroup
+ */
+ if (scf_value_set_ustring(value[i], viewEntry->hostGroup) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the hostGroup value to the transaction entry
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create the allTargets property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_ALLTARGETS, SCF_TYPE_BOOLEAN) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the allTargets value
+ */
+ scfBool = viewEntry->allTargets;
+ scf_value_set_boolean(value[i], scfBool);
+
+ /*
+ * Add the allTargets value to the transaction
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create targetGroup property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_TARGETGROUP, SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the value for targetGroup
+ */
+ if (scf_value_set_ustring(value[i], viewEntry->targetGroup) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add targetGroup value to the transaction
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create the luNbr property
+ */
+ if (scf_transaction_property_new(tran, entry[i], STMF_VE_LUNBR,
+ SCF_TYPE_OPAQUE) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the luNbr
+ */
+ if (scf_value_set_opaque(value[i], (char *)viewEntry->luNbr,
+ sizeof (viewEntry->luNbr)) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add luNbr to the transaction entry
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now that we've successfully added the view entry,
+ * update the logical unit property group or create
+ * it if it does not exist
+ */
+ ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD);
+
+ /*
+ * If we did not add the view entry name to the logical unit,
+ * make sure we do not commit the transaction
+ */
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Commit property transaction
+ */
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ /*
+ * If we did not commit, try to remove the view entry name
+ * from the logical unit.
+ * If that fails, we're now inconsistent.
+ */
+ backoutRet = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ REMOVE);
+
+ if (backoutRet != STMF_PS_SUCCESS) {
+ syslog(LOG_ERR, "remove lu view entry failed"
+ "possible inconsistency - %s",
+ scf_strerror(scf_error()));
+ }
+ /*
+ * We are still in an error scenario even though the remove
+ * lu view entry succeeded.
+ */
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ /* if there was an error, delete the created pg if one was created */
+ if ((ret != STMF_PS_SUCCESS) && createdVePg) {
+ if (scf_pg_delete(pg) == -1) {
+ syslog(LOG_ERR, "delete VE pg failed - %s",
+ scf_strerror(scf_error()));
+ }
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ /*
+ * Free value and entry scf resources
+ */
+ if (i > 0) {
+ for (j = 0; j < VIEW_ENTRY_STRUCT_CNT; j++) {
+ if (value[j] != NULL)
+ scf_value_destroy(value[j]);
+ if (entry[j] != NULL)
+ scf_entry_destroy(entry[j]);
+ }
+ }
+
+ return (ret);
+}
+/*
+ * psClearProviderData
+ *
+ * providerName - name of provider data to clear
+ */
+int
+psClearProviderData(char *providerName, int providerType)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char pgName[MAXPATHLEN];
+ int ret = STMF_PS_SUCCESS;
+ boolean_t pgNotFound = B_FALSE;
+
+ if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE)) {
+ ret = STMF_PS_ERROR_INVALID_ARG;
+ goto out;
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if ((pg = scf_pg_create(handle)) == NULL) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * create the property group name
+ */
+ (void) snprintf(pgName, sizeof (pgName), "%s%s",
+ STMF_PROVIDER_DATA_PREFIX, providerName);
+
+ /*
+ * delete provider property group
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ pgNotFound = B_TRUE;
+ }
+ }
+
+ if (!pgNotFound && (scf_pg_delete(pg) == -1)) {
+ syslog(LOG_ERR, "delete pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (pgNotFound) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsCreateDeleteGroup
+ *
+ * Creates or deletes a group (target or host)
+ *
+ * When creating a group, two properties are created. One to hold the group
+ * name and the other to hold the group members.
+ *
+ * pgName - Property group name
+ * groupName - group name to create
+ * addRemoveFlag - ADD_GROUP/REMOVE_GROUP
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsCreateDeleteGroup(char *pgRefName, char *groupName, int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_iter_t *propIter = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry1 = NULL;
+ scf_transaction_entry_t *entry2 = NULL;
+ scf_value_t *value = NULL;
+ uint64_t groupIdx;
+ char buf1[MAXNAMELEN];
+ char buf2[MAXNAMELEN];
+ char tmpbuf[MAXNAMELEN];
+ boolean_t found = B_FALSE;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ assert(groupName != NULL);
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry1 = scf_entry_create(handle)) == NULL) ||
+ ((entry2 = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the property group being modified
+ */
+ if (scf_service_get_pg(svc, pgRefName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND &&
+ addRemoveFlag == ADD) {
+ if (scf_service_add_pg(svc, pgRefName,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Iterate through the group names.
+ * If we find it in the list, it's an error when addRemoveFlag == ADD.
+ */
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over member list properties
+ */
+ if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, tmpbuf,
+ sizeof (tmpbuf)) == -1) {
+ syslog(LOG_ERR, "get ustring failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ if ((strlen(tmpbuf) == strlen(groupName)) &&
+ bcmp(tmpbuf, groupName, strlen(tmpbuf)) == 0) {
+ if (addRemoveFlag == ADD) {
+ ret = STMF_PS_ERROR_EXISTS;
+ }
+ found = B_TRUE;
+ /*
+ * buf1 contains the name for REMOVE
+ */
+ break;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ scf_value_reset(value);
+
+ if (!found && addRemoveFlag == REMOVE) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ /*
+ * If we're adding, we need to create a new property name for the
+ * new group
+ */
+ if (addRemoveFlag == ADD) {
+ for (groupIdx = 0; groupIdx < GROUP_MAX; groupIdx++) {
+ if (snprintf(buf1, sizeof (buf1), "%s-%lld",
+ STMF_GROUP_PREFIX, groupIdx) > sizeof (buf1)) {
+ syslog(LOG_ERR,
+ "buffer overflow on property name %s",
+ buf1);
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_pg_get_property(pg, buf1, prop) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * Now create the new member list property for the new group
+ */
+ if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1,
+ STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ buf1);
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * buf1 now contains the name of the property if it was found in the
+ * list in the case of delete or the next available property name
+ * in the case of create
+ *
+ * buf2 now contains the member list property name
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (addRemoveFlag == ADD) {
+ /*
+ * Create the property 'group name'
+ * This is the container for the group name
+ */
+ if (scf_transaction_property_new(tran, entry1, buf1,
+ SCF_TYPE_USTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (scf_value_set_ustring(value, groupName) == -1) {
+ syslog(LOG_ERR, "set ustring failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (scf_entry_add_value(entry1, value) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /*
+ * Create the property 'group list'
+ * This is the container for the group members
+ */
+ if (scf_transaction_property_new(tran, entry2, buf2,
+ SCF_TYPE_USTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ /*
+ * Delete the property 'group name'
+ */
+ if (scf_transaction_property_delete(tran, entry1, buf1)
+ == -1) {
+ syslog(LOG_ERR,
+ "transaction property delete failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /*
+ * Delete the property 'group list'
+ */
+ if (scf_transaction_property_delete(tran, entry2, buf2)
+ == -1) {
+ syslog(LOG_ERR,
+ "transaction property delete failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry1 != NULL) {
+ scf_entry_destroy(entry1);
+ }
+ if (entry2 != NULL) {
+ scf_entry_destroy(entry2);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsGetGroupList
+ *
+ * pgName - Property group name
+ * groupList - pointer to pointer to stmfGroupList structure. On success,
+ * contains the list of groups
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetGroupList(char *pgName, stmfGroupList **groupList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_iter_t *propIter = NULL;
+ scf_value_t *value = NULL;
+ char buf[MAXNAMELEN];
+ int memberCnt = 0;
+ int i = 0;
+ int ret = STMF_PS_SUCCESS;
+
+ assert(groupList != NULL);
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over member list properties
+ */
+ if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ memberCnt++;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
+ memberCnt * sizeof (stmfGroupName));
+
+ if (*groupList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * In order to get a list of groups, simply get all of the
+ * properties that are not member list properties, i.e. the group
+ * name properties.
+ * It's possible for this list to grow beyond what was originally
+ * read so just ensure we're not writing beyond our allocated buffer
+ * by ensuring i < memberCnt
+ */
+ while ((scf_iter_next_property(propIter, prop) == 1) &&
+ (i < memberCnt)) {
+ if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over member list properties
+ */
+ if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get ustring failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ bcopy(buf, (*groupList)->name[i++], strlen(buf));
+ (*groupList)->cnt++;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*groupList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsGetGroupMemberList
+ *
+ * pgName - Property group name
+ * groupName - group name (host group or target group)
+ * groupMemberList - pointer to pointer to stmfGroupProperties structure. On
+ * success, contains the list of group members
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetGroupMemberList(char *pgName, char *groupName,
+ stmfGroupProperties **groupMemberList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_iter_t *valueIter = NULL;
+ int i = 0;
+ int memberCnt;
+ int len;
+ int ret = STMF_PS_SUCCESS;
+ char buf[MAXNAMELEN];
+
+ assert(pgName != NULL && groupName != NULL);
+
+ /*
+ * init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL) ||
+ ((valueLookup = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * get the service property group handle
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Get the property handle
+ * based on the target or host group name
+ */
+ if (scf_pg_get_property(pg, groupName, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * valueIter is the iterator handle
+ */
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ i++;
+ }
+
+ /*
+ * valueIter is the iterator handle
+ */
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ memberCnt = i;
+
+ *groupMemberList = (stmfGroupProperties *)calloc(1,
+ sizeof (stmfGroupProperties) + memberCnt * sizeof (stmfDevid));
+ if (*groupMemberList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ i = 0;
+ while ((scf_iter_next_value(valueIter, valueLookup) == 1) &&
+ (i < memberCnt)) {
+ if ((len = scf_value_get_ustring(valueLookup, buf, MAXNAMELEN))
+ == -1) {
+ syslog(LOG_ERR, "iter value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (len < sizeof (stmfDevid) - 1) {
+ (*groupMemberList)->name[i].identLength = len;
+ bcopy(buf,
+ (*groupMemberList)->name[i++].ident, len);
+ (*groupMemberList)->cnt++;
+ } else {
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*groupMemberList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+
+ return (ret);
+}
+
+/*
+ * Initialize scf stmf service access
+ * handle - returned handle
+ * service - returned service handle
+ *
+ * Both handle and service must be destroyed by the caller
+ */
+static int
+iPsInit(scf_handle_t **handle, scf_service_t **service)
+{
+ scf_scope_t *scope = NULL;
+ uint64_t version;
+ int ret;
+
+ assert(handle != NULL && service != NULL);
+
+ if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
+ syslog(LOG_ERR, "scf_handle_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_bind(*handle) == -1) {
+ syslog(LOG_ERR, "scf_handle_bind failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if ((*service = scf_service_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_service_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if ((scope = scf_scope_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_scope_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
+ syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if (scf_scope_get_service(scope, STMF_SERVICE, *service) == -1) {
+ syslog(LOG_ERR, "scf_scope_get_service failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR_SERVICE_NOT_FOUND;
+ goto err;
+ }
+
+
+ /*
+ * Get and check the version number
+ */
+ ret = iPsGetServiceVersion(&version, *handle, *service);
+ if (ret != STMF_PS_SUCCESS) {
+ goto err;
+ }
+
+ if (version != STMF_SMF_VERSION) {
+ ret = STMF_PS_ERROR_VERSION_MISMATCH;
+ goto err;
+ }
+
+ /* we only need destroy the scope here */
+ scf_scope_destroy(scope);
+
+ return (STMF_PS_SUCCESS);
+
+err:
+ if (*handle != NULL) {
+ scf_handle_destroy(*handle);
+ }
+ if (*service != NULL) {
+ scf_service_destroy(*service);
+ *service = NULL;
+ }
+ if (scope != NULL) {
+ scf_scope_destroy(scope);
+ }
+ return (ret);
+}
+
+/*
+ * called by iPsInit only
+ * iPsGetServiceVersion
+ */
+static int
+iPsGetServiceVersion(uint64_t *version, scf_handle_t *handle,
+scf_service_t *svc)
+{
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *version = STMF_SMF_VERSION;
+
+ /*
+ * get stmf data property group
+ */
+ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* create the group */
+ if (ret == STMF_PS_ERROR_NOT_FOUND) {
+ /*
+ * create the property group.
+ */
+ if (scf_service_add_pg(svc, STMF_DATA_GROUP,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* reset return value */
+ ret = STMF_PS_SUCCESS;
+ }
+
+ /* find version property */
+ /*
+ * Get the version property
+ */
+ if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* no version property found */
+ if (ret == STMF_PS_ERROR_NOT_FOUND) {
+ /*
+ * If we have no version property, go ahead
+ * and create it. We're obviously making an assumption
+ * here that someone did not delete the existing property
+ * and that this is the initial set and the initial call
+ * to iPsInit.
+ * If they did delete it, this will simply plant this
+ * library's version on this service. That may or may not be
+ * correct and we have no way of determining that.
+ */
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_transaction_property_new(tran, entry,
+ STMF_VERSION_NAME, SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR,
+ "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * set the version number
+ */
+ scf_value_set_count(value, *version);
+
+ /*
+ * add the value to the transaction
+ */
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ /* reset return value */
+ ret = STMF_PS_SUCCESS;
+ } else {
+ /* get the version property */
+ if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the actual value of the view entry count property
+ */
+ if (scf_value_get_count(value, version) == -1) {
+ syslog(LOG_ERR, "get count value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+out:
+ /*
+ * Free resources.
+ * handle and svc should not be free'd here. They're
+ * free'd elsewhere
+ */
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ return (ret);
+}
+
+
+
+/*
+ * iPsGetActualGroupName
+ *
+ * pgName - Property group name
+ * groupName - requested group name
+ * actualName - actual group name to reference (len must be >= MAXNAMELEN)
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetActualGroupName(char *pgName, char *groupName, char *actualName)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_iter_t *propIter = NULL;
+ scf_value_t *value = NULL;
+ char buf[MAXNAMELEN];
+ int ret;
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * get group list property group
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Iterate through group properties searching for the requested
+ * group name. When we find it, we need to get the property name
+ * since it refers to the actual group name.
+ */
+
+ /* initialize to not found */
+ ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ if (scf_property_get_name(prop, actualName, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over non-member list properties
+ */
+ if (strstr(actualName, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get ustring failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * When we find a match, set success and break
+ */
+ if ((strlen(buf) == strlen(groupName)) &&
+ bcmp(buf, groupName, strlen(buf)) == 0) {
+ ret = STMF_PS_SUCCESS;
+ break;
+ }
+ }
+
+ /*
+ * if we didn't find it, ret is set to STMF_PS_ERROR_GROUP_NOT_FOUND
+ */
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * psAddHostGroupMember
+ *
+ * Add a host group member to a host group,
+ *
+ * Input: groupName - name of group to which the member is added
+ * memberName - name of group member to add
+ */
+int
+psAddHostGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
+ memberName, ADD));
+}
+
+/*
+ * psAddTargetGroupMember
+ *
+ * Add a target port group member to a target group
+ *
+ * Input: groupName - name of group to which the member is added
+ * memberName - name of group member to add. Must be nul terminated.
+ */
+int
+psAddTargetGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
+ memberName, ADD));
+}
+
+
+/*
+ * psAddViewEntry
+ *
+ * luGuid - logical unit identifier
+ * viewEntry - pointer to viewEntry allocated by the caller that contains
+ * the values to set for this view entry
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char scfLuPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+ sigset_t sigmaskRestore;
+
+ /* grab the signal hold lock */
+ (void) pthread_mutex_lock(&sigSetLock);
+
+ /*
+ * hold signals until we're done
+ */
+ if (holdSignal(&sigmaskRestore) != 0) {
+ (void) pthread_mutex_unlock(&sigSetLock);
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ pg = scf_pg_create(handle);
+ if (pg == NULL) {
+ syslog(LOG_ERR, "scf pg alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ (void) snprintf(scfLuPgName, sizeof (scfLuPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ bzero(viewEntryPgName, sizeof (viewEntryPgName));
+ /*
+ * Format of view entry property group name:
+ * VE-<view_entry_name>-<lu_name>
+ */
+ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
+ "%s-%d-%s", STMF_VE_PREFIX, viewEntry->veIndex, guidAsciiBuf);
+
+ ret = iPsAddViewEntry(scfLuPgName, viewEntryPgName, viewEntry);
+
+out:
+ /*
+ * Okay, we're done. Release the signals
+ */
+ if (releaseSignal(&sigmaskRestore) != 0) {
+ /*
+ * Don't set this as an STMF_PS_ERROR_*. We succeeded
+ * the requested operation. But we do need to log it.
+ */
+ syslog(LOG_ERR, "Unable to release one or more signals - %s",
+ strerror(errno));
+ }
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ /* release the signal hold lock */
+ (void) pthread_mutex_unlock(&sigSetLock);
+
+ return (ret);
+}
+
+/*
+ * psCheckService
+ *
+ * Purpose: Checks whether service exists
+ *
+ */
+int
+psCheckService()
+{
+ int ret;
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+
+ ret = iPsInit(&handle, &svc);
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+
+ return (ret);
+}
+
+/*
+ * psCreateHostGroup
+ *
+ * groupName - name of group to create
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psCreateHostGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, ADD));
+}
+
+/*
+ * psCreateTargetGroup
+ *
+ * groupName - name of group to create
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psCreateTargetGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, ADD));
+}
+
+/*
+ * psDeleteHostGroup
+ *
+ * groupName - name of group to delete
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psDeleteHostGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, REMOVE));
+}
+
+/*
+ * psDeleteTargetGroup
+ *
+ * groupName - name of group to delete
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psDeleteTargetGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName,
+ REMOVE));
+}
+
+/*
+ * psGetHostGroupList
+ *
+ * groupList - pointer to pointer to stmfGroupList. Contains the list
+ * of host groups on successful return.
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetHostGroupList(stmfGroupList **groupList)
+{
+ return (iPsGetGroupList(STMF_HOST_GROUPS, groupList));
+}
+
+/*
+ * psGetLogicalUnitList
+ *
+ *
+ */
+int
+psGetLogicalUnitList(stmfGuidList **guidList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_iter_t *pgIter = NULL;
+ char buf[MAXNAMELEN];
+ int guidCnt = 0;
+ int i = 0, j;
+ int ret = STMF_PS_SUCCESS;
+ unsigned int guid[sizeof (stmfGuid)];
+ stmfGuid outGuid;
+
+ assert(guidList != NULL);
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((pgIter = scf_iter_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_pg(pgIter, pg) == 1) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only count LU property groups
+ */
+ if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) == 0) {
+ guidCnt++;
+ }
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *guidList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
+ guidCnt * sizeof (stmfGuid));
+ if (*guidList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * it's possible for entries to be added/removed while we're retrieving
+ * the property groups. Just make sure we don't write beyond our
+ * allocated buffer by checking to ensure i < guidCnt.
+ */
+ while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < guidCnt)) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only use LU property groups
+ */
+ if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) != 0) {
+ continue;
+ }
+
+ j = strlen(STMF_LU_PREFIX) + strlen("-");
+
+ (void) sscanf(buf + j,
+ "%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 (j = 0; j < sizeof (stmfGuid); j++) {
+ outGuid.guid[j] = guid[j];
+ }
+
+ bcopy(&outGuid, (*guidList)->guid[i++].guid, sizeof (stmfGuid));
+ (*guidList)->cnt++;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*guidList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (pgIter != NULL) {
+ scf_iter_destroy(pgIter);
+ }
+
+ return (ret);
+}
+
+/*
+ * psGetTargetGroupList
+ *
+ * groupList - pointer to pointer to stmfGroupList. Contains the list
+ * of target groups on successful return.
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetTargetGroupList(stmfGroupList **groupList)
+{
+ return (iPsGetGroupList(STMF_TARGET_GROUPS, groupList));
+}
+
+/*
+ * psGetHostGroupMemberList
+ *
+ * groupName - group name for which to retrieve a member list
+ * groupMemberList - pointer to pointer to stmfGroupProperties list
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsGetGroupMemberList(STMF_HOST_GROUPS, groupPropListName,
+ groupMemberList));
+}
+
+/*
+ * psGetTargetGroupMemberList
+ *
+ * groupName - group name for which to retrieve a member list
+ * groupMemberList - pointer to pointer to stmfGroupProperties list
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetTargetGroupMemberList(char *groupName,
+ stmfGroupProperties **groupMemberList)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsGetGroupMemberList(STMF_TARGET_GROUPS,
+ groupPropListName, groupMemberList));
+}
+
+/*
+ * 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);
+}
+
+/*
+ * psGetViewEntryList
+ *
+ * luGuid - identifier of logical unit for which to retrieve a view entry list
+ * viewEntryList - pointer to pointer to stmfViewEntryList. It will be allocated
+ * on successful return.
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_iter_t *propIter = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char luPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+ uint64_t i = 0;
+ uint64_t veCnt;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ /* form the LU property group name (LU-<guid>) */
+ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ /* get the property group associated with this LU */
+ if (scf_service_get_pg(svc, luPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /* get the view entry count property */
+ if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the actual value of the view entry count property
+ */
+ if (scf_value_get_count(value, &veCnt) == -1) {
+ syslog(LOG_ERR, "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * alloc the list based on the view entry count
+ */
+ *viewEntryList = (stmfViewEntryList *)calloc(1,
+ sizeof (stmfViewEntryList) + veCnt * sizeof (stmfViewEntry));
+ if (*viewEntryList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ i = 0;
+ /*
+ * iterate through the view entry properties to find the
+ * view entries
+ */
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ /* find match for view entry property */
+ if (scf_property_get_name(prop, viewEntryPgName,
+ sizeof (viewEntryPgName)) != -1) {
+ if (strncmp(viewEntryPgName, STMF_VE_PREFIX,
+ strlen(STMF_VE_PREFIX)) != 0) {
+ continue;
+ }
+ /*
+ * We've exceeded our alloc limit
+ * break with error
+ */
+ if (i == veCnt) {
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ if ((ret = iPsGetViewEntry(viewEntryPgName,
+ &((*viewEntryList)->ve[i]))) != STMF_PS_SUCCESS) {
+ break;
+ }
+
+ i++;
+
+ /* set the list count */
+ (*viewEntryList)->cnt++;
+ } else {
+ syslog(LOG_ERR, "scf pg iter service failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*viewEntryList);
+ goto out;
+ }
+
+ /*
+ * We're sorting the final list here based on the veIndex
+ * If we don't, the caller is going to have to do it to reap
+ * some intelligent output.
+ */
+ qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
+ sizeof (stmfViewEntry), viewEntryCompare);
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsGetViewEntry
+ *
+ * viewEntryPgName - view entry property group name to retrieve
+ * viewEntry - pointer to stmfViewEntry structure allocated by the caller
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetViewEntry(char *viewEntryPgName, stmfViewEntry *viewEntry)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ uint8_t scfBool;
+ char *indexPtr;
+ char groupName[sizeof (stmfGroupName)];
+ int ret = STMF_PS_SUCCESS;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ bzero(viewEntry, sizeof (stmfViewEntry));
+
+ /*
+ * get the service property group view entry handle
+ */
+ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+
+ /*
+ * get index
+ * format is: VE-<veIndex>-GUID
+ */
+ indexPtr = strchr(viewEntryPgName, '-');
+ if (!indexPtr) {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Set the index */
+ viewEntry->veIndex = atoi(strtok(++indexPtr, "-"));
+
+ viewEntry->veIndexValid = B_TRUE;
+
+ /* get allHosts property */
+ if (scf_pg_get_property(pg, STMF_VE_ALLHOSTS,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* set allHosts */
+ if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ viewEntry->allHosts = scfBool;
+
+ /* get hostGroup property */
+ if (scf_pg_get_property(pg, STMF_VE_HOSTGROUP,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_get_ustring(value, groupName,
+ sizeof (groupName)) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* set hostGroup */
+ bcopy(groupName, viewEntry->hostGroup, strlen(groupName));
+
+ /* get allTargets property */
+ if (scf_pg_get_property(pg, STMF_VE_ALLTARGETS,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* set allTargets */
+ if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ viewEntry->allTargets = scfBool;
+
+ /* get targetGroup property */
+ if (scf_pg_get_property(pg, STMF_VE_TARGETGROUP, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_get_ustring(value, groupName,
+ sizeof (groupName)) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* set targetGroup */
+ bcopy(groupName, viewEntry->targetGroup, strlen(groupName));
+
+ /* get luNbr property */
+ if (scf_pg_get_property(pg, STMF_VE_LUNBR,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* set luNbr */
+ if (scf_value_get_opaque(value, (char *)viewEntry->luNbr,
+ sizeof (viewEntry->luNbr)) == -1) {
+ syslog(LOG_ERR, "get opaque value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* set luNbrValid to true since we just got it */
+ viewEntry->luNbrValid = B_TRUE;
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+
+ return (ret);
+}
+
+
+/*
+ * psRemoveHostGroupMember
+ *
+ * Remove a host group member from a host group,
+ *
+ * groupName - name of group from which the member is removed
+ * memberName - name of group member to remove
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psRemoveHostGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
+ memberName, REMOVE));
+}
+
+/*
+ * psRemoveTargetGroupMember
+ *
+ * Remove a target port group member from an target port group,
+ *
+ * groupName - name of group from which the member is removed
+ * memberName - name of group member to remove
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psRemoveTargetGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
+ memberName, REMOVE));
+}
+
+/*
+ * psGetProviderData
+ *
+ * Retrieves an nvlist on a per provider basis
+ *
+ * providerName - property group name to use
+ * nvl - nvlist to retrieve
+ *
+ */
+int
+psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ uint64_t blockCnt = 0;
+ ssize_t blockOffset = 0;
+ ssize_t actualBlockSize = 0;
+ char pgName[MAXPATHLEN];
+ char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
+ char *nvlistEncoded = NULL;
+ ssize_t nvlistEncodedSize = 0;
+ boolean_t foundSetCnt = B_TRUE;
+ int i;
+ int ret = STMF_PS_SUCCESS;
+
+ if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE)) {
+ ret = STMF_PS_ERROR_INVALID_ARG;
+ goto out;
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * create the property group name
+ */
+ (void) snprintf(pgName, sizeof (pgName), "%s%s",
+ STMF_PROVIDER_DATA_PREFIX, providerName);
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Retrieve the existing property group.
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ goto out;
+ }
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT property
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value, &blockCnt) == -1) {
+ syslog(LOG_ERR, "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Has the caller requested the token to be set? */
+ if (setToken) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
+ * If it doesn't exist, we assume it to be zero.
+ */
+ *setToken = 0;
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ foundSetCnt = B_FALSE;
+ } else {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (foundSetCnt) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR,
+ "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ * and set the caller's token
+ */
+ if (scf_value_get_count(value, setToken) == -1) {
+ syslog(LOG_ERR,
+ "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ }
+
+ nvlistEncoded = (char *)calloc(1,
+ blockCnt * STMF_PROVIDER_DATA_PROP_SIZE);
+ if (nvlistEncoded == NULL) {
+ syslog(LOG_ERR, "nvlistEncoded alloc failed");
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < blockCnt; i++) {
+ bzero(dataPropertyName, sizeof (dataPropertyName));
+ /*
+ * create the name to use for the property
+ */
+ (void) snprintf(dataPropertyName, sizeof (dataPropertyName),
+ "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
+
+ if (scf_pg_get_property(pg, dataPropertyName, prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Set the data block offset
+ */
+ blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
+ actualBlockSize = scf_value_get_opaque(value,
+ &nvlistEncoded[blockOffset], STMF_PROVIDER_DATA_PROP_SIZE);
+ if (actualBlockSize == -1) {
+ syslog(LOG_ERR, "get opaque property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ nvlistEncodedSize += actualBlockSize;
+ }
+
+ if (nvlist_unpack(nvlistEncoded, nvlistEncodedSize, nvl, 0) != 0) {
+ syslog(LOG_ERR, "unable to unpack nvlist");
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (nvlistEncoded != NULL) {
+ free(nvlistEncoded);
+ }
+
+ return (ret);
+
+}
+/*
+ * psGetProviderDataList
+ *
+ * Retrieves the list of providers that currently store persistent data
+ *
+ * providerList - pointer to a pointer to an stmfProviderList structure
+ * On success, this will contain the list of providers
+ * currently storing persistent data.
+ */
+int
+psGetProviderDataList(stmfProviderList **providerList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_iter_t *pgIter = NULL;
+ char buf[MAXNAMELEN];
+ int providerCnt = 0;
+ int64_t providerType;
+ int i = 0, j;
+ int ret = STMF_PS_SUCCESS;
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ *providerList = NULL;
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((pgIter = scf_iter_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_pg(pgIter, pg) == 1) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only count LU property groups
+ */
+ if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
+ strlen(STMF_PROVIDER_DATA_PREFIX)) == 0) {
+ providerCnt++;
+ }
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *providerList = (stmfProviderList *)calloc(1,
+ sizeof (stmfProviderList) + providerCnt * sizeof (stmfProvider));
+ if (*providerList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * it's possible for entries to be added/removed while we're retrieving
+ * the property groups. Just make sure we don't write beyond our
+ * allocated buffer by checking to ensure i < providerCnt.
+ */
+ while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < providerCnt)) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only use provider data property groups
+ */
+ if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
+ strlen(STMF_PROVIDER_DATA_PREFIX)) != 0) {
+ continue;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_TYPE property
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_TYPE,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_TYPE value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_integer(value, &providerType) == -1) {
+ syslog(LOG_ERR, "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ (*providerList)->provider[i].providerType = providerType;
+
+ /* determine offset for copy of provider name */
+ j = strlen(STMF_PROVIDER_DATA_PREFIX);
+
+ /* copy provider name to caller's list */
+ (void) strncpy((*providerList)->provider[i].name, buf + j,
+ sizeof ((*providerList)->provider[i].name));
+ i++;
+ (*providerList)->cnt++;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*providerList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (pgIter != NULL) {
+ scf_iter_destroy(pgIter);
+ }
+
+ return (ret);
+}
+
+
+/*
+ * psSetProviderData
+ *
+ * Stores a packed nvlist on a per provider basis
+ *
+ * providerName - property group name to use
+ * nvl - nvlist to store
+ * providerType - type of provider (logical unit or port)
+ *
+ */
+int
+psSetProviderData(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_transaction_t *tran = NULL;
+ /* represents arrays of entry and value pointers for scf */
+ scf_transaction_entry_t **addEntry = NULL;
+ scf_transaction_entry_t **deleteEntry = NULL;
+ scf_value_t **addValue = NULL;
+
+ /*
+ * These declarations are for known entry and value set/get
+ * operations
+ */
+ scf_transaction_entry_t *entry1 = NULL;
+ scf_transaction_entry_t *entry2 = NULL;
+ scf_transaction_entry_t *entry3 = NULL;
+ scf_transaction_entry_t *entry5 = NULL;
+ scf_value_t *value1 = NULL;
+ scf_value_t *value2 = NULL;
+ scf_value_t *value3 = NULL;
+ scf_value_t *value4 = NULL;
+ scf_value_t *value5 = NULL;
+
+ boolean_t newPg = B_FALSE;
+ char pgName[MAXPATHLEN];
+ char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
+ char *nvlistEncoded = NULL;
+ size_t nvlistEncodedSize;
+ size_t blockSize;
+ int i, j = 0;
+ int addEntryAlloc = 0, deleteEntryAlloc = 0, addValueAlloc = 0;
+ int blockOffset;
+ uint64_t oldBlockCnt = 0;
+ uint64_t blockCnt = 0;
+ uint64_t setCnt = 0;
+ boolean_t foundSetCnt = B_TRUE;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE)) {
+ ret = STMF_PS_ERROR_INVALID_ARG;
+ goto out;
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ bzero(pgName, sizeof (pgName));
+ /*
+ * create the property group name
+ */
+ (void) snprintf(pgName, sizeof (pgName), "%s%s",
+ STMF_PROVIDER_DATA_PREFIX, providerName);
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((entry1 = scf_entry_create(handle)) == NULL) ||
+ ((entry2 = scf_entry_create(handle)) == NULL) ||
+ ((entry3 = scf_entry_create(handle)) == NULL) ||
+ ((entry5 = scf_entry_create(handle)) == NULL) ||
+ ((value1 = scf_value_create(handle)) == NULL) ||
+ ((value2 = scf_value_create(handle)) == NULL) ||
+ ((value3 = scf_value_create(handle)) == NULL) ||
+ ((value4 = scf_value_create(handle)) == NULL) ||
+ ((value5 = scf_value_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the existing property group
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ /*
+ * create the property group.
+ */
+ if (scf_service_add_pg(svc, pgName,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ newPg = B_TRUE;
+ }
+ }
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (!newPg) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT property
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT value
+ */
+ if (scf_property_get_value(prop, value4) == -1) {
+ syslog(LOG_ERR, "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value4, &oldBlockCnt) == -1) {
+ syslog(LOG_ERR, "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
+ * If it doesn't exist, we'll create it later after successfully
+ * setting the data.
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ foundSetCnt = B_FALSE;
+ } else {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (foundSetCnt) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
+ */
+ if (scf_property_get_value(prop, value5) == -1) {
+ syslog(LOG_ERR,
+ "get property value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value5, &setCnt) == -1) {
+ syslog(LOG_ERR,
+ "get integer value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Compare the setCnt prop to the caller's.
+ */
+ if (setToken && (*setToken != setCnt)) {
+ ret = STMF_PS_ERROR_PROV_DATA_STALE;
+ goto out;
+ }
+ }
+
+ setCnt++;
+
+ /*
+ * prepare the list for writing
+ */
+ if (nvlist_pack(nvl, &nvlistEncoded, &nvlistEncodedSize,
+ NV_ENCODE_XDR, 0) != 0) {
+ syslog(LOG_ERR, "nvlist_pack failed");
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /* Determine how many chunks we need to write */
+ blockCnt = nvlistEncodedSize/STMF_PROVIDER_DATA_PROP_SIZE;
+ if (nvlistEncodedSize % STMF_PROVIDER_DATA_PROP_SIZE)
+ blockCnt++;
+
+ /* allocate entry and value resources for writing those chunks */
+ addEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*addEntry)
+ * blockCnt);
+ if (addEntry == NULL) {
+ syslog(LOG_ERR, "addEntry alloc failed");
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ addValue = (scf_value_t **)calloc(1, sizeof (*addValue)
+ * blockCnt);
+ if (addValue == NULL) {
+ syslog(LOG_ERR, "value alloc failed");
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * allocate entry delete resources for deleting anything existing
+ * that is more than the new block count. We could leave them around
+ * without suffering any ill effects but it will be cleaner to look at
+ * in smf tools if they are deleted.
+ */
+ if (oldBlockCnt > blockCnt) {
+ deleteEntry = (scf_transaction_entry_t **)calloc(1,
+ sizeof (*deleteEntry) * (oldBlockCnt - blockCnt));
+ if (deleteEntry == NULL) {
+ syslog(LOG_ERR, "deleteEntry alloc failed");
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+ deleteEntryAlloc = oldBlockCnt - blockCnt;
+ }
+
+
+ for (i = 0; i < blockCnt; i++) {
+ /*
+ * Create the entry resource for the prop
+ */
+ addEntry[i] = scf_entry_create(handle);
+ if (addEntry[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* bump alloc count for addEntry allocation */
+ addEntryAlloc++;
+
+ /*
+ * create the name to use for the property
+ */
+ (void) snprintf(dataPropertyName, sizeof (dataPropertyName),
+ "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
+
+ /*
+ * Create the new property
+ */
+ if (scf_transaction_property_new(tran, addEntry[i],
+ dataPropertyName, SCF_TYPE_OPAQUE) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran,
+ addEntry[i], dataPropertyName,
+ SCF_TYPE_OPAQUE) == -1) {
+ syslog(LOG_ERR, "transaction property"
+ "change failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ /*
+ * Create the value resource for the prop
+ */
+ addValue[i] = scf_value_create(handle);
+ if (addValue[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* bump alloc count for addValue allocation */
+ addValueAlloc++;
+
+ /*
+ * Set the data block offset and size
+ */
+ if ((STMF_PROVIDER_DATA_PROP_SIZE * (i + 1))
+ > nvlistEncodedSize) {
+ blockSize = nvlistEncodedSize
+ - STMF_PROVIDER_DATA_PROP_SIZE * i;
+ } else {
+ blockSize = STMF_PROVIDER_DATA_PROP_SIZE;
+ }
+
+ blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
+ if (scf_value_set_opaque(addValue[i],
+ &nvlistEncoded[blockOffset], blockSize) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the data block to the transaction entry
+ */
+ if (scf_entry_add_value(addEntry[i], addValue[i]) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * Now we need to delete any chunks (properties) that are no longer
+ * needed. Iterate through the rest of the chunks deleting each.
+ */
+ for (i = blockCnt; i < oldBlockCnt; i++) {
+ /*
+ * Create the entry resource for the prop
+ */
+ deleteEntry[j] = scf_entry_create(handle);
+ if (deleteEntry[j] == NULL) {
+ syslog(LOG_ERR, "scf value alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * create the name to use for the property
+ */
+ (void) snprintf(dataPropertyName, sizeof (dataPropertyName),
+ "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
+
+ /*
+ * Delete the existing property
+ */
+ if (scf_transaction_property_delete(tran, deleteEntry[j++],
+ dataPropertyName) == -1) {
+ syslog(LOG_ERR, "get property failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (newPg) {
+ /*
+ * Ensure the read_authorization property is set
+ * for the group
+ */
+ if (scf_transaction_property_new(tran, entry1,
+ "read_authorization", SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_set_astring(value1, STMF_SMF_READ_ATTR) == -1) {
+ syslog(LOG_ERR, "set value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_entry_add_value(entry1, value1) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* create or change the count property */
+ if (scf_transaction_property_new(tran, entry2,
+ STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran, entry2,
+ STMF_PROVIDER_DATA_PROP_COUNT,
+ SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ scf_value_set_count(value2, blockCnt);
+
+ if (scf_entry_add_value(entry2, value2) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* create or change the set count property */
+ if (scf_transaction_property_new(tran, entry5,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran, entry5,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+
+
+ scf_value_set_count(value5, setCnt);
+
+ if (scf_entry_add_value(entry5, value5) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* create or change the provider type property */
+ if (scf_transaction_property_new(tran, entry3,
+ STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran, entry3,
+ STMF_PROVIDER_DATA_PROP_TYPE,
+ SCF_TYPE_INTEGER) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ switch (providerType) {
+ case STMF_PORT_PROVIDER_TYPE:
+ case STMF_LU_PROVIDER_TYPE:
+ scf_value_set_integer(value3, providerType);
+ break;
+ default:
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_entry_add_value(entry3, value3) == -1) {
+ syslog(LOG_ERR, "add value failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit failed - %s",
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /* pass the new token back to the caller if requested */
+ if (ret == STMF_PS_SUCCESS && setToken) {
+ *setToken = setCnt;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ for (i = 0; i < addEntryAlloc; i++) {
+ scf_entry_destroy(addEntry[i]);
+ }
+ for (i = 0; i < addValueAlloc; i++) {
+ scf_value_destroy(addValue[i]);
+ }
+ free(addValue);
+ free(addEntry);
+ for (i = 0; i < deleteEntryAlloc; i++) {
+ scf_entry_destroy(deleteEntry[i]);
+ }
+ free(deleteEntry);
+ if (entry1 != NULL) {
+ scf_entry_destroy(entry1);
+ }
+ if (entry2 != NULL) {
+ scf_entry_destroy(entry2);
+ }
+ if (entry3 != NULL) {
+ scf_entry_destroy(entry3);
+ }
+ if (entry5 != NULL) {
+ scf_entry_destroy(entry5);
+ }
+ if (value1 != NULL) {
+ scf_value_destroy(value1);
+ }
+ if (value2 != NULL) {
+ scf_value_destroy(value2);
+ }
+ if (value3 != NULL) {
+ scf_value_destroy(value3);
+ }
+ if (value4 != NULL) {
+ scf_value_destroy(value4);
+ }
+ if (value5 != NULL) {
+ scf_value_destroy(value5);
+ }
+ if (nvlistEncoded != NULL) {
+ free(nvlistEncoded);
+ }
+
+ return (ret);
+}
+
+/*
+ * psGetViewEntry
+ *
+ * Purpose: Get a single view entry based on the logical unit identifier and
+ * view entry index
+ *
+ * lu - logical unit identifier
+ * viewEntryIndex - index of view entry
+ * ve - caller allocated stmfViewEntry structure. On success, this will
+ * contain the retrieved view entry
+ */
+int
+psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char luPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ pg = scf_pg_create(handle);
+ if (pg == NULL) {
+ syslog(LOG_ERR, "scf pg alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ /*
+ * Format of view entry property group name:
+ * VE-<view_entry_index>-<lu_name>
+ */
+ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
+ "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
+
+ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+
+ if ((ret = iPsGetViewEntry(viewEntryPgName, ve)) != STMF_PS_SUCCESS) {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ return (ret);
+}
+
+/*
+ * psRemoveViewEntry
+ *
+ * Remove a view entry
+ *
+ * luGuid - identifier of logical unit from which to remove view entry
+ * viewEntryIndex - view entry name to remove
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char luPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+ sigset_t sigmaskRestore;
+
+ /* grab the signal hold lock */
+ (void) pthread_mutex_lock(&sigSetLock);
+
+ /*
+ * hold signals until we're done
+ */
+ if (holdSignal(&sigmaskRestore) != 0) {
+ (void) pthread_mutex_unlock(&sigSetLock);
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ pg = scf_pg_create(handle);
+ if (pg == NULL) {
+ syslog(LOG_ERR, "scf pg alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ /*
+ * Format of view entry property group name:
+ * VE-<view_entry_index>-<lu_name>
+ */
+ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
+ "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
+
+ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * update the logical unit property group to remove
+ * the view entry and update the view entry count
+ * If it fails, we won't delete the property group so that
+ * we maintain consistency.
+ */
+ if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ REMOVE)) != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Delete the view entry. If this fails, we should try to add
+ * the logical unit view entry property group back otherwise
+ * we're inconsistent.
+ */
+ if (scf_pg_delete(pg) == -1) {
+ syslog(LOG_ERR, "delete pg failed - %s",
+ scf_strerror(scf_error()));
+ if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ ADD)) != STMF_PS_SUCCESS) {
+ syslog(LOG_ERR, "add of view entry failed, possible"
+ "inconsistency - %s", scf_strerror(scf_error()));
+ }
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+out:
+ /*
+ * Okay, we're done. Release the signals
+ */
+ if (releaseSignal(&sigmaskRestore) != 0) {
+ /*
+ * Don't set this as an STMF_PS_ERROR_*. We succeeded
+ * the requested operation. But we do need to log it.
+ */
+ syslog(LOG_ERR, "Unable to release one or more signals - %s",
+ strerror(errno));
+ }
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ /* release the signal hold lock */
+ (void) pthread_mutex_unlock(&sigSetLock);
+
+ return (ret);
+}
+
+
+
+/*
+ * holdSignal
+ *
+ * Hold SIGINT, SIGTERM, SIGQUIT until further notice.
+ *
+ * Saves old signal mask on a per thread basis
+ * and saves action for the process.
+ *
+ * Installs action for above signals.
+ *
+ * locks held: sigSetLock
+ *
+ * returns:
+ * 0 on success
+ * non-zero otherwise
+ */
+static int
+holdSignal(sigset_t *sigmaskRestore)
+{
+ struct sigaction act;
+ sigset_t sigmask;
+
+ /*
+ * Return existing signal mask for this thread
+ */
+ if (pthread_sigmask(0, NULL, sigmaskRestore) != 0) {
+ return (1);
+ }
+
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_handler = sigHandler;
+ act.sa_flags = 0;
+
+ /*
+ * Have we set the actions for the signals we want to catch?
+ */
+ if (!actionSet) {
+ if (sigaction(SIGQUIT, &act, &currentActionQuit) != 0) {
+ return (1);
+ }
+
+ if (sigaction(SIGINT, &act, &currentActionInt) != 0) {
+ return (1);
+ }
+
+ if (sigaction(SIGTERM, &act, &currentActionTerm) != 0) {
+ return (1);
+ }
+
+ actionSet = B_TRUE;
+ }
+
+ /*
+ * We still need to change the mask for the current thread
+ */
+ if (sigfillset(&sigmask) != 0) {
+ return (1);
+ }
+
+ (void) sigdelset(&sigmask, SIGQUIT);
+
+ (void) sigdelset(&sigmask, SIGINT);
+
+ (void) sigdelset(&sigmask, SIGTERM);
+
+ if (pthread_sigmask(SIG_SETMASK, &sigmask, NULL) != 0) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * releaseSignal
+ *
+ * Re-install the original signal mask and signal actions
+ *
+ * Also, raise any signals that were caught during the hold period and clear
+ * the signal from the caught set (signalsCaught).
+ *
+ * locks held: sigSetLock
+ *
+ * Returns
+ * 0 on success
+ * non-zero otherwise
+ */
+static int
+releaseSignal(sigset_t *sigmaskRestore)
+{
+ int ret = 0;
+
+ if (sigaction(SIGQUIT, &currentActionQuit, NULL) != 0) {
+ ret = 1;
+ }
+
+ if (sigaction(SIGINT, &currentActionInt, NULL) != 0) {
+ ret = 1;
+ }
+
+ if (sigaction(SIGTERM, &currentActionTerm, NULL) != 0) {
+ ret = 1;
+ }
+
+ actionSet = B_FALSE;
+
+ /*
+ * Restore previous signal mask for this thread
+ */
+ if (pthread_sigmask(SIG_SETMASK, sigmaskRestore, NULL) != 0) {
+ syslog(LOG_ERR, "Unable to restore sigmask");
+ }
+
+ /*
+ * Now raise signals that were raised while we were held
+ */
+ if (sigismember(&signalsCaught, SIGTERM)) {
+ (void) sigdelset(&signalsCaught, SIGTERM);
+ (void) raise(SIGTERM);
+ }
+
+ if (sigismember(&signalsCaught, SIGINT)) {
+ (void) sigdelset(&signalsCaught, SIGINT);
+ (void) raise(SIGINT);
+ }
+
+ if (sigismember(&signalsCaught, SIGQUIT)) {
+ (void) sigdelset(&signalsCaught, SIGQUIT);
+ (void) raise(SIGQUIT);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libstmf/common/store.h b/usr/src/lib/libstmf/common/store.h
new file mode 100644
index 0000000000..2f19963755
--- /dev/null
+++ b/usr/src/lib/libstmf/common/store.h
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _STORE_H
+#define _STORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libnvpair.h>
+
+/*
+ * Error defines
+ */
+#define STMF_PS_SUCCESS 0
+#define STMF_PS_ERROR 1
+#define STMF_PS_ERROR_MEMBER_NOT_FOUND 2
+#define STMF_PS_ERROR_GROUP_NOT_FOUND 3
+#define STMF_PS_ERROR_NOT_FOUND 4
+#define STMF_PS_ERROR_EXISTS 5
+#define STMF_PS_ERROR_NOMEM 6
+#define STMF_PS_ERROR_RETRY 7
+#define STMF_PS_ERROR_BUSY 8
+#define STMF_PS_ERROR_SERVICE_NOT_FOUND 9
+#define STMF_PS_ERROR_INVALID_ARG 10
+#define STMF_PS_ERROR_VERSION_MISMATCH 11
+#define STMF_PS_ERROR_PROV_DATA_STALE 12
+
+int psAddHostGroupMember(char *groupName, char *memberName);
+int psAddTargetGroupMember(char *groupName, char *memberName);
+int psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry);
+int psCreateHostGroup(char *groupName);
+int psDeleteHostGroup(char *groupName);
+int psCreateTargetGroup(char *groupName);
+int psDeleteTargetGroup(char *groupName);
+int psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve);
+int psGetLogicalUnitList(stmfGuidList **guidList);
+int psRemoveHostGroupMember(char *groupName, char *memberName);
+int psRemoveTargetGroupMember(char *groupName, char *memberName);
+int psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex);
+int psGetHostGroupList(stmfGroupList **groupList);
+int psGetTargetGroupList(stmfGroupList **groupList);
+int psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupList);
+int psGetTargetGroupMemberList(char *groupName,
+ stmfGroupProperties **groupList);
+int psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList);
+int psCheckService();
+int psSetProviderData(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setHandle);
+int psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setHandle);
+int psGetProviderDataList(stmfProviderList **providerList);
+int psClearProviderData(char *providerName, int providerType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STORE_H */