summaryrefslogtreecommitdiff
path: root/usr/src/lib/libstmf
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libstmf')
-rw-r--r--usr/src/lib/libstmf/common/libstmf.h392
-rw-r--r--usr/src/lib/libstmf/common/libstmf_impl.h80
-rw-r--r--usr/src/lib/libstmf/common/stmf.c6949
-rw-r--r--usr/src/lib/libstmf/common/store.c5385
-rw-r--r--usr/src/lib/libstmf/common/store.h84
5 files changed, 12890 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 0000000..f9d05ad
--- /dev/null
+++ b/usr/src/lib/libstmf/common/libstmf.h
@@ -0,0 +1,392 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#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_DEFAULT_LU_STATE 18
+#define STMF_DEFAULT_TARGET_PORT_STATE 19
+
+#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)
+#define STMF_ERROR_NO_PROP (STMF_STATUS_ERROR | 0x14)
+#define STMF_ERROR_NO_PROP_VAL (STMF_STATUS_ERROR | 0x15)
+#define STMF_ERROR_MISSING_PROP_VAL (STMF_STATUS_ERROR | 0x16)
+#define STMF_ERROR_INVALID_BLOCKSIZE (STMF_STATUS_ERROR | 0x17)
+#define STMF_ERROR_FILE_ALREADY (STMF_STATUS_ERROR | 0x18)
+#define STMF_ERROR_INVALID_PROPSIZE (STMF_STATUS_ERROR | 0x19)
+#define STMF_ERROR_INVALID_PROP (STMF_STATUS_ERROR | 0x20)
+#define STMF_ERROR_PERSIST_TYPE (STMF_STATUS_ERROR | 0x21)
+#define STMF_ERROR_TG_ONLINE (STMF_STATUS_ERROR | 0x22)
+#define STMF_ERROR_ACCESS_STATE_SET (STMF_STATUS_ERROR | 0x23)
+#define STMF_ERROR_NO_PROP_STANDBY (STMF_STATUS_ERROR | 0x24)
+#define STMF_ERROR_POST_MSG_FAILED (STMF_STATUS_ERROR | 0x25)
+#define STMF_ERROR_DOOR_INSTALLED (STMF_STATUS_ERROR | 0x26)
+
+/* Failures for stmfCreateLu */
+#define STMF_ERROR_FILE_IN_USE (STMF_STATUS_ERROR | 0x100)
+#define STMF_ERROR_INVALID_BLKSIZE (STMF_STATUS_ERROR | 0x101)
+#define STMF_ERROR_GUID_IN_USE (STMF_STATUS_ERROR | 0x102)
+#define STMF_ERROR_META_FILE_NAME (STMF_STATUS_ERROR | 0x103)
+#define STMF_ERROR_DATA_FILE_NAME (STMF_STATUS_ERROR | 0x104)
+#define STMF_ERROR_SIZE_OUT_OF_RANGE (STMF_STATUS_ERROR | 0x105)
+#define STMF_ERROR_LU_BUSY (STMF_STATUS_ERROR | 0x106)
+#define STMF_ERROR_META_CREATION (STMF_STATUS_ERROR | 0x107)
+#define STMF_ERROR_FILE_SIZE_INVALID (STMF_STATUS_ERROR | 0x108)
+#define STMF_ERROR_WRITE_CACHE_SET (STMF_STATUS_ERROR | 0x109)
+
+/* Initiator Name Types */
+#define STMF_FC_PORT_WWN 1
+#define STMF_ISCSI_NAME 2
+
+
+/* provider types */
+#define STMF_LU_PROVIDER_TYPE 1
+#define STMF_PORT_PROVIDER_TYPE 2
+
+/* LU Resource types */
+#define STMF_DISK 0
+
+/* Persistence methods */
+#define STMF_PERSIST_SMF 1
+#define STMF_PERSIST_NONE 2
+
+/* Logical unit access states */
+#define STMF_ACCESS_ACTIVE "0"
+#define STMF_ACCESS_ACTIVE_TO_STANDBY "1"
+#define STMF_ACCESS_STANDBY "2"
+#define STMF_ACCESS_STANDBY_TO_ACTIVE "3"
+
+/*
+ * LU Disk Properties
+ */
+
+enum {
+ STMF_LU_PROP_ALIAS = 1,
+ STMF_LU_PROP_BLOCK_SIZE,
+ STMF_LU_PROP_COMPANY_ID,
+ STMF_LU_PROP_FILENAME,
+ STMF_LU_PROP_GUID,
+ STMF_LU_PROP_META_FILENAME,
+ STMF_LU_PROP_MGMT_URL,
+ STMF_LU_PROP_NEW,
+ STMF_LU_PROP_SIZE,
+ STMF_LU_PROP_WRITE_PROTECT,
+ STMF_LU_PROP_WRITE_CACHE_DISABLE,
+ STMF_LU_PROP_VID,
+ STMF_LU_PROP_PID,
+ STMF_LU_PROP_SERIAL_NUM,
+ STMF_LU_PROP_ACCESS_STATE,
+ STMF_LU_PROP_HOST_ID
+};
+
+
+/* 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_SCSI = 1,
+ STMF_PROTOCOL_SSA = 2,
+ STMF_PROTOCOL_IEEE_1394 = 3,
+ STMF_PROTOCOL_SRP = 4,
+ STMF_PROTOCOL_ISCSI = 5,
+ STMF_PROTOCOL_SAS = 6
+} 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 void * luResource;
+
+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 stmfCreateLu(luResource hdl, stmfGuid *luGuid);
+int stmfCreateLuResource(uint16_t dType, luResource *hdl);
+int stmfCreateTargetGroup(stmfGroupName *targetGroupName);
+int stmfDeleteHostGroup(stmfGroupName *hostGroupName);
+int stmfDeleteLu(stmfGuid *luGuid);
+int stmfDeleteTargetGroup(stmfGroupName *targetGroupName);
+void stmfDestroyProxyDoor(int hdl);
+int stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid);
+int stmfDevidFromWwn(uchar_t wwn[8], stmfDevid *devid);
+int stmfFreeLuResource(luResource hdl);
+void stmfFreeMemory(void *);
+int stmfGetAluaState(boolean_t *enabled, uint32_t *node);
+int stmfGetGlobalLuProp(uint16_t dType, uint32_t prop, char *propVal,
+ size_t *propLen);
+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 stmfGetLuProp(luResource hdl, uint32_t propType, char *prop,
+ size_t *propLen);
+int stmfGetLuResource(stmfGuid *luGuid, luResource *hdl);
+int stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState);
+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 stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid);
+int stmfInitProxyDoor(int *hdl, int fd);
+int stmfLoadConfig(void);
+int stmfLuStandby(stmfGuid *luGuid);
+int stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal);
+int stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
+ const char *propVal);
+int stmfOffline(void);
+int stmfOfflineTarget(stmfDevid *devid);
+int stmfOfflineLogicalUnit(stmfGuid *logicalUnit);
+int stmfOnline(void);
+int stmfOnlineTarget(stmfDevid *devid);
+int stmfOnlineLogicalUnit(stmfGuid *logicalUnit);
+int stmfPostProxyMsg(int hdl, void *buf, uint32_t buflen);
+int stmfRemoveFromHostGroup(stmfGroupName *hostGroupName,
+ stmfDevid *initiatorName);
+int stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName,
+ stmfDevid *targetName);
+int stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex);
+int stmfSetAluaState(boolean_t enabled, uint32_t node);
+int stmfSetGlobalLuProp(uint16_t dType, uint32_t propType, const char *propVal);
+int stmfSetLuProp(luResource hdl, uint32_t propType, const char *propVal);
+int stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet);
+int stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType);
+int stmfSetProviderDataProt(char *providerName, nvlist_t *nvl,
+ int providerType, uint64_t *setToken);
+int stmfValidateView(stmfViewEntry *viewEntry);
+int stmfSetStmfProp(uint8_t propType, char *propVal);
+int stmfGetStmfProp(uint8_t propType, char *propVal, size_t *propLen);
+int stmfLoadStmfProps(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSTMF_H */
diff --git a/usr/src/lib/libstmf/common/libstmf_impl.h b/usr/src/lib/libstmf/common/libstmf_impl.h
new file mode 100644
index 0000000..ec02fcd
--- /dev/null
+++ b/usr/src/lib/libstmf/common/libstmf_impl.h
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSTMF_IMPL_H
+#define _LIBSTMF_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libstmf.h>
+
+typedef struct _luResourceImpl {
+ uint16_t type;
+ void *resource;
+} luResourceImpl;
+
+
+typedef struct _diskResource {
+ boolean_t luDataFileNameValid;
+ char luDataFileName[MAXPATHLEN];
+ boolean_t luMetaFileNameValid;
+ char luMetaFileName[MAXPATHLEN];
+ boolean_t luSizeValid;
+ uint64_t luSize;
+ boolean_t blkSizeValid;
+ uint16_t blkSize;
+ boolean_t luGuidValid;
+ uint8_t luGuid[16];
+ boolean_t serialNumValid;
+ char serialNum[253];
+ boolean_t companyIdValid;
+ uint32_t companyId;
+ boolean_t luAliasValid;
+ char luAlias[256];
+ boolean_t luMgmtUrlValid;
+ char luMgmtUrl[1024];
+ boolean_t vidValid;
+ char vid[8];
+ boolean_t pidValid;
+ char pid[16];
+ boolean_t revValid;
+ char rev[4];
+ boolean_t writeProtectEnableValid;
+ boolean_t writeProtectEnable;
+ boolean_t writebackCacheDisableValid;
+ boolean_t writebackCacheDisable;
+ uint16_t accessState;
+ uint32_t hostId;
+ boolean_t hostIdValid;
+} diskResource;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSTMF_IMPL_H */
diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c
new file mode 100644
index 0000000..e12c189
--- /dev/null
+++ b/usr/src/lib/libstmf/common/stmf.c
@@ -0,0 +1,6949 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <libnvpair.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <libstmf.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <store.h>
+#include <locale.h>
+#include <math.h>
+#include <libstmf_impl.h>
+#include <sys/stmf_ioctl.h>
+#include <sys/stmf_sbd_ioctl.h>
+#include <sys/pppt_ioctl.h>
+#include <macros.h>
+
+#define STMF_PATH "/devices/pseudo/stmf@0:admin"
+#define SBD_PATH "/devices/pseudo/stmf_sbd@0:admin"
+#define PPPT_PATH "/devices/pseudo/pppt@0:pppt"
+
+#define EUI "eui."
+#define WWN "wwn."
+#define IQN "iqn."
+#define LU_ASCII_GUID_SIZE 32
+#define LU_GUID_SIZE 16
+#define OUI_ASCII_SIZE 6
+#define HOST_ID_ASCII_SIZE 8
+#define OUI_SIZE 3
+#define HOST_ID_SIZE 4
+#define IDENT_LENGTH_BYTE 3
+
+/* various initial allocation values */
+#define ALLOC_LU 8192
+#define ALLOC_TARGET_PORT 2048
+#define ALLOC_PROVIDER 64
+#define ALLOC_GROUP 2048
+#define ALLOC_SESSION 2048
+#define ALLOC_VE 256
+#define ALLOC_PP_DATA_SIZE 128*1024
+#define ALLOC_GRP_MEMBER 256
+
+#define MAX_ISCSI_NAME 223
+#define MAX_SERIAL_SIZE 252 + 1
+#define MAX_LU_ALIAS_SIZE 256
+#define MAX_SBD_PROPS MAXPATHLEN + MAX_SERIAL_SIZE + MAX_LU_ALIAS_SIZE
+
+#define OPEN_STMF 0
+#define OPEN_EXCL_STMF O_EXCL
+
+#define OPEN_SBD 0
+#define OPEN_EXCL_SBD O_EXCL
+
+#define OPEN_PPPT 0
+#define OPEN_EXCL_PPPT O_EXCL
+
+#define LOGICAL_UNIT_TYPE 0
+#define TARGET_TYPE 1
+#define STMF_SERVICE_TYPE 2
+
+#define HOST_GROUP 1
+#define TARGET_GROUP 2
+
+/* set default persistence here */
+#define STMF_DEFAULT_PERSIST STMF_PERSIST_SMF
+
+#define MAX_PROVIDER_RETRY 30
+
+static int openStmf(int, int *fd);
+static int openSbd(int, int *fd);
+static int openPppt(int, int *fd);
+static int groupIoctl(int fd, int cmd, stmfGroupName *);
+static int loadStore(int fd);
+static int initializeConfig();
+static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *);
+static int guidCompare(const void *, const void *);
+static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *);
+static int loadHostGroups(int fd, stmfGroupList *);
+static int loadTargetGroups(int fd, stmfGroupList *);
+static int getStmfState(stmf_state_desc_t *);
+static int setStmfState(int fd, stmf_state_desc_t *, int);
+static int setProviderData(int fd, char *, nvlist_t *, int, uint64_t *);
+static int createDiskResource(luResourceImpl *);
+static int createDiskLu(diskResource *, stmfGuid *);
+static int deleteDiskLu(stmfGuid *luGuid);
+static int getDiskProp(luResourceImpl *, uint32_t, char *, size_t *);
+static int getDiskAllProps(stmfGuid *luGuid, luResource *hdl);
+static int loadDiskPropsFromDriver(luResourceImpl *, sbd_lu_props_t *);
+static int removeGuidFromDiskStore(stmfGuid *);
+static int addGuidToDiskStore(stmfGuid *, char *);
+static int persistDiskGuid(stmfGuid *, char *, boolean_t);
+static int setDiskProp(luResourceImpl *, uint32_t, const char *);
+static int getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen);
+static int checkHexUpper(char *);
+static int strToShift(const char *);
+static int niceStrToNum(const char *, uint64_t *);
+static void diskError(uint32_t, int *);
+static int importDiskLu(char *fname, stmfGuid *);
+static int modifyDiskLu(diskResource *, stmfGuid *, const char *);
+static int modifyDiskLuProp(stmfGuid *, const char *, uint32_t, const char *);
+static int validateModifyDiskProp(uint32_t);
+static uint8_t iGetPersistMethod();
+static int groupListIoctl(stmfGroupList **, int);
+static int iLoadGroupFromPs(stmfGroupList **, int);
+static int groupMemberListIoctl(stmfGroupName *, stmfGroupProperties **, int);
+static int getProviderData(char *, nvlist_t **, int, uint64_t *);
+static int setDiskStandby(stmfGuid *luGuid);
+static int setDiskGlobalProp(uint32_t, const char *);
+static int viewEntryCompare(const void *, const void *);
+static void deleteNonActiveLus();
+static int loadStmfProp(int fd);
+
+static pthread_mutex_t persistenceTypeLock = PTHREAD_MUTEX_INITIALIZER;
+static int iPersistType = 0;
+/* when B_TRUE, no need to access SMF anymore. Just use iPersistType */
+static boolean_t iLibSetPersist = B_FALSE;
+
+/*
+ * Open for stmf module
+ *
+ * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openStmf(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else if (errno == EACCES) {
+ ret = STMF_ERROR_PERM;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)",
+ STMF_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * Open for sbd module
+ *
+ * flag - open flag (OPEN_SBD, OPEN_EXCL_SBD)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openSbd(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(SBD_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else if (errno == EACCES) {
+ ret = STMF_ERROR_PERM;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openSbd:open failure:%s:errno(%d)",
+ SBD_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * Open for pppt module
+ *
+ * flag - open flag (OPEN_PPPT, OPEN_EXCL_PPPT)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openPppt(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(PPPT_PATH, O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else if (errno == EACCES) {
+ ret = STMF_ERROR_PERM;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openPppt:open failure:%s:errno(%d)",
+ PPPT_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * initializeConfig
+ *
+ * This routine should be called before any ioctl requiring initialization
+ * which is basically everything except stmfGetState(), setStmfState() and
+ * stmfLoadConfig().
+ */
+static int
+initializeConfig()
+{
+ int ret;
+ stmfState state;
+
+
+ ret = stmfGetState(&state);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /* if we've already initialized or in the process, return success */
+ if (state.configState == STMF_CONFIG_STATE_INIT_DONE ||
+ state.configState == STMF_CONFIG_STATE_INIT) {
+ return (STMF_STATUS_SUCCESS);
+ }
+
+ ret = stmfLoadConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "initializeConfig:stmfLoadConfig:error(%d)", ret);
+ return (ret);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "initializeConfig:stmfGetState:error(%d)", ret);
+ return (ret);
+ }
+
+ if (state.configState != STMF_CONFIG_STATE_INIT_DONE) {
+ syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)",
+ state.configState);
+ ret = STMF_STATUS_ERROR;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * groupIoctl
+ *
+ * Purpose: issue ioctl for create/delete on group
+ *
+ * cmd - valid STMF ioctl group cmd
+ * groupName - groupName to create or delete
+ */
+static int
+groupIoctl(int fd, int cmd, stmfGroupName *groupName)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_group_name_t iGroupName;
+
+ bzero(&iGroupName, sizeof (iGroupName));
+
+ bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
+
+ iGroupName.name_size = strlen((char *)groupName);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to create the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (iGroupName);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_EXISTS:
+ case STMF_IOCERR_HG_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_IOCERR_TG_IN_USE:
+ case STMF_IOCERR_HG_IN_USE:
+ ret = STMF_ERROR_GROUP_IN_USE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupIoctl:error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * groupMemberIoctl
+ *
+ * Purpose: issue ioctl for add/remove member on group
+ *
+ * cmd - valid STMF ioctl group member cmd
+ * groupName - groupName to add to or remove from
+ * devid - group member to add or remove
+ */
+static int
+groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_group_op_data_t stmfGroupData;
+
+ bzero(&stmfGroupData, sizeof (stmfGroupData));
+
+ bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName));
+
+ stmfGroupData.group.name_size = strlen((char *)groupName);
+ stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_NEED_TG_OFFLINE:
+ ret = STMF_ERROR_TG_ONLINE;
+ break;
+ default:
+ ret = STMF_ERROR_BUSY;
+ break;
+ }
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_ENTRY_EXISTS:
+ case STMF_IOCERR_HG_ENTRY_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_IOCERR_INVALID_TG_ENTRY:
+ case STMF_IOCERR_INVALID_HG_ENTRY:
+ ret =
+ STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ case STMF_IOCERR_INVALID_HG:
+ ret =
+ STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupMemberIoctl:error"
+ "(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * qsort function
+ * sort on veIndex
+ */
+static int
+viewEntryCompare(const void *p1, const void *p2)
+{
+
+ stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
+ if (v1->veIndex > v2->veIndex)
+ return (1);
+ if (v1->veIndex < v2->veIndex)
+ return (-1);
+ return (0);
+}
+
+/*
+ * guidCompare
+ *
+ * qsort function
+ * sort on guid
+ */
+static int
+guidCompare(const void *p1, const void *p2)
+{
+
+ stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2;
+ int i;
+
+ for (i = 0; i < sizeof (stmfGuid); i++) {
+ if (g1->guid[i] > g2->guid[i])
+ return (1);
+ if (g1->guid[i] < g2->guid[i])
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * stmfAddToHostGroup
+ *
+ * Purpose: Adds an initiator to an existing host group
+ *
+ * hostGroupName - name of an existing host group
+ * hostName - name of initiator to add
+ */
+int
+stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || hostName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName,
+ hostName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psAddHostGroupMember((char *)hostGroupName,
+ (char *)hostName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddToHostGroup:psAddHostGroupMember:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfAddToTargetGroup
+ *
+ * Purpose: Adds a local port to an existing target group
+ *
+ * targetGroupName - name of an existing target group
+ * targetName - name of target to add
+ */
+int
+stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || targetName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
+ targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psAddTargetGroupMember((char *)targetGroupName,
+ (char *)targetName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddToTargetGroup:psAddTargetGroupMember:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * addViewEntryIoctl
+ *
+ * Purpose: Issues ioctl to add a view entry
+ *
+ * lu - Logical Unit identifier to which the view entry is added
+ * viewEntry - view entry to add
+ * init - When set to B_TRUE, we are in the init state, i.e. don't call open
+ */
+static int
+addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ /*
+ * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
+ * false on input
+ */
+ ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
+ ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
+ ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
+
+ if (viewEntry->allHosts == B_FALSE) {
+ bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_host_group.name_size =
+ strlen((char *)viewEntry->hostGroup);
+ }
+ if (viewEntry->allTargets == B_FALSE) {
+ bcopy(viewEntry->targetGroup,
+ &ioctlViewEntry.ve_target_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_target_group.name_size =
+ strlen((char *)viewEntry->targetGroup);
+ }
+ if (viewEntry->luNbrValid) {
+ bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_LU_NUMBER_IN_USE:
+ ret = STMF_ERROR_LUN_IN_USE;
+ break;
+ case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
+ ret = STMF_ERROR_VE_CONFLICT;
+ break;
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ ret = STMF_ERROR_INVALID_HG;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_INVALID_TG;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "addViewEntryIoctl"
+ ":error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ goto done;
+ }
+
+ /* copy lu nbr back to caller's view entry on success */
+ viewEntry->veIndex = ioctlViewEntry.ve_ndx;
+ if (ioctlViewEntry.ve_lu_number_valid) {
+ bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ viewEntry->luNbrValid = B_TRUE;
+
+done:
+ return (ret);
+}
+
+/*
+ * stmfAddViewEntry
+ *
+ * Purpose: Adds a view entry to a logical unit
+ *
+ * lu - guid of the logical unit to which the view entry is added
+ * viewEntry - view entry structure to add
+ */
+int
+stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ int ret;
+ int fd;
+ stmfViewEntry iViewEntry;
+
+ if (lu == NULL || viewEntry == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* initialize and set internal view entry */
+ bzero(&iViewEntry, sizeof (iViewEntry));
+
+ if (!viewEntry->allHosts) {
+ bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
+ sizeof (iViewEntry.hostGroup));
+ } else {
+ iViewEntry.allHosts = B_TRUE;
+ }
+
+ if (!viewEntry->allTargets) {
+ bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
+ sizeof (iViewEntry.targetGroup));
+ } else {
+ iViewEntry.allTargets = B_TRUE;
+ }
+
+ if (viewEntry->luNbrValid) {
+ iViewEntry.luNbrValid = B_TRUE;
+ bcopy(viewEntry->luNbr, iViewEntry.luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ /*
+ * set users return view entry index valid flag to false
+ * in case of failure
+ */
+ viewEntry->veIndexValid = B_FALSE;
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * First add the view entry to the driver
+ */
+ ret = addViewEntryIoctl(fd, lu, &iViewEntry);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the add to driver was successful, add it to the persistent
+ * store.
+ */
+ ret = psAddViewEntry(lu, &iViewEntry);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddViewEntry:psAddViewEntry:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+
+ if (ret == STMF_STATUS_SUCCESS) {
+ /* set caller's view entry on success */
+ viewEntry->veIndexValid = iViewEntry.veIndexValid;
+ viewEntry->veIndex = iViewEntry.veIndex;
+ viewEntry->luNbrValid = B_TRUE;
+ bcopy(iViewEntry.luNbr, viewEntry->luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+ return (ret);
+}
+
+/*
+ * stmfClearProviderData
+ *
+ * Purpose: delete all provider data for specified provider
+ *
+ * providerName - name of provider for which data should be deleted
+ */
+int
+stmfClearProviderData(char *providerName, int providerType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int savedErrno;
+ stmf_iocdata_t stmfIoctl;
+ stmf_ppioctl_data_t ppi;
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&ppi, sizeof (ppi));
+
+ (void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name));
+
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi.ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi.ppi_port_provider = 1;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
+
+ ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfClearProviderData:ioctl error(%d)",
+ ioctlRet);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (savedErrno != ENOENT) {
+ goto done;
+ }
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psClearProviderData(providerName, providerType);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfClearProviderData:psClearProviderData"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfCreateHostGroup
+ *
+ * Purpose: Create a new initiator group
+ *
+ * hostGroupName - name of host group to create
+ */
+int
+stmfCreateHostGroup(stmfGroupName *hostGroupName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName))) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
+ hostGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psCreateHostGroup((char *)hostGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfCreateHostGroup:psCreateHostGroup:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfCreateLu
+ *
+ * Purpose: Create a logical unit
+ *
+ * hdl - handle to logical unit resource created via stmfCreateLuResource
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the created logical
+ * unit
+ */
+int
+stmfCreateLu(luResource hdl, stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResourceImpl *luPropsHdl = hdl;
+
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (luPropsHdl->type == STMF_DISK) {
+ ret = createDiskLu((diskResource *)luPropsHdl->resource,
+ luGuid);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfCreateLuResource
+ *
+ * Purpose: Create resource handle for a logical unit
+ *
+ * dType - Type of logical unit resource to create
+ * Can be: STMF_DISK
+ *
+ * hdl - pointer to luResource
+ */
+int
+stmfCreateLuResource(uint16_t dType, luResource *hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+
+ if (dType != STMF_DISK || hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ *hdl = calloc(1, sizeof (luResourceImpl));
+ if (*hdl == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ ret = createDiskResource((luResourceImpl *)*hdl);
+ if (ret != STMF_STATUS_SUCCESS) {
+ free(*hdl);
+ return (ret);
+ }
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * Creates a disk logical unit
+ *
+ * disk - pointer to diskResource structure that represents the properties
+ * for the disk logical unit to be created.
+ */
+static int
+createDiskLu(diskResource *disk, stmfGuid *createdGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int dataFileNameLen = 0;
+ int metaFileNameLen = 0;
+ int serialNumLen = 0;
+ int luAliasLen = 0;
+ int luMgmtUrlLen = 0;
+ int sluBufSize = 0;
+ int bufOffset = 0;
+ int fd = 0;
+ int ioctlRet;
+ int savedErrno;
+ stmfGuid guid;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ sbd_create_and_reg_lu_t *sbdLu = NULL;
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /* data file name must be specified */
+ if (disk->luDataFileNameValid) {
+ dataFileNameLen = strlen(disk->luDataFileName);
+ } else {
+ (void) close(fd);
+ return (STMF_ERROR_MISSING_PROP_VAL);
+ }
+
+ sluBufSize += dataFileNameLen + 1;
+
+ if (disk->luMetaFileNameValid) {
+ metaFileNameLen = strlen(disk->luMetaFileName);
+ sluBufSize += metaFileNameLen + 1;
+ }
+
+ serialNumLen = strlen(disk->serialNum);
+ sluBufSize += serialNumLen;
+
+ if (disk->luAliasValid) {
+ luAliasLen = strlen(disk->luAlias);
+ sluBufSize += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ luMgmtUrlLen = strlen(disk->luMgmtUrl);
+ sluBufSize += luMgmtUrlLen + 1;
+ }
+
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdLu = (sbd_create_and_reg_lu_t *)calloc(1,
+ sizeof (sbd_create_and_reg_lu_t) + sluBufSize - 8);
+ if (sbdLu == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdLu->slu_struct_size = sizeof (sbd_create_and_reg_lu_t) +
+ sluBufSize - 8;
+
+ if (metaFileNameLen) {
+ sbdLu->slu_meta_fname_valid = 1;
+ sbdLu->slu_meta_fname_off = bufOffset;
+ bcopy(disk->luMetaFileName, &(sbdLu->slu_buf[bufOffset]),
+ metaFileNameLen + 1);
+ bufOffset += metaFileNameLen + 1;
+ }
+
+ bcopy(disk->luDataFileName, &(sbdLu->slu_buf[bufOffset]),
+ dataFileNameLen + 1);
+ sbdLu->slu_data_fname_off = bufOffset;
+ bufOffset += dataFileNameLen + 1;
+
+ /* currently, serial # is not passed null terminated to the driver */
+ if (disk->serialNumValid) {
+ sbdLu->slu_serial_valid = 1;
+ sbdLu->slu_serial_off = bufOffset;
+ sbdLu->slu_serial_size = serialNumLen;
+ bcopy(disk->serialNum, &(sbdLu->slu_buf[bufOffset]),
+ serialNumLen);
+ bufOffset += serialNumLen;
+ }
+
+ if (disk->luAliasValid) {
+ sbdLu->slu_alias_valid = 1;
+ sbdLu->slu_alias_off = bufOffset;
+ bcopy(disk->luAlias, &(sbdLu->slu_buf[bufOffset]),
+ luAliasLen + 1);
+ bufOffset += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ sbdLu->slu_mgmt_url_valid = 1;
+ sbdLu->slu_mgmt_url_off = bufOffset;
+ bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]),
+ luMgmtUrlLen + 1);
+ bufOffset += luMgmtUrlLen + 1;
+ }
+
+ if (disk->luSizeValid) {
+ sbdLu->slu_lu_size_valid = 1;
+ sbdLu->slu_lu_size = disk->luSize;
+ }
+
+ if (disk->luGuidValid) {
+ sbdLu->slu_guid_valid = 1;
+ bcopy(disk->luGuid, sbdLu->slu_guid, sizeof (disk->luGuid));
+ }
+
+ if (disk->vidValid) {
+ sbdLu->slu_vid_valid = 1;
+ bcopy(disk->vid, sbdLu->slu_vid, sizeof (disk->vid));
+ }
+
+ if (disk->pidValid) {
+ sbdLu->slu_pid_valid = 1;
+ bcopy(disk->pid, sbdLu->slu_pid, sizeof (disk->pid));
+ }
+
+ if (disk->revValid) {
+ sbdLu->slu_rev_valid = 1;
+ bcopy(disk->rev, sbdLu->slu_rev, sizeof (disk->rev));
+ }
+
+ if (disk->companyIdValid) {
+ sbdLu->slu_company_id_valid = 1;
+ sbdLu->slu_company_id = disk->companyId;
+ }
+
+ if (disk->hostIdValid) {
+ sbdLu->slu_host_id_valid = 1;
+ sbdLu->slu_host_id = disk->hostId;
+ }
+
+ if (disk->blkSizeValid) {
+ sbdLu->slu_blksize_valid = 1;
+ sbdLu->slu_blksize = disk->blkSize;
+ }
+
+ if (disk->writeProtectEnableValid) {
+ if (disk->writeProtectEnable) {
+ sbdLu->slu_write_protected = 1;
+ }
+ }
+
+ if (disk->writebackCacheDisableValid) {
+ sbdLu->slu_writeback_cache_disable_valid = 1;
+ if (disk->writebackCacheDisable) {
+ sbdLu->slu_writeback_cache_disable = 1;
+ }
+ }
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdLu->slu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+ sbdIoctl.stmf_obuf_size = sbdLu->slu_struct_size;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_CREATE_AND_REGISTER_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "createDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * on success, copy the resulting guid into the caller's guid if not
+ * NULL
+ */
+ if (createdGuid) {
+ bcopy(sbdLu->slu_guid, createdGuid->guid,
+ sizeof (sbdLu->slu_guid));
+ }
+
+ bcopy(sbdLu->slu_guid, guid.guid, sizeof (sbdLu->slu_guid));
+ if (disk->luMetaFileNameValid) {
+ ret = addGuidToDiskStore(&guid, disk->luMetaFileName);
+ } else {
+ ret = addGuidToDiskStore(&guid, disk->luDataFileName);
+ }
+done:
+ free(sbdLu);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfImportLu
+ *
+ * Purpose: Import a previously created logical unit
+ *
+ * dType - Type of logical unit
+ * Can be: STMF_DISK
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the imported logical
+ * unit
+ *
+ * fname - A file name where the metadata resides
+ *
+ */
+int
+stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+
+ if (dType == STMF_DISK) {
+ ret = importDiskLu(fname, luGuid);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * importDiskLu
+ *
+ * filename - filename to import
+ * createdGuid - if not NULL, on success contains the imported guid
+ *
+ */
+static int
+importDiskLu(char *fname, stmfGuid *createdGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd = 0;
+ int ioctlRet;
+ int savedErrno;
+ int metaFileNameLen;
+ stmfGuid iGuid;
+ int iluBufSize = 0;
+ sbd_import_lu_t *sbdLu = NULL;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ if (fname == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ metaFileNameLen = strlen(fname);
+ iluBufSize += metaFileNameLen + 1;
+
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdLu = (sbd_import_lu_t *)calloc(1,
+ sizeof (sbd_import_lu_t) + iluBufSize - 8);
+ if (sbdLu == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ /*
+ * Accept either a data file or meta data file.
+ * sbd will do the right thing here either way.
+ * i.e. if it's a data file, it assumes that the
+ * meta data is shared with the data.
+ */
+ (void) strncpy(sbdLu->ilu_meta_fname, fname, metaFileNameLen);
+
+ sbdLu->ilu_struct_size = sizeof (sbd_import_lu_t) + iluBufSize - 8;
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdLu->ilu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+ sbdIoctl.stmf_obuf_size = sbdLu->ilu_struct_size;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_IMPORT_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+
+ if (createdGuid && sbdIoctl.stmf_error ==
+ SBD_RET_FILE_ALREADY_REGISTERED) {
+ bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
+ sizeof (sbdLu->ilu_ret_guid));
+ }
+
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "importDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * on success, copy the resulting guid into the caller's guid if not
+ * NULL and add it to the persistent store for sbd
+ */
+ if (createdGuid) {
+ bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
+ sizeof (sbdLu->ilu_ret_guid));
+ ret = addGuidToDiskStore(createdGuid, fname);
+ } else {
+ bcopy(sbdLu->ilu_ret_guid, iGuid.guid,
+ sizeof (sbdLu->ilu_ret_guid));
+ ret = addGuidToDiskStore(&iGuid, fname);
+ }
+done:
+ free(sbdLu);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * diskError
+ *
+ * Purpose: Translate sbd driver error
+ */
+static void
+diskError(uint32_t stmfError, int *ret)
+{
+ switch (stmfError) {
+ case SBD_RET_META_CREATION_FAILED:
+ case SBD_RET_ZFS_META_CREATE_FAILED:
+ *ret = STMF_ERROR_META_CREATION;
+ break;
+ case SBD_RET_INVALID_BLKSIZE:
+ *ret = STMF_ERROR_INVALID_BLKSIZE;
+ break;
+ case SBD_RET_FILE_ALREADY_REGISTERED:
+ *ret = STMF_ERROR_FILE_IN_USE;
+ break;
+ case SBD_RET_GUID_ALREADY_REGISTERED:
+ *ret = STMF_ERROR_GUID_IN_USE;
+ break;
+ case SBD_RET_META_PATH_NOT_ABSOLUTE:
+ case SBD_RET_META_FILE_LOOKUP_FAILED:
+ case SBD_RET_META_FILE_OPEN_FAILED:
+ case SBD_RET_META_FILE_GETATTR_FAILED:
+ case SBD_RET_NO_META:
+ *ret = STMF_ERROR_META_FILE_NAME;
+ break;
+ case SBD_RET_DATA_PATH_NOT_ABSOLUTE:
+ case SBD_RET_DATA_FILE_LOOKUP_FAILED:
+ case SBD_RET_DATA_FILE_OPEN_FAILED:
+ case SBD_RET_DATA_FILE_GETATTR_FAILED:
+ *ret = STMF_ERROR_DATA_FILE_NAME;
+ break;
+ case SBD_RET_FILE_SIZE_ERROR:
+ *ret = STMF_ERROR_FILE_SIZE_INVALID;
+ break;
+ case SBD_RET_SIZE_OUT_OF_RANGE:
+ *ret = STMF_ERROR_SIZE_OUT_OF_RANGE;
+ break;
+ case SBD_RET_LU_BUSY:
+ *ret = STMF_ERROR_LU_BUSY;
+ break;
+ case SBD_RET_WRITE_CACHE_SET_FAILED:
+ *ret = STMF_ERROR_WRITE_CACHE_SET;
+ break;
+ case SBD_RET_ACCESS_STATE_FAILED:
+ *ret = STMF_ERROR_ACCESS_STATE_SET;
+ break;
+ default:
+ *ret = STMF_STATUS_ERROR;
+ break;
+ }
+}
+
+/*
+ * Creates a logical unit resource of type STMF_DISK.
+ *
+ * No defaults should be set here as all defaults are derived from the
+ * driver's default settings.
+ */
+static int
+createDiskResource(luResourceImpl *hdl)
+{
+ hdl->type = STMF_DISK;
+
+ hdl->resource = calloc(1, sizeof (diskResource));
+ if (hdl->resource == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfDeleteLu
+ *
+ * Purpose: Delete a logical unit
+ *
+ * hdl - handle to logical unit resource created via stmfCreateLuResource
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the created logical
+ * unit
+ */
+int
+stmfDeleteLu(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (luGuid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = deleteDiskLu(luGuid);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+deleteDiskLu(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int savedErrno;
+ int ioctlRet;
+ sbd_delete_lu_t deleteLu = {0};
+
+ stmf_iocdata_t sbdIoctl = {0};
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = removeGuidFromDiskStore(luGuid);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ bcopy(luGuid, deleteLu.dlu_guid, sizeof (deleteLu.dlu_guid));
+ deleteLu.dlu_by_guid = 1;
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sizeof (deleteLu);
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&deleteLu;
+ ioctlRet = ioctl(fd, SBD_IOCTL_DELETE_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "deleteDiskLu:ioctl error(%d) (%d) (%d)",
+ ioctlRet, sbdIoctl.stmf_error, savedErrno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfLuStandby
+ *
+ * Purpose: Sets access state to standby
+ *
+ * luGuid - guid of registered logical unit
+ *
+ */
+int
+stmfLuStandby(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (luGuid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = setDiskStandby(luGuid);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+setDiskStandby(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmf_iocdata_t sbdIoctl = {0};
+ sbd_set_lu_standby_t sbdLu = {0};
+ int ioctlRet;
+ int savedErrno;
+ int fd = 0;
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bcopy(luGuid, &sbdLu.stlu_guid, sizeof (stmfGuid));
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sizeof (sbd_set_lu_standby_t);
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_SET_LU_STANDBY, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "setDiskStandby:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfModifyLu
+ *
+ * Purpose: Modify properties of a logical unit
+ *
+ * luGuid - guid of registered logical unit
+ * prop - property to modify
+ * propVal - property value to set
+ *
+ */
+int
+stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (luGuid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = modifyDiskLuProp(luGuid, NULL, prop, propVal);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfModifyLuByFname
+ *
+ * Purpose: Modify a device by filename. Device does not need to be registered.
+ *
+ * dType - type of device to modify
+ * STMF_DISK
+ *
+ * fname - filename or meta filename
+ * prop - valid property identifier
+ * propVal - property value
+ *
+ */
+int
+stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
+ const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (fname == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (dType == STMF_DISK) {
+ ret = modifyDiskLuProp(NULL, fname, prop, propVal);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+static int
+modifyDiskLuProp(stmfGuid *luGuid, const char *fname, uint32_t prop,
+ const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResource hdl = NULL;
+ luResourceImpl *luPropsHdl;
+
+ ret = stmfCreateLuResource(STMF_DISK, &hdl);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ ret = validateModifyDiskProp(prop);
+ if (ret != STMF_STATUS_SUCCESS) {
+ (void) stmfFreeLuResource(hdl);
+ return (STMF_ERROR_INVALID_PROP);
+ }
+ ret = stmfSetLuProp(hdl, prop, propVal);
+ if (ret != STMF_STATUS_SUCCESS) {
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+ }
+ luPropsHdl = hdl;
+ ret = modifyDiskLu((diskResource *)luPropsHdl->resource, luGuid, fname);
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+}
+
+static int
+validateModifyDiskProp(uint32_t prop)
+{
+ switch (prop) {
+ case STMF_LU_PROP_ALIAS:
+ case STMF_LU_PROP_SIZE:
+ case STMF_LU_PROP_MGMT_URL:
+ case STMF_LU_PROP_WRITE_PROTECT:
+ case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+ return (STMF_STATUS_SUCCESS);
+ default:
+ return (STMF_STATUS_ERROR);
+ }
+}
+
+static int
+modifyDiskLu(diskResource *disk, stmfGuid *luGuid, const char *fname)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int luAliasLen = 0;
+ int luMgmtUrlLen = 0;
+ int mluBufSize = 0;
+ int bufOffset = 0;
+ int fd = 0;
+ int ioctlRet;
+ int savedErrno;
+ int fnameSize = 0;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ sbd_modify_lu_t *sbdLu = NULL;
+
+ if (luGuid == NULL && fname == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (fname) {
+ fnameSize = strlen(fname) + 1;
+ mluBufSize += fnameSize;
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if (disk->luAliasValid) {
+ luAliasLen = strlen(disk->luAlias);
+ mluBufSize += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ luMgmtUrlLen = strlen(disk->luMgmtUrl);
+ mluBufSize += luMgmtUrlLen + 1;
+ }
+
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdLu = (sbd_modify_lu_t *)calloc(1,
+ sizeof (sbd_modify_lu_t) + mluBufSize - 8 + fnameSize);
+ if (sbdLu == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdLu->mlu_struct_size = sizeof (sbd_modify_lu_t) +
+ mluBufSize - 8 + fnameSize;
+
+ if (disk->luAliasValid) {
+ sbdLu->mlu_alias_valid = 1;
+ sbdLu->mlu_alias_off = bufOffset;
+ bcopy(disk->luAlias, &(sbdLu->mlu_buf[bufOffset]),
+ luAliasLen + 1);
+ bufOffset += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ sbdLu->mlu_mgmt_url_valid = 1;
+ sbdLu->mlu_mgmt_url_off = bufOffset;
+ bcopy(disk->luMgmtUrl, &(sbdLu->mlu_buf[bufOffset]),
+ luMgmtUrlLen + 1);
+ bufOffset += luMgmtUrlLen + 1;
+ }
+
+ if (disk->luSizeValid) {
+ sbdLu->mlu_lu_size_valid = 1;
+ sbdLu->mlu_lu_size = disk->luSize;
+ }
+
+ if (disk->writeProtectEnableValid) {
+ sbdLu->mlu_write_protected_valid = 1;
+ if (disk->writeProtectEnable) {
+ sbdLu->mlu_write_protected = 1;
+ }
+ }
+
+ if (disk->writebackCacheDisableValid) {
+ sbdLu->mlu_writeback_cache_disable_valid = 1;
+ if (disk->writebackCacheDisable) {
+ sbdLu->mlu_writeback_cache_disable = 1;
+ }
+ }
+
+ if (luGuid) {
+ bcopy(luGuid, sbdLu->mlu_input_guid, sizeof (stmfGuid));
+ sbdLu->mlu_by_guid = 1;
+ } else {
+ sbdLu->mlu_fname_off = bufOffset;
+ bcopy(fname, &(sbdLu->mlu_buf[bufOffset]), fnameSize + 1);
+ sbdLu->mlu_by_fname = 1;
+ }
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdLu->mlu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_MODIFY_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "modifyDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+done:
+ free(sbdLu);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * removeGuidFromDiskStore
+ *
+ * Purpose: delete a logical unit from the sbd provider data
+ */
+static int
+removeGuidFromDiskStore(stmfGuid *guid)
+{
+ return (persistDiskGuid(guid, NULL, B_FALSE));
+}
+
+
+/*
+ * addGuidToDiskStore
+ *
+ * Purpose: add a logical unit to the sbd provider data
+ */
+static int
+addGuidToDiskStore(stmfGuid *guid, char *filename)
+{
+ return (persistDiskGuid(guid, filename, B_TRUE));
+}
+
+
+/*
+ * persistDiskGuid
+ *
+ * Purpose: Persist or unpersist a guid for the sbd provider data
+ *
+ */
+static int
+persistDiskGuid(stmfGuid *guid, char *filename, boolean_t persist)
+{
+ char guidAsciiBuf[LU_ASCII_GUID_SIZE + 1] = {0};
+ nvlist_t *nvl = NULL;
+
+ uint64_t setToken;
+ boolean_t retryGetProviderData = B_FALSE;
+ boolean_t newData = B_FALSE;
+ int ret = STMF_STATUS_SUCCESS;
+ int retryCnt = 0;
+ int stmfRet;
+
+ /* if we're persisting a guid, there must be a filename */
+ if (persist && !filename) {
+ return (1);
+ }
+
+ /* guid is stored in lowercase ascii hex */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+ "%02x%02x%02x%02x%02x%02x",
+ guid->guid[0], guid->guid[1], guid->guid[2], guid->guid[3],
+ guid->guid[4], guid->guid[5], guid->guid[6], guid->guid[7],
+ guid->guid[8], guid->guid[9], guid->guid[10], guid->guid[11],
+ guid->guid[12], guid->guid[13], guid->guid[14], guid->guid[15]);
+
+
+ do {
+ retryGetProviderData = B_FALSE;
+ stmfRet = stmfGetProviderDataProt("sbd", &nvl,
+ STMF_LU_PROVIDER_TYPE, &setToken);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ if (persist && stmfRet == STMF_ERROR_NOT_FOUND) {
+ ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ syslog(LOG_DEBUG,
+ "unpersistGuid:nvlist_alloc(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+ newData = B_TRUE;
+ } else {
+ /*
+ * if we're persisting the data, it's
+ * an error. Otherwise, just return
+ */
+ if (persist) {
+ ret = stmfRet;
+ }
+ goto done;
+ }
+ }
+ if (persist) {
+ ret = nvlist_add_string(nvl, guidAsciiBuf, filename);
+ } else {
+ ret = nvlist_remove(nvl, guidAsciiBuf,
+ DATA_TYPE_STRING);
+ if (ret == ENOENT) {
+ ret = 0;
+ }
+ }
+ if (ret == 0) {
+ if (newData) {
+ stmfRet = stmfSetProviderDataProt("sbd", nvl,
+ STMF_LU_PROVIDER_TYPE, NULL);
+ } else {
+ stmfRet = stmfSetProviderDataProt("sbd", nvl,
+ STMF_LU_PROVIDER_TYPE, &setToken);
+ }
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ if (stmfRet == STMF_ERROR_BUSY) {
+ /* get/set failed, try again */
+ retryGetProviderData = B_TRUE;
+ if (retryCnt++ > MAX_PROVIDER_RETRY) {
+ ret = stmfRet;
+ break;
+ }
+ continue;
+ } else if (stmfRet ==
+ STMF_ERROR_PROV_DATA_STALE) {
+ /* update failed, try again */
+ nvlist_free(nvl);
+ nvl = NULL;
+ retryGetProviderData = B_TRUE;
+ if (retryCnt++ > MAX_PROVIDER_RETRY) {
+ ret = stmfRet;
+ break;
+ }
+ continue;
+ } else {
+ syslog(LOG_DEBUG,
+ "unpersistGuid:error(%x)", stmfRet);
+ ret = stmfRet;
+ }
+ break;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "unpersistGuid:error nvlist_add/remove(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ }
+ } while (retryGetProviderData);
+
+done:
+ nvlist_free(nvl);
+ return (ret);
+}
+
+
+/*
+ * stmfGetLuProp
+ *
+ * Purpose: Get current value for a resource property
+ *
+ * hdl - luResource from a previous call to stmfCreateLuResource
+ *
+ * resourceProp - a valid resource property type
+ *
+ * propVal - void pointer to a pointer of the value to be retrieved
+ */
+int
+stmfGetLuProp(luResource hdl, uint32_t prop, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResourceImpl *luPropsHdl = hdl;
+ if (hdl == NULL || propLen == NULL || propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (luPropsHdl->type == STMF_DISK) {
+ ret = getDiskProp(luPropsHdl, prop, propVal, propLen);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetLuResource
+ *
+ * Purpose: Get a logical unit resource handle for a given logical unit.
+ *
+ * hdl - pointer to luResource
+ */
+int
+stmfGetLuResource(stmfGuid *luGuid, luResource *hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = getDiskAllProps(luGuid, hdl);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * getDiskAllProps
+ *
+ * Purpose: load all disk properties from sbd driver
+ *
+ * luGuid - guid of disk device for which properties are to be retrieved
+ * hdl - allocated luResource into which properties are to be copied
+ *
+ */
+static int
+getDiskAllProps(stmfGuid *luGuid, luResource *hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ sbd_lu_props_t *sbdProps;
+ int ioctlRet;
+ int savedErrno;
+ int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+
+ *hdl = calloc(1, sizeof (luResourceImpl));
+ if (*hdl == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdProps = calloc(1, sbdPropsSize);
+ if (sbdProps == NULL) {
+ free(*hdl);
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ ret = createDiskResource((luResourceImpl *)*hdl);
+ if (ret != STMF_STATUS_SUCCESS) {
+ free(*hdl);
+ free(sbdProps);
+ (void) close(fd);
+ return (ret);
+ }
+
+ sbdProps->slp_input_guid = 1;
+ bcopy(luGuid, sbdProps->slp_guid, sizeof (sbdProps->slp_guid));
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdPropsSize;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdProps;
+ sbdIoctl.stmf_obuf_size = sbdPropsSize;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
+ ioctlRet = ioctl(fd, SBD_IOCTL_GET_LU_PROPS, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getDiskAllProps:ioctl error(%d) (%d) (%d)",
+ ioctlRet, sbdIoctl.stmf_error, savedErrno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+
+ if (ret == STMF_STATUS_SUCCESS) {
+ ret = loadDiskPropsFromDriver((luResourceImpl *)*hdl, sbdProps);
+ }
+
+ free(sbdProps);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * loadDiskPropsFromDriver
+ *
+ * Purpose: Retrieve all disk type properties from sbd driver
+ *
+ * hdl - Allocated luResourceImpl
+ * sbdProps - sbd_lu_props_t structure returned from sbd driver
+ *
+ */
+static int
+loadDiskPropsFromDriver(luResourceImpl *hdl, sbd_lu_props_t *sbdProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ diskResource *diskLu = hdl->resource;
+ /* copy guid */
+ diskLu->luGuidValid = B_TRUE;
+ bcopy(sbdProps->slp_guid, diskLu->luGuid, sizeof (sbdProps->slp_guid));
+
+ if (sbdProps->slp_separate_meta && sbdProps->slp_meta_fname_valid) {
+ diskLu->luMetaFileNameValid = B_TRUE;
+ if (strlcpy(diskLu->luMetaFileName,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_meta_fname_off]),
+ sizeof (diskLu->luMetaFileName)) >=
+ sizeof (diskLu->luMetaFileName)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+
+ if (sbdProps->slp_data_fname_valid) {
+ diskLu->luDataFileNameValid = B_TRUE;
+ if (strlcpy(diskLu->luDataFileName,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_data_fname_off]),
+ sizeof (diskLu->luDataFileName)) >=
+ sizeof (diskLu->luDataFileName)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+
+ if (sbdProps->slp_serial_valid) {
+ diskLu->serialNumValid = B_TRUE;
+ bcopy(&(sbdProps->slp_buf[sbdProps->slp_serial_off]),
+ diskLu->serialNum, sbdProps->slp_serial_size);
+ }
+
+ if (sbdProps->slp_mgmt_url_valid) {
+ diskLu->luMgmtUrlValid = B_TRUE;
+ if (strlcpy(diskLu->luMgmtUrl,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_mgmt_url_off]),
+ sizeof (diskLu->luMgmtUrl)) >=
+ sizeof (diskLu->luMgmtUrl)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+
+ if (sbdProps->slp_alias_valid) {
+ diskLu->luAliasValid = B_TRUE;
+ if (strlcpy(diskLu->luAlias,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_alias_off]),
+ sizeof (diskLu->luAlias)) >=
+ sizeof (diskLu->luAlias)) {
+ return (STMF_STATUS_ERROR);
+ }
+ } else { /* set alias to data filename if not set */
+ if (sbdProps->slp_data_fname_valid) {
+ diskLu->luAliasValid = B_TRUE;
+ if (strlcpy(diskLu->luAlias,
+ (char *)&(sbdProps->slp_buf[
+ sbdProps->slp_data_fname_off]),
+ sizeof (diskLu->luAlias)) >=
+ sizeof (diskLu->luAlias)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+ }
+
+ diskLu->vidValid = B_TRUE;
+ bcopy(sbdProps->slp_vid, diskLu->vid, sizeof (diskLu->vid));
+
+ diskLu->pidValid = B_TRUE;
+ bcopy(sbdProps->slp_pid, diskLu->pid, sizeof (diskLu->pid));
+
+ diskLu->revValid = B_TRUE;
+ bcopy(sbdProps->slp_rev, diskLu->rev, sizeof (diskLu->rev));
+
+ diskLu->writeProtectEnableValid = B_TRUE;
+ if (sbdProps->slp_write_protected) {
+ diskLu->writeProtectEnable = B_TRUE;
+ }
+
+ diskLu->writebackCacheDisableValid = B_TRUE;
+ if (sbdProps->slp_writeback_cache_disable_cur) {
+ diskLu->writebackCacheDisable = B_TRUE;
+ }
+
+ diskLu->blkSizeValid = B_TRUE;
+ diskLu->blkSize = sbdProps->slp_blksize;
+
+ diskLu->luSizeValid = B_TRUE;
+ diskLu->luSize = sbdProps->slp_lu_size;
+
+ diskLu->accessState = sbdProps->slp_access_state;
+
+ return (ret);
+}
+
+/*
+ * stmfGetGlobalLuProp
+ *
+ * Purpose: get a global property for a device type
+ *
+ */
+int
+stmfGetGlobalLuProp(uint16_t dType, uint32_t prop, char *propVal,
+ size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (dType != STMF_DISK || propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = getDiskGlobalProp(prop, propVal, propLen);
+
+ return (ret);
+}
+
+/*
+ * getDiskGlobalProp
+ *
+ * Purpose: get global property from sbd driver
+ *
+ */
+static int
+getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ sbd_global_props_t *sbdProps;
+ void *sbd_realloc;
+ int retryCnt = 0;
+ boolean_t retry;
+ int ioctlRet;
+ int savedErrno;
+ int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
+ stmf_iocdata_t sbdIoctl = {0};
+ size_t reqLen;
+
+ switch (prop) {
+ case STMF_LU_PROP_MGMT_URL:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_PROP);
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ sbdProps = calloc(1, sbdPropsSize);
+ if (sbdProps == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ do {
+ retry = B_FALSE;
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_obuf_size = sbdPropsSize;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
+ ioctlRet = ioctl(fd, SBD_IOCTL_GET_GLOBAL_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOMEM:
+ if (sbdIoctl.stmf_error ==
+ SBD_RET_INSUFFICIENT_BUF_SPACE &&
+ retryCnt++ < 3) {
+ sbdPropsSize =
+ sizeof (*sbdProps) +
+ sbdProps->
+ mlu_buf_size_needed;
+
+ sbd_realloc = sbdProps;
+ sbdProps = realloc(sbdProps,
+ sbdPropsSize);
+ if (sbdProps == NULL) {
+ free(sbd_realloc);
+ ret = STMF_ERROR_NOMEM;
+ break;
+ }
+ retry = B_TRUE;
+ } else {
+ ret = STMF_ERROR_NOMEM;
+ }
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getDiskGlobalProp:ioctl error(%d)"
+ "(%d)(%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ }
+ } while (retry);
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ switch (prop) {
+ case STMF_LU_PROP_MGMT_URL:
+ if (sbdProps->mlu_mgmt_url_valid == 0) {
+ ret = STMF_ERROR_NO_PROP;
+ goto done;
+ }
+ if ((reqLen = strlcpy(propVal, (char *)&(
+ sbdProps->mlu_buf[sbdProps->mlu_mgmt_url_off]),
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+ break;
+ }
+
+done:
+ free(sbdProps);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfSetGlobalLuProp
+ *
+ * Purpose: set a global property for a device type
+ *
+ */
+int
+stmfSetGlobalLuProp(uint16_t dType, uint32_t prop, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (dType != STMF_DISK || propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = setDiskGlobalProp(prop, propVal);
+
+ return (ret);
+}
+
+/*
+ * setDiskGlobalProp
+ *
+ * Purpose: set properties for resource of type disk
+ *
+ * resourceProp - valid resource identifier
+ * propVal - valid resource value
+ */
+static int
+setDiskGlobalProp(uint32_t resourceProp, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ sbd_global_props_t *sbdGlobalProps = NULL;
+ int sbdGlobalPropsSize = 0;
+ int propLen;
+ int mluBufSize = 0;
+ int fd;
+ int savedErrno;
+ int ioctlRet;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ switch (resourceProp) {
+ case STMF_LU_PROP_MGMT_URL:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_PROP);
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ propLen = strlen(propVal);
+ mluBufSize += propLen + 1;
+ sbdGlobalPropsSize += sizeof (sbd_global_props_t) - 8 +
+ max(8, mluBufSize);
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdGlobalProps = (sbd_global_props_t *)calloc(1, sbdGlobalPropsSize);
+ if (sbdGlobalProps == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdGlobalProps->mlu_struct_size = sbdGlobalPropsSize;
+
+ switch (resourceProp) {
+ case STMF_LU_PROP_MGMT_URL:
+ sbdGlobalProps->mlu_mgmt_url_valid = 1;
+ bcopy(propVal, &(sbdGlobalProps->mlu_buf),
+ propLen + 1);
+ break;
+ default:
+ ret = STMF_ERROR_NO_PROP;
+ goto done;
+ }
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdGlobalProps->mlu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdGlobalProps;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_SET_GLOBAL_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "modifyDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+done:
+ free(sbdGlobalProps);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfSetLuProp
+ *
+ * Purpose: set a property on an luResource
+ *
+ * hdl - allocated luResource
+ * prop - property identifier
+ * propVal - property value to be set
+ */
+int
+stmfSetLuProp(luResource hdl, uint32_t prop, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResourceImpl *luPropsHdl = hdl;
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (luPropsHdl->type == STMF_DISK) {
+ ret = setDiskProp(luPropsHdl, prop, propVal);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * getDiskProp
+ *
+ * Purpose: retrieve a given property from a logical unit resource of type disk
+ *
+ * hdl - allocated luResourceImpl
+ * prop - property identifier
+ * propVal - pointer to character to contain the retrieved property value
+ * propLen - On input this is the length of propVal. On failure, it contains the
+ * number of bytes required for propVal
+ */
+static int
+getDiskProp(luResourceImpl *hdl, uint32_t prop, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ diskResource *diskLu = hdl->resource;
+ char accessState[20];
+ size_t reqLen;
+
+ if (prop == STMF_LU_PROP_ACCESS_STATE) {
+ if (diskLu->accessState == SBD_LU_ACTIVE) {
+ (void) strlcpy(accessState, STMF_ACCESS_ACTIVE,
+ sizeof (accessState));
+ } else if (diskLu->accessState == SBD_LU_TRANSITION_TO_ACTIVE) {
+ (void) strlcpy(accessState,
+ STMF_ACCESS_STANDBY_TO_ACTIVE,
+ sizeof (accessState));
+ } else if (diskLu->accessState == SBD_LU_STANDBY) {
+ (void) strlcpy(accessState, STMF_ACCESS_STANDBY,
+ sizeof (accessState));
+ } else if (diskLu->accessState ==
+ SBD_LU_TRANSITION_TO_STANDBY) {
+ (void) strlcpy(accessState,
+ STMF_ACCESS_ACTIVE_TO_STANDBY,
+ sizeof (accessState));
+ }
+ if ((reqLen = strlcpy(propVal, accessState,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ return (0);
+ }
+
+ if (diskLu->accessState != SBD_LU_ACTIVE) {
+ return (STMF_ERROR_NO_PROP_STANDBY);
+ }
+
+ switch (prop) {
+ case STMF_LU_PROP_BLOCK_SIZE:
+ if (diskLu->blkSizeValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ reqLen = snprintf(propVal, *propLen, "%llu",
+ (u_longlong_t)diskLu->blkSize);
+ if (reqLen >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_FILENAME:
+ if (diskLu->luDataFileNameValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luDataFileName,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_META_FILENAME:
+ if (diskLu->luMetaFileNameValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luMetaFileName,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_MGMT_URL:
+ if (diskLu->luMgmtUrlValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_GUID:
+ if (diskLu->luGuidValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ reqLen = snprintf(propVal, *propLen,
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X",
+ diskLu->luGuid[0], diskLu->luGuid[1],
+ diskLu->luGuid[2], diskLu->luGuid[3],
+ diskLu->luGuid[4], diskLu->luGuid[5],
+ diskLu->luGuid[6], diskLu->luGuid[7],
+ diskLu->luGuid[8], diskLu->luGuid[9],
+ diskLu->luGuid[10], diskLu->luGuid[11],
+ diskLu->luGuid[12], diskLu->luGuid[13],
+ diskLu->luGuid[14], diskLu->luGuid[15]);
+ if (reqLen >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_SERIAL_NUM:
+ if (diskLu->serialNumValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->serialNum,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_SIZE:
+ if (diskLu->luSizeValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ (void) snprintf(propVal, *propLen, "%llu",
+ (u_longlong_t)diskLu->luSize);
+ break;
+ case STMF_LU_PROP_ALIAS:
+ if (diskLu->luAliasValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luAlias,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_VID:
+ if (diskLu->vidValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (*propLen <= sizeof (diskLu->vid)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bcopy(diskLu->vid, propVal, sizeof (diskLu->vid));
+ propVal[sizeof (diskLu->vid)] = 0;
+ break;
+ case STMF_LU_PROP_PID:
+ if (diskLu->pidValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (*propLen <= sizeof (diskLu->pid)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bcopy(diskLu->pid, propVal, sizeof (diskLu->pid));
+ propVal[sizeof (diskLu->pid)] = 0;
+ break;
+ case STMF_LU_PROP_WRITE_PROTECT:
+ if (diskLu->writeProtectEnableValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (diskLu->writeProtectEnable) {
+ if ((reqLen = strlcpy(propVal, "true",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ } else {
+ if ((reqLen = strlcpy(propVal, "false",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+ break;
+ case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+ if (diskLu->writebackCacheDisableValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (diskLu->writebackCacheDisable) {
+ if ((reqLen = strlcpy(propVal, "true",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ } else {
+ if ((reqLen = strlcpy(propVal, "false",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_PROP;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * setDiskProp
+ *
+ * Purpose: set properties for resource of type disk
+ *
+ * hdl - allocated luResourceImpl
+ * resourceProp - valid resource identifier
+ * propVal - valid resource value
+ */
+static int
+setDiskProp(luResourceImpl *hdl, uint32_t resourceProp, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int i;
+ diskResource *diskLu = hdl->resource;
+ unsigned long long numericProp = 0;
+ char guidProp[LU_ASCII_GUID_SIZE + 1];
+ char ouiProp[OUI_ASCII_SIZE + 1];
+ char hostIdProp[HOST_ID_ASCII_SIZE + 1];
+ unsigned int oui[OUI_SIZE];
+ unsigned int hostId[HOST_ID_SIZE];
+ unsigned int guid[LU_GUID_SIZE];
+ int propSize;
+
+
+ if (propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ switch (resourceProp) {
+ case STMF_LU_PROP_ALIAS:
+ if (strlcpy(diskLu->luAlias, propVal,
+ sizeof (diskLu->luAlias)) >=
+ sizeof (diskLu->luAlias)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luAliasValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_BLOCK_SIZE: {
+ const char *tmp = propVal;
+ while (*tmp) {
+ if (!isdigit(*tmp++)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+ (void) sscanf(propVal, "%llu", &numericProp);
+ if (numericProp > UINT16_MAX) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->blkSize = numericProp;
+ diskLu->blkSizeValid = B_TRUE;
+ break;
+ }
+ case STMF_LU_PROP_COMPANY_ID:
+ if ((strlcpy(ouiProp, propVal, sizeof (ouiProp))) >=
+ sizeof (ouiProp)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (checkHexUpper(ouiProp) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ (void) sscanf(ouiProp, "%2X%2X%2X",
+ &oui[0], &oui[1], &oui[2]);
+
+ diskLu->companyId = 0;
+ diskLu->companyId += oui[0] << 16;
+ diskLu->companyId += oui[1] << 8;
+ diskLu->companyId += oui[2];
+ if (diskLu->companyId == 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->companyIdValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_HOST_ID:
+ if ((strlcpy(hostIdProp, propVal,
+ sizeof (hostIdProp))) >= sizeof (hostIdProp)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (checkHexUpper(hostIdProp) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ (void) sscanf(hostIdProp, "%2X%2X%2X%2X",
+ &hostId[0], &hostId[1], &hostId[2], &hostId[3]);
+
+ diskLu->hostId = 0;
+ diskLu->hostId += hostId[0] << 24;
+ diskLu->hostId += hostId[1] << 16;
+ diskLu->hostId += hostId[2] << 8;
+ diskLu->hostId += hostId[3];
+ if (diskLu->hostId == 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->hostIdValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_GUID:
+ if (strlen(propVal) != LU_ASCII_GUID_SIZE) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+
+ if ((strlcpy(guidProp, propVal, sizeof (guidProp))) >=
+ sizeof (guidProp)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (checkHexUpper(guidProp) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ (void) sscanf(guidProp,
+ "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
+ &guid[0], &guid[1], &guid[2], &guid[3], &guid[4],
+ &guid[5], &guid[6], &guid[7], &guid[8], &guid[9],
+ &guid[10], &guid[11], &guid[12], &guid[13],
+ &guid[14], &guid[15]);
+ for (i = 0; i < sizeof (diskLu->luGuid); i++) {
+ diskLu->luGuid[i] = guid[i];
+ }
+ diskLu->luGuidValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_FILENAME:
+ if ((strlcpy(diskLu->luDataFileName, propVal,
+ sizeof (diskLu->luDataFileName))) >=
+ sizeof (diskLu->luDataFileName)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luDataFileNameValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_META_FILENAME:
+ if ((strlcpy(diskLu->luMetaFileName, propVal,
+ sizeof (diskLu->luMetaFileName))) >=
+ sizeof (diskLu->luMetaFileName)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luMetaFileNameValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_MGMT_URL:
+ if ((strlcpy(diskLu->luMgmtUrl, propVal,
+ sizeof (diskLu->luMgmtUrl))) >=
+ sizeof (diskLu->luMgmtUrl)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luMgmtUrlValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_PID:
+ if ((propSize = strlen(propVal)) >
+ sizeof (diskLu->pid)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ (void) strncpy(diskLu->pid, propVal, propSize);
+ diskLu->pidValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_SERIAL_NUM:
+ if ((propSize = strlen(propVal)) >
+ (sizeof (diskLu->serialNum) - 1)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ (void) strncpy(diskLu->serialNum, propVal, propSize);
+ diskLu->serialNumValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_SIZE:
+ if ((niceStrToNum(propVal, &diskLu->luSize) != 0)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->luSizeValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_VID:
+ if ((propSize = strlen(propVal)) >
+ sizeof (diskLu->vid)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ (void) strncpy(diskLu->vid, propVal, propSize);
+ diskLu->vidValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_WRITE_PROTECT:
+ if (strcasecmp(propVal, "TRUE") == 0) {
+ diskLu->writeProtectEnable = B_TRUE;
+ } else if (strcasecmp(propVal, "FALSE") == 0) {
+ diskLu->writeProtectEnable = B_FALSE;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->writeProtectEnableValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+ if (strcasecmp(propVal, "TRUE") == 0) {
+ diskLu->writebackCacheDisable = B_TRUE;
+ } else if (strcasecmp(propVal, "FALSE") == 0) {
+ diskLu->writebackCacheDisable = B_FALSE;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->writebackCacheDisableValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_ACCESS_STATE:
+ ret = STMF_ERROR_INVALID_PROP;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_PROP;
+ break;
+ }
+ return (ret);
+}
+
+static int
+checkHexUpper(char *buf)
+{
+ int i;
+
+ for (i = 0; i < strlen(buf); i++) {
+ if (isxdigit(buf[i])) {
+ buf[i] = toupper(buf[i]);
+ continue;
+ }
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Given a numeric suffix, convert the value into a number of bits that the
+ * resulting value must be shifted.
+ * Code lifted from libzfs_util.c
+ */
+static int
+strToShift(const char *buf)
+{
+ const char *ends = "BKMGTPE";
+ int i;
+
+ if (buf[0] == '\0')
+ return (0);
+
+ for (i = 0; i < strlen(ends); i++) {
+ if (toupper(buf[0]) == ends[i])
+ return (10*i);
+ }
+
+ return (-1);
+}
+
+int
+stmfFreeLuResource(luResource hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ luResourceImpl *hdlImpl = hdl;
+ free(hdlImpl->resource);
+ free(hdlImpl);
+ return (ret);
+}
+
+/*
+ * Convert a string of the form '100G' into a real number. Used when setting
+ * the size of a logical unit.
+ * Code lifted from libzfs_util.c
+ */
+static int
+niceStrToNum(const char *value, uint64_t *num)
+{
+ char *end;
+ int shift;
+
+ *num = 0;
+
+ /* Check to see if this looks like a number. */
+ if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
+ return (-1);
+ }
+
+ /* Rely on stroull() to process the numeric portion. */
+ errno = 0;
+ *num = strtoull(value, &end, 10);
+
+ /*
+ * Check for ERANGE, which indicates that the value is too large to fit
+ * in a 64-bit value.
+ */
+ if (errno == ERANGE) {
+ return (-1);
+ }
+
+ /*
+ * If we have a decimal value, then do the computation with floating
+ * point arithmetic. Otherwise, use standard arithmetic.
+ */
+ if (*end == '.') {
+ double fval = strtod(value, &end);
+
+ if ((shift = strToShift(end)) == -1) {
+ return (-1);
+ }
+
+ fval *= pow(2, shift);
+
+ if (fval > UINT64_MAX) {
+ return (-1);
+ }
+
+ *num = (uint64_t)fval;
+ } else {
+ if ((shift = strToShift(end)) == -1) {
+ return (-1);
+ }
+
+ /* Check for overflow */
+ if (shift >= 64 || (*num << shift) >> shift != *num) {
+ return (-1);
+ }
+
+ *num <<= shift;
+ }
+
+ return (0);
+}
+
+/*
+ * stmfCreateTargetGroup
+ *
+ * Purpose: Create a local port group
+ *
+ * targetGroupName - name of local port group to create
+ */
+int
+stmfCreateTargetGroup(stmfGroupName *targetGroupName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName))) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Add the group to the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
+ targetGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the add to the driver was successful, add it to the persistent
+ * store.
+ */
+ ret = psCreateTargetGroup((char *)targetGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfCreateTargetGroup:psCreateTargetGroup"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDeleteHostGroup
+ *
+ * Purpose: Delete an initiator or local port group
+ *
+ * hostGroupName - group to delete
+ */
+int
+stmfDeleteHostGroup(stmfGroupName *hostGroupName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Remove the group from the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP,
+ hostGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the remove from the driver was successful, remove it from the
+ * persistent store.
+ */
+ ret = psDeleteHostGroup((char *)hostGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDeleteTargetGroup
+ *
+ * Purpose: Delete an initiator or local port group
+ *
+ * targetGroupName - group to delete
+ */
+int
+stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (targetGroupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Remove the group from the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP,
+ targetGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the remove from the driver was successful, remove it from the
+ * persistent store.
+ */
+ ret = psDeleteTargetGroup((char *)targetGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfDeleteTargetGroup:psDeleteTargetGroup"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDevidFromIscsiName
+ *
+ * Purpose: convert an iSCSI name to an stmf devid
+ *
+ * iscsiName - unicode nul terminated utf-8 encoded iSCSI name
+ * devid - on success, contains the converted iscsi name
+ */
+int
+stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid)
+{
+ if (devid == NULL || iscsiName == NULL)
+ return (STMF_ERROR_INVALID_ARG);
+
+ bzero(devid, sizeof (stmfDevid));
+
+ /* Validate size of target */
+ if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME ||
+ devid->identLength < strlen(EUI) ||
+ devid->identLength < strlen(IQN)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) &&
+ strncmp(iscsiName, IQN, strlen(IQN)) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* copy UTF-8 bytes to ident */
+ bcopy(iscsiName, devid->ident, devid->identLength);
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfDevidFromWwn
+ *
+ * Purpose: convert a WWN to an stmf devid
+ *
+ * wwn - 8-byte wwn identifier
+ * devid - on success, contains the converted wwn
+ */
+int
+stmfDevidFromWwn(uchar_t *wwn, stmfDevid *devid)
+{
+ if (wwn == NULL || devid == NULL)
+ return (STMF_ERROR_INVALID_ARG);
+
+ bzero(devid, sizeof (stmfDevid));
+
+ /* Copy eui prefix */
+ (void) bcopy(WWN, devid->ident, strlen(WWN));
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf((char *)&devid->ident[strlen(WWN)],
+ sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X",
+ wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
+
+ devid->identLength = strlen((char *)devid->ident);
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfFreeMemory
+ *
+ * Purpose: Free memory allocated by this library
+ *
+ * memory - previously allocated pointer of memory managed by library
+ */
+void
+stmfFreeMemory(void *memory)
+{
+ free(memory);
+}
+
+/*
+ * get host group, target group list from stmf
+ *
+ * groupType - HOST_GROUP, TARGET_GROUP
+ */
+static int
+groupListIoctl(stmfGroupList **groupList, int groupType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+ /* framework group list */
+ stmf_group_name_t *iGroupList = NULL;
+ uint32_t groupListSize;
+
+ if (groupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (groupType == HOST_GROUP) {
+ cmd = STMF_IOCTL_GET_HG_LIST;
+ } else if (groupType == TARGET_GROUP) {
+ cmd = STMF_IOCTL_GET_TG_LIST;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ groupListSize = ALLOC_GROUP;
+ groupListSize = groupListSize * (sizeof (stmf_group_name_t));
+ iGroupList = (stmf_group_name_t *)calloc(1, groupListSize);
+ if (iGroupList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the group list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GROUP) {
+ groupListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (stmf_group_name_t);
+ iGroupList = realloc(iGroupList, groupListSize);
+ if (iGroupList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /* allocate and copy to caller's buffer */
+ *groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
+ sizeof (stmfGroupName) * stmfIoctl.stmf_obuf_nentries);
+ if (*groupList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ (*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
+ bcopy(iGroupList[i].name, (*groupList)->name[i],
+ sizeof (stmfGroupName));
+ }
+
+done:
+ free(iGroupList);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * get host group members, target group members from stmf
+ *
+ * groupProps - allocated on success
+ *
+ * groupType - HOST_GROUP, TARGET_GROUP
+ */
+static int
+groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
+ int groupType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+ /* framework group list */
+ stmf_group_name_t iGroupName;
+ stmf_ge_ident_t *iGroupMembers;
+ uint32_t groupListSize;
+
+ if (groupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (groupType == HOST_GROUP) {
+ cmd = STMF_IOCTL_GET_HG_ENTRIES;
+ } else if (groupType == TARGET_GROUP) {
+ cmd = STMF_IOCTL_GET_TG_ENTRIES;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&iGroupName, sizeof (iGroupName));
+
+ bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
+
+ iGroupName.name_size = strlen((char *)groupName);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ groupListSize = ALLOC_GRP_MEMBER;
+ groupListSize = groupListSize * (sizeof (stmf_ge_ident_t));
+ iGroupMembers = (stmf_ge_ident_t *)calloc(1, groupListSize);
+ if (iGroupMembers == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the group list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GRP_MEMBER) {
+ groupListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (stmf_ge_ident_t);
+ iGroupMembers = realloc(iGroupMembers, groupListSize);
+ if (iGroupMembers == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /* allocate and copy to caller's buffer */
+ *groupProps = (stmfGroupProperties *)calloc(1,
+ sizeof (stmfGroupProperties) +
+ sizeof (stmfDevid) * stmfIoctl.stmf_obuf_nentries);
+ if (*groupProps == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ (*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
+ (*groupProps)->name[i].identLength =
+ iGroupMembers[i].ident_size;
+ bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident,
+ iGroupMembers[i].ident_size);
+ }
+
+done:
+ free(iGroupMembers);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * Purpose: access persistent config data for host groups and target groups
+ */
+static int
+iLoadGroupFromPs(stmfGroupList **groupList, int type)
+{
+ int ret;
+
+ if (groupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (type == HOST_GROUP) {
+ ret = psGetHostGroupList(groupList);
+ } else if (type == TARGET_GROUP) {
+ ret = psGetTargetGroupList(groupList);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetHostGroupList:psGetHostGroupList:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetHostGroupList
+ *
+ * Purpose: Retrieves the list of initiator group oids
+ *
+ * hostGroupList - pointer to pointer to hostGroupList structure
+ * on success, this contains the host group list.
+ */
+int
+stmfGetHostGroupList(stmfGroupList **hostGroupList)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if (hostGroupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupListIoctl(hostGroupList, HOST_GROUP);
+ return (ret);
+}
+
+
+/*
+ * Purpose: access persistent config data for host groups and target groups
+ */
+static int
+iLoadGroupMembersFromPs(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp, int type)
+{
+ int ret;
+
+ if (groupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (type == HOST_GROUP) {
+ ret = psGetHostGroupMemberList((char *)groupName, groupProp);
+ } else if (type == TARGET_GROUP) {
+ ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "iLoadGroupMembersFromPs:psGetHostGroupList:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetHostGroupMembers
+ *
+ * Purpose: Retrieves the group properties for a host group
+ *
+ * groupName - name of group for which to retrieve host group members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ * on success, this contains the list of group members.
+ */
+int
+stmfGetHostGroupMembers(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp)
+{
+ int ret;
+
+ if (groupName == NULL || groupProp == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupMemberListIoctl(groupName, groupProp, HOST_GROUP);
+
+ return (ret);
+}
+
+/*
+ * stmfGetProviderData
+ *
+ * Purpose: Get provider data list
+ *
+ * providerName - name of provider for which to retrieve the data
+ * nvl - pointer to nvlist_t pointer which will contain the nvlist data
+ * retrieved.
+ * providerType - type of provider for which to retrieve data.
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ */
+int
+stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType)
+{
+ return (stmfGetProviderDataProt(providerName, nvl, providerType,
+ NULL));
+}
+
+/*
+ * stmfGetProviderDataProt
+ *
+ * Purpose: Get provider data list with token
+ *
+ * providerName - name of provider for which to retrieve the data
+ * nvl - pointer to nvlist_t pointer which will contain the nvlist data
+ * retrieved.
+ * providerType - type of provider for which to retrieve data.
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ * setToken - Returns the stale data token
+ */
+int
+stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret;
+
+ if (providerName == NULL || nvl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ return (getProviderData(providerName, nvl, providerType, setToken));
+}
+
+/*
+ * stmfGetProviderDataList
+ *
+ * Purpose: Get the list of providers currently persisting data
+ *
+ * providerList - pointer to pointer to an stmfProviderList structure allocated
+ * by the caller. Will contain the list of providers on success.
+ */
+int
+stmfGetProviderDataList(stmfProviderList **providerList)
+{
+ int ret;
+
+ ret = psGetProviderDataList(providerList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetProviderDataList:psGetProviderDataList"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * stmfGetSessionList
+ *
+ * Purpose: Retrieves the session list for a target (devid)
+ *
+ * devid - devid of target for which to retrieve session information.
+ * sessionList - pointer to pointer to stmfSessionList structure
+ * on success, this contains the list of initiator sessions.
+ */
+int
+stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_SESSION_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ slist_scsi_session_t *fSessionList, *fSessionListP = NULL;
+ uint8_t ident[260];
+ uint32_t fSessionListSize;
+
+ if (sessionList == NULL || devid == NULL) {
+ ret = STMF_ERROR_INVALID_ARG;
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fSessionListSize = ALLOC_SESSION;
+ fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
+ fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
+ fSessionListP = fSessionList;
+ if (fSessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the session list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident;
+ stmfIoctl.stmf_ibuf_size = sizeof (ident);
+ stmfIoctl.stmf_obuf_size = fSessionListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetSessionList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_SESSION) {
+ fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_scsi_session_t);
+ fSessionList = realloc(fSessionList, fSessionListSize);
+ if (fSessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ fSessionListP = fSessionList;
+ stmfIoctl.stmf_obuf_size = fSessionListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetSessionList:ioctl "
+ "errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) +
+ stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession));
+ if (*sessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ free(sessionList);
+ goto done;
+ }
+
+ (*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
+
+ /*
+ * copy session info to caller's buffer
+ */
+ for (i = 0; i < (*sessionList)->cnt; i++) {
+ (*sessionList)->session[i].initiator.identLength =
+ fSessionList->initiator[IDENT_LENGTH_BYTE];
+ bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]),
+ (*sessionList)->session[i].initiator.ident,
+ STMF_IDENT_LENGTH);
+ bcopy(&(fSessionList->alias),
+ &((*sessionList)->session[i].alias),
+ sizeof ((*sessionList)->session[i].alias));
+ bcopy(&(fSessionList++->creation_time),
+ &((*sessionList)->session[i].creationTime),
+ sizeof (time_t));
+ }
+done:
+ (void) close(fd);
+ free(fSessionListP);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetGroupList
+ *
+ * Purpose: Retrieves the list of target groups
+ *
+ * targetGroupList - pointer to a pointer to an stmfGroupList structure. On
+ * success, it contains the list of target groups.
+ */
+int
+stmfGetTargetGroupList(stmfGroupList **targetGroupList)
+{
+ int ret;
+
+ if (targetGroupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupListIoctl(targetGroupList, TARGET_GROUP);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetGroupMembers
+ *
+ * Purpose: Retrieves the group members for a target group
+ *
+ * groupName - name of target group for which to retrieve members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ * on success, this contains the list of group members.
+ */
+int
+stmfGetTargetGroupMembers(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp)
+{
+ int ret;
+
+ if (groupName == NULL || groupProp == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupMemberListIoctl(groupName, groupProp, TARGET_GROUP);
+
+ return (ret);
+}
+
+/*
+ * stmfGetTargetList
+ *
+ * Purpose: Retrieves the list of target ports
+ *
+ * targetList - pointer to a pointer to an stmfDevidList structure.
+ * On success, it contains the list of local ports (target).
+ */
+int
+stmfGetTargetList(stmfDevidList **targetList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ /* framework target port list */
+ slist_target_port_t *fTargetList, *fTargetListP = NULL;
+ uint32_t fTargetListSize;
+
+ if (targetList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fTargetListSize = ALLOC_TARGET_PORT * sizeof (slist_target_port_t);
+ fTargetListP = fTargetList =
+ (slist_target_port_t *)calloc(1, fTargetListSize);
+ if (fTargetList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to retrieve target list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = fTargetListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
+ ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetList:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_TARGET_PORT) {
+ fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_target_port_t);
+ fTargetListP = fTargetList =
+ realloc(fTargetList, fTargetListSize);
+ if (fTargetList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_obuf_size = fTargetListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
+ ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST,
+ &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ *targetList = (stmfDevidList *)calloc(1,
+ stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
+ sizeof (stmfDevidList));
+ if (*targetList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ (*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
+ (*targetList)->devid[i].identLength =
+ fTargetList->target[IDENT_LENGTH_BYTE];
+ bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1],
+ &(*targetList)->devid[i].ident,
+ fTargetList->target[IDENT_LENGTH_BYTE]);
+ }
+
+done:
+ (void) close(fd);
+ free(fTargetListP);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetProperties
+ *
+ * Purpose: Retrieves the properties for a logical unit
+ *
+ * devid - devid of the target for which to retrieve properties
+ * targetProps - pointer to an stmfTargetProperties structure.
+ * On success, it contains the target properties for
+ * the specified devid.
+ */
+int
+stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ sioc_target_port_props_t targetProperties;
+ scsi_devid_desc_t *scsiDevid;
+
+ if (devid == NULL || targetProps == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties;
+ stmfIoctl.stmf_obuf_size = sizeof (targetProperties);
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES,
+ &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetProperties:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ bcopy(targetProperties.tgt_provider_name, targetProps->providerName,
+ sizeof (targetProperties.tgt_provider_name));
+ if (targetProperties.tgt_state == STMF_STATE_ONLINE) {
+ targetProps->status = STMF_TARGET_PORT_ONLINE;
+ } else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) {
+ targetProps->status = STMF_TARGET_PORT_OFFLINE;
+ } else if (targetProperties.tgt_state == STMF_STATE_ONLINING) {
+ targetProps->status = STMF_TARGET_PORT_ONLINING;
+ } else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) {
+ targetProps->status = STMF_TARGET_PORT_OFFLINING;
+ }
+ bcopy(targetProperties.tgt_alias, targetProps->alias,
+ sizeof (targetProps->alias));
+
+ scsiDevid = (scsi_devid_desc_t *)&targetProperties.tgt_id;
+ targetProps->protocol = scsiDevid->protocol_id;
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetLogicalUnitList
+ *
+ * Purpose: Retrieves list of logical unit Object IDs
+ *
+ * luList - pointer to a pointer to a stmfGuidList structure. On success,
+ * it contains the list of logical unit guids.
+ *
+ */
+int
+stmfGetLogicalUnitList(stmfGuidList **luList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_LU_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ slist_lu_t *fLuList;
+ uint32_t fLuListSize;
+ uint32_t listCnt;
+
+ if (luList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fLuListSize = ALLOC_LU;
+ fLuListSize = fLuListSize * (sizeof (slist_lu_t));
+ fLuList = (slist_lu_t *)calloc(1, fLuListSize);
+ if (fLuList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the LU list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = fLuListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_LU) {
+ fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_lu_t);
+ free(fLuList);
+ fLuList = (slist_lu_t *)calloc(1, fLuListSize);
+ if (fLuList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_obuf_size = fLuListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ listCnt = stmfIoctl.stmf_obuf_nentries;
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
+ listCnt * sizeof (stmfGuid));
+ if (*luList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ (*luList)->cnt = listCnt;
+
+ /* copy to caller's buffer */
+ for (i = 0; i < listCnt; i++) {
+ bcopy(&fLuList[i].lu_guid, (*luList)->guid[i].guid,
+ sizeof (stmfGuid));
+ }
+
+ /*
+ * sort the list. This gives a consistent view across gets
+ */
+ qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
+ sizeof (stmfGuid), guidCompare);
+
+done:
+ (void) close(fd);
+ /*
+ * free internal buffers
+ */
+ free(fLuList);
+ return (ret);
+}
+
+/*
+ * stmfGetLogicalUnitProperties
+ *
+ * Purpose: Retrieves the properties for a logical unit
+ *
+ * lu - guid of the logical unit for which to retrieve properties
+ * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success,
+ * it contains the logical unit properties for the specified guid.
+ */
+int
+stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int stmfRet;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_GET_LU_PROPERTIES;
+ stmfViewEntryList *viewEntryList = NULL;
+ stmf_iocdata_t stmfIoctl;
+ sioc_lu_props_t fLuProps;
+
+ if (lu == NULL || luProps == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(luProps, sizeof (stmfLogicalUnitProperties));
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps;
+ stmfIoctl.stmf_obuf_size = sizeof (fLuProps);
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ stmfRet = stmfGetViewEntryList(lu,
+ &viewEntryList);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ luProps->status =
+ STMF_LOGICAL_UNIT_UNREGISTERED;
+ if (viewEntryList->cnt > 0) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ ret = STMF_ERROR_NOT_FOUND;
+ }
+ } else {
+ ret = STMF_ERROR_NOT_FOUND;
+ }
+ stmfFreeMemory(viewEntryList);
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnit:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ bcopy(fLuProps.lu_provider_name, luProps->providerName,
+ sizeof (fLuProps.lu_provider_name));
+ if (fLuProps.lu_state == STMF_STATE_ONLINE) {
+ luProps->status = STMF_LOGICAL_UNIT_ONLINE;
+ } else if (fLuProps.lu_state == STMF_STATE_OFFLINE) {
+ luProps->status = STMF_LOGICAL_UNIT_OFFLINE;
+ } else if (fLuProps.lu_state == STMF_STATE_ONLINING) {
+ luProps->status = STMF_LOGICAL_UNIT_ONLINING;
+ } else if (fLuProps.lu_state == STMF_STATE_OFFLINING) {
+ luProps->status = STMF_LOGICAL_UNIT_OFFLINING;
+ }
+ bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias));
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetState
+ *
+ * Purpose: retrieve the current state of the stmf module
+ *
+ * state - pointer to stmfState structure allocated by the caller
+ * On success, contains the state of stmf
+ */
+int
+stmfGetState(stmfState *state)
+{
+ int ret;
+ stmf_state_desc_t iState;
+
+ if (state == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = getStmfState(&iState);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ switch (iState.state) {
+ case STMF_STATE_ONLINE:
+ state->operationalState =
+ STMF_SERVICE_STATE_ONLINE;
+ break;
+ case STMF_STATE_OFFLINE:
+ state->operationalState =
+ STMF_SERVICE_STATE_OFFLINE;
+ break;
+ case STMF_STATE_ONLINING:
+ state->operationalState =
+ STMF_SERVICE_STATE_ONLINING;
+ break;
+ case STMF_STATE_OFFLINING:
+ state->operationalState =
+ STMF_SERVICE_STATE_OFFLINING;
+ break;
+ default:
+ state->operationalState =
+ STMF_SERVICE_STATE_UNKNOWN;
+ break;
+ }
+ switch (iState.config_state) {
+ case STMF_CONFIG_NONE:
+ state->configState = STMF_CONFIG_STATE_NONE;
+ break;
+ case STMF_CONFIG_INIT:
+ state->configState = STMF_CONFIG_STATE_INIT;
+ break;
+ case STMF_CONFIG_INIT_DONE:
+ state->configState =
+ STMF_CONFIG_STATE_INIT_DONE;
+ break;
+ default:
+ state->configState =
+ STMF_CONFIG_STATE_UNKNOWN;
+ break;
+ }
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfGetViewEntryList
+ *
+ * Purpose: Retrieves the list of view entries for the specified
+ * logical unit.
+ *
+ * lu - the guid of the logical unit for which to retrieve the view entry list
+ * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On
+ * success, contains the list of view entries.
+ */
+int
+stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_LU_VE_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t *fVeList;
+ uint32_t fVeListSize;
+ uint32_t listCnt;
+
+ if (lu == NULL || viewEntryList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fVeListSize = ALLOC_VE;
+ fVeListSize = fVeListSize * (sizeof (stmf_view_op_entry_t));
+ fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
+ if (fVeList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the LU list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
+ stmfIoctl.stmf_obuf_size = fVeListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetViewEntryList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_VE) {
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ fVeListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (stmf_view_op_entry_t);
+ free(fVeList);
+ fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
+ if (fVeList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+ stmfIoctl.stmf_obuf_size = fVeListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ listCnt = stmfIoctl.stmf_obuf_nentries;
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *viewEntryList = (stmfViewEntryList *)calloc(1,
+ sizeof (stmfViewEntryList) + listCnt * sizeof (stmfViewEntry));
+ if (*viewEntryList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ (*viewEntryList)->cnt = listCnt;
+
+ /* copy to caller's buffer */
+ for (i = 0; i < listCnt; i++) {
+ (*viewEntryList)->ve[i].veIndexValid = B_TRUE;
+ (*viewEntryList)->ve[i].veIndex = fVeList[i].ve_ndx;
+ if (fVeList[i].ve_all_hosts == 1) {
+ (*viewEntryList)->ve[i].allHosts = B_TRUE;
+ } else {
+ bcopy(fVeList[i].ve_host_group.name,
+ (*viewEntryList)->ve[i].hostGroup,
+ fVeList[i].ve_host_group.name_size);
+ }
+ if (fVeList[i].ve_all_targets == 1) {
+ (*viewEntryList)->ve[i].allTargets = B_TRUE;
+ } else {
+ bcopy(fVeList[i].ve_target_group.name,
+ (*viewEntryList)->ve[i].targetGroup,
+ fVeList[i].ve_target_group.name_size);
+ }
+ bcopy(fVeList[i].ve_lu_nbr, (*viewEntryList)->ve[i].luNbr,
+ sizeof ((*viewEntryList)->ve[i].luNbr));
+ (*viewEntryList)->ve[i].luNbrValid = B_TRUE;
+ }
+
+ /*
+ * sort the list. This gives a consistent view across gets
+ */
+ qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
+ sizeof (stmfViewEntry), viewEntryCompare);
+
+done:
+ (void) close(fd);
+ /*
+ * free internal buffers
+ */
+ free(fVeList);
+ return (ret);
+}
+
+
+/*
+ * loadHostGroups
+ *
+ * Purpose - issues the ioctl to load the host groups into stmf
+ *
+ * fd - file descriptor for the control node of stmf.
+ * groupList - populated host group list
+ */
+static int
+loadHostGroups(int fd, stmfGroupList *groupList)
+{
+ int i, j;
+ int ret = STMF_STATUS_SUCCESS;
+ stmfGroupProperties *groupProps = NULL;
+
+ for (i = 0; i < groupList->cnt; i++) {
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
+ &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
+ &groupProps, HOST_GROUP);
+ for (j = 0; j < groupProps->cnt; j++) {
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
+ &(groupList->name[i]), &(groupProps->name[j])))
+ != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+
+out:
+ stmfFreeMemory(groupProps);
+ return (ret);
+}
+
+/*
+ * loadTargetGroups
+ *
+ * Purpose - issues the ioctl to load the target groups into stmf
+ *
+ * fd - file descriptor for the control node of stmf.
+ * groupList - populated target group list.
+ */
+static int
+loadTargetGroups(int fd, stmfGroupList *groupList)
+{
+ int i, j;
+ int ret = STMF_STATUS_SUCCESS;
+ stmfGroupProperties *groupProps = NULL;
+
+ for (i = 0; i < groupList->cnt; i++) {
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
+ &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
+ &groupProps, TARGET_GROUP);
+ for (j = 0; j < groupProps->cnt; j++) {
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
+ &(groupList->name[i]), &(groupProps->name[j])))
+ != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+
+out:
+ stmfFreeMemory(groupProps);
+ return (ret);
+}
+
+
+/*
+ * loadStore
+ *
+ * Purpose: Load the configuration data from the store
+ *
+ * First load the host groups and target groups, then the view entries
+ * and finally the provider data
+ *
+ * fd - file descriptor of control node for stmf.
+ */
+static int
+loadStore(int fd)
+{
+ int ret;
+ int i, j;
+ stmfGroupList *groupList = NULL;
+ stmfGuidList *guidList = NULL;
+ stmfViewEntryList *viewEntryList = NULL;
+ stmfProviderList *providerList = NULL;
+ int providerType;
+ nvlist_t *nvl = NULL;
+
+
+
+ /* load host groups */
+ ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ ret = loadHostGroups(fd, groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ stmfFreeMemory(groupList);
+ groupList = NULL;
+
+ /* load target groups */
+ ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = loadTargetGroups(fd, groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ stmfFreeMemory(groupList);
+ groupList = NULL;
+
+ /* Get the guid list */
+ ret = psGetLogicalUnitList(&guidList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * We have the guid list, now get the corresponding
+ * view entries for each guid
+ */
+ for (i = 0; i < guidList->cnt; i++) {
+ ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ for (j = 0; j < viewEntryList->cnt; j++) {
+ ret = addViewEntryIoctl(fd, &guidList->guid[i],
+ &viewEntryList->ve[j]);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+ /* get the list of providers that have data */
+ ret = psGetProviderDataList(&providerList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ for (i = 0; i < providerList->cnt; i++) {
+ providerType = providerList->provider[i].providerType;
+ ret = psGetProviderData(providerList->provider[i].name,
+ &nvl, providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ /* call setProviderData */
+ ret = setProviderData(fd, providerList->provider[i].name, nvl,
+ providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ nvlist_free(nvl);
+ nvl = NULL;
+ }
+out:
+ if (groupList != NULL) {
+ free(groupList);
+ }
+ if (guidList != NULL) {
+ free(guidList);
+ }
+ if (viewEntryList != NULL) {
+ free(viewEntryList);
+ }
+ if (nvl != NULL) {
+ nvlist_free(nvl);
+ }
+ return (ret);
+}
+
+/*
+ * stmfGetAluaState
+ *
+ * Purpose - Get the alua state
+ *
+ */
+int
+stmfGetAluaState(boolean_t *enabled, uint32_t *node)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ stmf_iocdata_t stmfIoctl = {0};
+ stmf_alua_state_desc_t alua_state = {0};
+ int ioctlRet;
+
+ if (enabled == NULL || node == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = sizeof (alua_state);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&alua_state;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_ALUA_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ } else {
+ if (alua_state.alua_state == 1) {
+ *enabled = B_TRUE;
+ } else {
+ *enabled = B_FALSE;
+ }
+ *node = alua_state.alua_node;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfSetAluaState
+ *
+ * Purpose - set the alua state to enabled/disabled
+ *
+ */
+int
+stmfSetAluaState(boolean_t enabled, uint32_t node)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ stmf_iocdata_t stmfIoctl = {0};
+ stmf_alua_state_desc_t alua_state = {0};
+ int ioctlRet;
+
+ if ((enabled != B_TRUE && enabled != B_FALSE) || (node > 1)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (enabled) {
+ alua_state.alua_state = 1;
+ }
+
+ alua_state.alua_node = node;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (alua_state);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&alua_state;
+ ioctlRet = ioctl(fd, STMF_IOCTL_SET_ALUA_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+ if (!enabled && ret == STMF_STATUS_SUCCESS) {
+ deleteNonActiveLus();
+ }
+
+ return (ret);
+}
+
+static void
+deleteNonActiveLus()
+{
+ int stmfRet;
+ int i;
+ stmfGuidList *luList;
+ luResource hdl = NULL;
+ char propVal[10];
+ size_t propValSize = sizeof (propVal);
+
+ stmfRet = stmfGetLogicalUnitList(&luList);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ return;
+ }
+
+ for (i = 0; i < luList->cnt; i++) {
+ stmfRet = stmfGetLuResource(&luList->guid[i], &hdl);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ goto err;
+ }
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
+ &propValSize);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ goto err;
+ }
+ if (propVal[0] == '0') {
+ (void) stmfFreeLuResource(hdl);
+ hdl = NULL;
+ continue;
+ }
+ (void) stmfDeleteLu(&luList->guid[i]);
+ (void) stmfFreeLuResource(hdl);
+ hdl = NULL;
+ }
+
+err:
+ stmfFreeMemory(luList);
+ (void) stmfFreeLuResource(hdl);
+}
+
+/*
+ * stmfLoadConfig
+ *
+ * Purpose - load the configuration data from smf into stmf
+ *
+ */
+int
+stmfLoadConfig(void)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ stmf_state_desc_t stmfStateSet;
+ stmfState state;
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ /*
+ * Configuration not stored persistently; nothing to
+ * initialize so do not set to STMF_CONFIG_INIT.
+ */
+ stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
+ goto done;
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+
+
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+ stmfStateSet.config_state = STMF_CONFIG_INIT;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /* Load the persistent configuration data */
+ ret = loadStore(fd);
+ if (ret != 0) {
+ goto done;
+ }
+
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+ stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
+
+done:
+ if (ret == STMF_STATUS_SUCCESS) {
+ ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+ }
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * getStmfState
+ *
+ * stmfState - pointer to stmf_state_desc_t structure. Will contain the state
+ * information of the stmf service on success.
+ */
+static int
+getStmfState(stmf_state_desc_t *stmfState)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
+ stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+ return (ret);
+}
+
+
+/*
+ * setStmfState
+ *
+ * stmfState - pointer to caller set state structure
+ * objectType - one of:
+ * LOGICAL_UNIT_TYPE
+ * TARGET_TYPE
+ * STMF_SERVICE_TYPE
+ */
+static int
+setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+
+ switch (objectType) {
+ case LOGICAL_UNIT_TYPE:
+ cmd = STMF_IOCTL_SET_LU_STATE;
+ break;
+ case TARGET_TYPE:
+ cmd = STMF_IOCTL_SET_TARGET_PORT_STATE;
+ break;
+ case STMF_SERVICE_TYPE:
+ cmd = STMF_IOCTL_SET_STMF_STATE;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to set the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+int
+stmfSetStmfProp(uint8_t propType, char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE:
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ ret = psSetStmfProp(propType, propVal);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfSetStmfProp:psSetStmfProp:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ return (ret);
+}
+
+
+int
+stmfGetStmfProp(uint8_t propType, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ char prop[MAXNAMELEN] = {0};
+ size_t reqLen;
+
+ if (propVal == NULL || propLen == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE:
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ ret = psGetStmfProp(propType, prop);
+ if ((reqLen = strlcpy(propVal, prop, *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetStmfProp:psGetStmfProp:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ return (ret);
+}
+
+static int
+setStmfProp(stmf_set_props_t *stmf_set_props)
+{
+ char propVal[MAXNAMELEN] = {0};
+ int ret;
+ if ((ret = psGetStmfProp(STMF_DEFAULT_LU_STATE, propVal)) ==
+ STMF_PS_SUCCESS) {
+ if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
+ stmf_set_props->default_lu_state_value =
+ STMF_STATE_OFFLINE;
+ } else {
+ stmf_set_props->default_lu_state_value =
+ STMF_STATE_ONLINE;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "DefaultLuState:psSetStmfProp:error(%d)", ret);
+ goto done;
+ }
+
+ if ((ret = psGetStmfProp(STMF_DEFAULT_TARGET_PORT_STATE, propVal)) ==
+ STMF_PS_SUCCESS) {
+ if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
+ stmf_set_props->default_target_state_value =
+ STMF_STATE_OFFLINE;
+ } else {
+ stmf_set_props->default_target_state_value =
+ STMF_STATE_ONLINE;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "DefaultTargetPortState:psSetStmfProp:error(%d)", ret);
+ goto done;
+ }
+done:
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ return (ret);
+}
+
+static int
+loadStmfProp(int fd)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl = {0};
+ stmf_set_props_t *stmf_set_props = NULL;
+
+ stmf_set_props = (stmf_set_props_t *)
+ calloc(1, (sizeof (stmf_set_props_t)));
+ if (stmf_set_props == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ /* Loading the default property values from smf */
+
+ if ((ret = setStmfProp(stmf_set_props)) != STMF_STATUS_SUCCESS)
+ goto done;
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_set_props_t);
+ stmfIoctl.stmf_ibuf =
+ (uint64_t)(unsigned long)stmf_set_props;
+
+ ioctlRet = ioctl(fd, STMF_IOCTL_SET_STMF_PROPS,
+ &stmfIoctl);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setDefaultStmfState:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+done:
+ if (stmf_set_props != NULL) {
+ free(stmf_set_props);
+ }
+ return (ret);
+}
+
+int
+stmfLoadStmfProps(void)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ /* open control node for stmf */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
+ != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+ ret = loadStmfProp(fd);
+
+ (void) close(fd);
+done:
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "stmfLoadStmfProps:Failed");
+ }
+ return (ret);
+}
+
+/*
+ * stmfOnline
+ *
+ * Purpose: Online stmf service
+ *
+ */
+int
+stmfOnline(void)
+{
+ int ret;
+ int fd;
+ stmfState state;
+ stmf_state_desc_t iState;
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+ iState.state = STMF_STATE_ONLINE;
+ iState.config_state = STMF_CONFIG_NONE;
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOffline
+ *
+ * Purpose: Offline stmf service
+ *
+ */
+int
+stmfOffline(void)
+{
+ int ret;
+ int fd;
+ stmfState state;
+ stmf_state_desc_t iState;
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_OFFLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+ iState.state = STMF_STATE_OFFLINE;
+ iState.config_state = STMF_CONFIG_NONE;
+
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfOfflineTarget
+ *
+ * Purpose: Change state of target to offline
+ *
+ * devid - devid of the target to offline
+ */
+int
+stmfOfflineTarget(stmfDevid *devid)
+{
+ stmf_state_desc_t targetState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (devid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bzero(&targetState, sizeof (targetState));
+
+ targetState.state = STMF_STATE_OFFLINE;
+ targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &targetState, TARGET_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOfflineLogicalUnit
+ *
+ * Purpose: Change state of logical unit to offline
+ *
+ * lu - guid of the logical unit to offline
+ */
+int
+stmfOfflineLogicalUnit(stmfGuid *lu)
+{
+ stmf_state_desc_t luState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(&luState, sizeof (luState));
+
+ luState.state = STMF_STATE_OFFLINE;
+ bcopy(lu, &luState.ident, sizeof (stmfGuid));
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOnlineTarget
+ *
+ * Purpose: Change state of target to online
+ *
+ * devid - devid of the target to online
+ */
+int
+stmfOnlineTarget(stmfDevid *devid)
+{
+ stmf_state_desc_t targetState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (devid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bzero(&targetState, sizeof (targetState));
+
+ targetState.state = STMF_STATE_ONLINE;
+ targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &targetState, TARGET_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOnlineLogicalUnit
+ *
+ * Purpose: Change state of logical unit to online
+ *
+ * lu - guid of the logical unit to online
+ */
+int
+stmfOnlineLogicalUnit(stmfGuid *lu)
+{
+ stmf_state_desc_t luState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(&luState, sizeof (luState));
+
+ luState.state = STMF_STATE_ONLINE;
+ bcopy(lu, &luState.ident, sizeof (stmfGuid));
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveFromHostGroup
+ *
+ * Purpose: Removes an initiator from an initiator group
+ *
+ * hostGroupName - name of an initiator group
+ * hostName - name of host group member to remove
+ */
+int
+stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || hostName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY,
+ hostGroupName, hostName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psRemoveHostGroupMember((char *)hostGroupName,
+ (char *)hostName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_MEMBER_NOT_FOUND:
+ ret = STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveFromHostGroup"
+ "psRemoveHostGroupMember:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveFromTargetGroup
+ *
+ * Purpose: Removes a local port from a local port group
+ *
+ * targetGroupName - name of a target group
+ * targetName - name of target to remove
+ */
+int
+stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || targetName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY,
+ targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psRemoveTargetGroupMember((char *)targetGroupName,
+ (char *)targetName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_MEMBER_NOT_FOUND:
+ ret = STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveFromTargetGroup"
+ "psRemoveTargetGroupMember:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveViewEntry
+ *
+ * Purpose: Removes a view entry from a logical unit
+ *
+ * lu - guid of lu for which view entry is being removed
+ * viewEntryIndex - index of view entry to remove
+ *
+ */
+int
+stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ ioctlViewEntry.ve_ndx_valid = B_TRUE;
+ ioctlViewEntry.ve_ndx = viewEntryIndex;
+ bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ case ENODEV:
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveViewEntry:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psRemoveViewEntry(lu, viewEntryIndex);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfSetProviderData
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - type of provider for which to set data
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ */
+int
+stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType)
+{
+ return (stmfSetProviderDataProt(providerName, nvl, providerType,
+ NULL));
+}
+
+/*
+ * stmfSetProviderDataProt
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - type of provider for which to set data
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ * setToken - Stale data token returned in the stmfGetProviderDataProt()
+ * call or NULL.
+ */
+int
+stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret;
+ int fd;
+
+ if (providerName == NULL || nvl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = setProviderData(fd, providerName, nvl, providerType, setToken);
+
+ (void) close(fd);
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /* setting driver provider data successful. Now persist it */
+ ret = psSetProviderData(providerName, nvl, providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ case STMF_PS_ERROR_PROV_DATA_STALE:
+ ret = STMF_ERROR_PROV_DATA_STALE;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfSetProviderData"
+ "psSetProviderData:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ return (ret);
+}
+
+/*
+ * getProviderData
+ *
+ * Purpose: set the provider data from stmf
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to load/retrieve
+ * providerType - logical unit or port provider
+ * setToken - returned stale data token
+ */
+int
+getProviderData(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ size_t nvlistSize = ALLOC_PP_DATA_SIZE;
+ int retryCnt = 0;
+ int retryCntMax = MAX_PROVIDER_RETRY;
+ stmf_ppioctl_data_t ppi = {0}, *ppi_out = NULL;
+ boolean_t retry = B_TRUE;
+ stmf_iocdata_t stmfIoctl;
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /* set provider name and provider type */
+ if (strlcpy(ppi.ppi_name, providerName,
+ sizeof (ppi.ppi_name)) >=
+ sizeof (ppi.ppi_name)) {
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi.ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi.ppi_port_provider = 1;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+
+ do {
+ /* allocate memory for ioctl */
+ ppi_out = (stmf_ppioctl_data_t *)calloc(1, nvlistSize +
+ sizeof (stmf_ppioctl_data_t));
+ if (ppi_out == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+
+ }
+
+ /* set the size of the ioctl data to allocated buffer */
+ ppi.ppi_data_size = nvlistSize;
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
+ stmfIoctl.stmf_obuf_size = sizeof (stmf_ppioctl_data_t) +
+ nvlistSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)ppi_out;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EINVAL:
+ if (stmfIoctl.stmf_error ==
+ STMF_IOCERR_INSUFFICIENT_BUF) {
+ nvlistSize =
+ ppi_out->ppi_data_size;
+ free(ppi_out);
+ ppi_out = NULL;
+ if (retryCnt++ > retryCntMax) {
+ retry = B_FALSE;
+ ret = STMF_ERROR_BUSY;
+ } else {
+ ret =
+ STMF_STATUS_SUCCESS;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "getProviderData:ioctl"
+ "unable to retrieve "
+ "nvlist");
+ ret = STMF_STATUS_ERROR;
+ }
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getProviderData:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS)
+ goto done;
+ }
+ } while (retry && stmfIoctl.stmf_error == STMF_IOCERR_INSUFFICIENT_BUF);
+
+ if ((ret = nvlist_unpack((char *)ppi_out->ppi_data,
+ ppi_out->ppi_data_size, nvl, 0)) != 0) {
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+
+ /* caller has asked for new token */
+ if (setToken) {
+ *setToken = ppi_out->ppi_token;
+ }
+done:
+ free(ppi_out);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * setProviderData
+ *
+ * Purpose: set the provider data in stmf
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - logical unit or port provider
+ * setToken - stale data token to check if not NULL
+ */
+static int
+setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ size_t nvlistEncodedSize;
+ stmf_ppioctl_data_t *ppi = NULL;
+ uint64_t outToken;
+ char *allocatedNvBuffer;
+ stmf_iocdata_t stmfIoctl;
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* get size of encoded nvlist */
+ if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* allocate memory for ioctl */
+ ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize +
+ sizeof (stmf_ppioctl_data_t));
+ if (ppi == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ if (setToken) {
+ ppi->ppi_token_valid = 1;
+ ppi->ppi_token = *setToken;
+ }
+
+ allocatedNvBuffer = (char *)&ppi->ppi_data;
+ if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
+ NV_ENCODE_XDR, 0) != 0) {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* set provider name and provider type */
+ (void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name));
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi->ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi->ppi_port_provider = 1;
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* set the size of the ioctl data to packed data size */
+ ppi->ppi_data_size = nvlistEncodedSize;
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ /*
+ * Subtracting 8 from the size as that is the size of the last member
+ * of the structure where the packed data resides
+ */
+ stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
+ sizeof (stmf_ppioctl_data_t) - 8;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
+ stmfIoctl.stmf_obuf_size = sizeof (uint64_t);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&outToken;
+ ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EINVAL:
+ if (stmfIoctl.stmf_error ==
+ STMF_IOCERR_PPD_UPDATED) {
+ ret = STMF_ERROR_PROV_DATA_STALE;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setProviderData:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS)
+ goto done;
+ }
+
+ /* caller has asked for new token */
+ if (setToken) {
+ *setToken = outToken;
+ }
+done:
+ free(ppi);
+ return (ret);
+}
+
+/*
+ * set the persistence method in the library only or library and service
+ */
+int
+stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int oldPersist;
+
+ (void) pthread_mutex_lock(&persistenceTypeLock);
+ oldPersist = iPersistType;
+ if (persistType == STMF_PERSIST_NONE ||
+ persistType == STMF_PERSIST_SMF) {
+ iLibSetPersist = B_TRUE;
+ iPersistType = persistType;
+ } else {
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ /* Is this for this library open or in SMF */
+ if (serviceSet == B_TRUE) {
+ ret = psSetServicePersist(persistType);
+ if (ret != STMF_PS_SUCCESS) {
+ ret = STMF_ERROR_PERSIST_TYPE;
+ /* Set to old value */
+ iPersistType = oldPersist;
+ }
+ }
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+
+ return (ret);
+}
+
+/*
+ * Only returns internal state for persist. If unset, goes to ps. If that
+ * fails, returns default setting
+ */
+static uint8_t
+iGetPersistMethod()
+{
+
+ uint8_t persistType = 0;
+
+ (void) pthread_mutex_lock(&persistenceTypeLock);
+ if (iLibSetPersist) {
+ persistType = iPersistType;
+ } else {
+ int ret;
+ ret = psGetServicePersist(&persistType);
+ if (ret != STMF_PS_SUCCESS) {
+ /* set to default */
+ persistType = STMF_DEFAULT_PERSIST;
+ }
+ }
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+ return (persistType);
+}
+
+/*
+ * Returns either library state or persistent config state depending on
+ * serviceState
+ */
+int
+stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState)
+{
+ int ret = STMF_STATUS_SUCCESS;
+
+ if (persistType == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (serviceState) {
+ ret = psGetServicePersist(persistType);
+ if (ret != STMF_PS_SUCCESS) {
+ ret = STMF_ERROR_PERSIST_TYPE;
+ }
+ } else {
+ (void) pthread_mutex_lock(&persistenceTypeLock);
+ if (iLibSetPersist) {
+ *persistType = iPersistType;
+ } else {
+ *persistType = STMF_DEFAULT_PERSIST;
+ }
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfPostProxyMsg
+ *
+ * Purpose: Post a message to the proxy port provider
+ *
+ * buf - buffer containing message to post
+ * buflen - buffer length
+ */
+int
+stmfPostProxyMsg(int hdl, void *buf, uint32_t buflen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ pppt_iocdata_t ppptIoctl = {0};
+
+ if (buf == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Issue ioctl to post the message
+ */
+ ppptIoctl.pppt_version = PPPT_VERSION_1;
+ ppptIoctl.pppt_buf_size = buflen;
+ ppptIoctl.pppt_buf = (uint64_t)(unsigned long)buf;
+ ioctlRet = ioctl(hdl, PPPT_MESSAGE, &ppptIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ ret = STMF_ERROR_POST_MSG_FAILED;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfInitProxyDoor
+ *
+ * Purpose: Install door in proxy
+ *
+ * hdl - pointer to returned handle
+ * fd - door from door_create()
+ */
+int
+stmfInitProxyDoor(int *hdl, int door)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ int fd;
+ pppt_iocdata_t ppptIoctl = {0};
+
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for pppt
+ */
+ if ((ret = openPppt(OPEN_PPPT, &fd)) != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Issue ioctl to install the door
+ */
+ ppptIoctl.pppt_version = PPPT_VERSION_1;
+ ppptIoctl.pppt_door_fd = (uint32_t)door;
+ ioctlRet = ioctl(fd, PPPT_INSTALL_DOOR, &ppptIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EINVAL:
+ ret = STMF_ERROR_INVALID_ARG;
+ break;
+ case EBUSY:
+ ret = STMF_ERROR_DOOR_INSTALLED;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+
+ /* return driver fd to caller */
+ *hdl = fd;
+ return (ret);
+}
+
+void
+stmfDestroyProxyDoor(int hdl)
+{
+ (void) close(hdl);
+}
+
+/*
+ * validateLunNumIoctl
+ *
+ * Purpose: Issues ioctl to check and get available lun# in view entry
+ *
+ * viewEntry - view entry to use
+ */
+static int
+validateLunNumIoctl(int fd, stmfViewEntry *viewEntry)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ /*
+ * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
+ * false on input
+ */
+ ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
+ ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
+ ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
+
+ if (viewEntry->allHosts == B_FALSE) {
+ bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_host_group.name_size =
+ strlen((char *)viewEntry->hostGroup);
+ }
+ if (viewEntry->allTargets == B_FALSE) {
+ bcopy(viewEntry->targetGroup,
+ &ioctlViewEntry.ve_target_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_target_group.name_size =
+ strlen((char *)viewEntry->targetGroup);
+ }
+ /* Validating the lun number */
+ if (viewEntry->luNbrValid) {
+ bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to validate lun# in the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_VALIDATE_VIEW, &stmfIoctl);
+
+ /* save available lun number */
+ if (!viewEntry->luNbrValid) {
+ bcopy(ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_LU_NUMBER_IN_USE:
+ ret = STMF_ERROR_LUN_IN_USE;
+ break;
+ case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
+ ret = STMF_ERROR_VE_CONFLICT;
+ break;
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ ret = STMF_ERROR_INVALID_HG;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_INVALID_TG;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "addViewEntryIoctl"
+ ":error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * stmfValidateView
+ *
+ * Purpose: Validate or get lun # base on TG, HG of view entry
+ *
+ * viewEntry - view entry structure to use
+ */
+int
+stmfValidateView(stmfViewEntry *viewEntry)
+{
+ int ret;
+ int fd;
+ stmfViewEntry iViewEntry;
+
+ if (viewEntry == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* initialize and set internal view entry */
+ bzero(&iViewEntry, sizeof (iViewEntry));
+
+ if (!viewEntry->allHosts) {
+ bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
+ sizeof (iViewEntry.hostGroup));
+ } else {
+ iViewEntry.allHosts = B_TRUE;
+ }
+
+ if (!viewEntry->allTargets) {
+ bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
+ sizeof (iViewEntry.targetGroup));
+ } else {
+ iViewEntry.allTargets = B_TRUE;
+ }
+
+ if (viewEntry->luNbrValid) {
+ iViewEntry.luNbrValid = B_TRUE;
+ bcopy(viewEntry->luNbr, iViewEntry.luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ /*
+ * set users return view entry index valid flag to false
+ * in case of failure
+ */
+ viewEntry->veIndexValid = B_FALSE;
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Validate lun# in the view entry from the driver
+ */
+ ret = validateLunNumIoctl(fd, &iViewEntry);
+ (void) close(fd);
+
+ /* save available lun number */
+ if (!viewEntry->luNbrValid) {
+ bcopy(iViewEntry.luNbr, viewEntry->luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libstmf/common/store.c b/usr/src/lib/libstmf/common/store.c
new file mode 100644
index 0000000..b6eabd8
--- /dev/null
+++ b/usr/src/lib/libstmf/common/store.c
@@ -0,0 +1,5385 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ */
+
+#include <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 iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *,
+ int);
+static int iPsGetSetStmfProp(int, char *, int);
+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
+
+/*
+ * Note: Do not change these property names and size values.
+ * They represent fields in the persistent config and once modified
+ * will have a nasty side effect of invalidating the existing store.
+ * If you do need to change them, you'll need to use the versioning above
+ * to retain backward compatiblity with the previous configuration schema.
+ */
+
+/* BEGIN STORE PROPERTY DEFINITIONS */
+/*
+ * 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"
+#define STMF_PERSIST_TYPE "persist_method"
+
+/* Property names for stmf properties */
+
+#define DEFAULT_LU_STATE "default_lu_state"
+#define DEFAULT_TARGET_PORT_STATE "default_target_state"
+
+/*
+ * 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"
+
+
+#define STMF_SMF_READ_ATTR "solaris.smf.read.stmf"
+
+#define STMF_PS_PERSIST_NONE "none"
+#define STMF_PS_PERSIST_SMF "smf"
+#define STMF_PROVIDER_DATA_PROP_SIZE 4000
+
+#define STMF_PS_LU_ONLINE "default_lu_online"
+#define STMF_PS_LU_OFFLINE "default_lu_offline"
+#define STMF_PS_TARGET_PORT_ONLINE "default_target_online"
+#define STMF_PS_TARGET_PORT_OFFLINE "default_target_offline"
+
+/* END STORE PROPERTY DEFINITIONS */
+
+/* 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
+#define GET 0
+#define SET 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 {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+
+ goto out;
+ }
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ pgName, 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 %s/%s "
+ "failed - %s", pgName, groupName,
+ scf_strerror(scf_error()));
+ }
+ goto out;
+ }
+
+ /*
+ * Get the property handle
+ */
+ if (scf_pg_get_property(pg, groupName, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, groupName, 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 for %s failed - %s",
+ pgName, 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 values for %s/%s failed - %s",
+ pgName, groupName, 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 %s/%s value failed - %s",
+ pgName, groupName, 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 for %s failed - %s",
+ pgName, 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 for %s/%s failed - %s",
+ pgName, groupName, 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 for %s/%s failed - %s",
+ pgName, groupName, 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 for %s/%s failed - %s",
+ pgName, groupName, 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 for %s/%s failed - %s",
+ pgName, groupName, 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 for %s/%s failed - %s",
+ pgName, groupName, 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 for %s failed - %s",
+ pgName, 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 %s failed - %s",
+ luPgName, 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 lu pg %s failed - %s",
+ luPgName, 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 for %s failed - %s",
+ luPgName, 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 %s/%s "
+ "failed - %s", luPgName, STMF_VE_CNT,
+ 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 %s/%s change "
+ "failed - %s", luPgName, STMF_VE_CNT,
+ 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 %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, 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 %s/%s value failed - %s",
+ luPgName, STMF_VE_CNT, 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 count value %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, 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 %s failed - %s",
+ luPgName, 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 %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, 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 %s/%s failed - %s",
+ luPgName, viewEntryPgName, 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 %s/%s "
+ "failed - %s", luPgName, viewEntryPgName,
+ 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 %s/%s "
+ "failed - %s", luPgName, viewEntryPgName,
+ 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 for %s failed - %s",
+ luPgName, 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 %s failed - %s",
+ viewEntryPgName, 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 for add %s failed - %s",
+ viewEntryPgName, 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 %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ 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 %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ 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 %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ 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 %s/%s "
+ "failed - %s", viewEntryPgName,
+ STMF_VE_TARGETGROUP, 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ 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 %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_LUNBR,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR, 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR, 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 for add %s failed - %s",
+ viewEntryPgName, 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 %s failed"
+ "possible inconsistency - %s", luPgName,
+ 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 %s failed - %s",
+ viewEntryPgName, 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 %s failed - %s",
+ pgName, 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 %s failed - %s",
+ pgName, 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 %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgRefName, 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 for %s failed - %s",
+ pgRefName, 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 from %s iter failed - %s",
+ pgRefName, 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 %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, tmpbuf,
+ sizeof (tmpbuf)) == -1) {
+ syslog(LOG_ERR, "get ustring %s/%s failed - %s",
+ pgRefName, buf1, 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 property %s/%s "
+ "failed - %s", pgRefName, buf1,
+ 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 for %s failed - %s",
+ pgRefName, 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 %s/%s "
+ "failed - %s", pgRefName, buf1,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (scf_value_set_ustring(value, groupName) == -1) {
+ syslog(LOG_ERR, "set ustring %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (scf_entry_add_value(entry1, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ pgRefName, buf1, 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 %s/%s "
+ "failed - %s", pgRefName, buf2,
+ 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 %s/%s failed - %s",
+ pgRefName, buf1, 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 %s/%s "
+ "failed - %s", pgRefName, buf2,
+ 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 for %s failed - %s",
+ pgRefName, 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) {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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 from %s iter failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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 from %s iter failed - %s",
+ pgName, 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 %s/%s failed - %s",
+ pgName, buf, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get ustring %s/%s failed - %s",
+ pgName, buf, 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 {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_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 %s/%s failed - %s",
+ pgName, groupName, 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 %s/%s failed - %s",
+ pgName, groupName, 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 %s/%s failed - %s",
+ pgName, groupName, 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 %s/%s failed - %s",
+ pgName, groupName, 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 %s/%s failed - %s",
+ pgName, groupName, 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);
+}
+
+int
+psGetServicePersist(uint8_t *persistType)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ int ret;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsGetSetPersistType(persistType, handle, svc, GET);
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ return (ret);
+}
+
+int
+psSetServicePersist(uint8_t persistType)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ int ret;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsGetSetPersistType(&persistType, handle, svc, SET);
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ return (ret);
+}
+
+static int
+iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle,
+scf_service_t *svc, int getSet)
+{
+ 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;
+ char iPersistTypeGet[MAXNAMELEN] = {0};
+ char *iPersistType;
+ 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;
+ }
+
+ if (getSet == GET) {
+ /* set to default */
+ *persistType = STMF_PERSIST_SMF;
+ iPersistType = STMF_PS_PERSIST_SMF;
+ }
+
+ if (getSet == SET) {
+ if (*persistType == STMF_PERSIST_SMF) {
+ iPersistType = STMF_PS_PERSIST_SMF;
+ } else if (*persistType == STMF_PERSIST_NONE) {
+ iPersistType = STMF_PS_PERSIST_NONE;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * 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 {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+
+ goto out;
+ }
+
+ /* find persistence property */
+ /*
+ * Get the persistence property
+ */
+ if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* no persist property found */
+ if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
+ /*
+ * If we have no persistType property, go ahead
+ * and create it with the user specified value or
+ * the default value.
+ */
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* is this a SET or GET w/error? */
+ if (ret) {
+ if (scf_transaction_property_new(tran, entry,
+ STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new "
+ "%s/%s failed - %s", STMF_DATA_GROUP,
+ STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ if (scf_transaction_property_change(tran, entry,
+ STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property change "
+ "%s/%s failed - %s", STMF_DATA_GROUP,
+ STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * set the persist type
+ */
+ if (scf_value_set_astring(value, iPersistType) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * add the value to the transaction
+ */
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ STMF_DATA_GROUP, 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 if (getSet == GET) {
+ /* get the persist property */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the value of the persist property
+ */
+ if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN)
+ == -1) {
+ syslog(LOG_ERR, "get string value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (getSet == GET) {
+ if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) {
+ *persistType = STMF_PERSIST_NONE;
+ } else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) {
+ *persistType = STMF_PERSIST_SMF;
+ } else {
+ 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);
+}
+
+int
+psSetStmfProp(int propType, char *propVal)
+{
+ return (iPsGetSetStmfProp(propType, propVal, SET));
+}
+
+int
+psGetStmfProp(int propType, char *propVal)
+{
+ return (iPsGetSetStmfProp(propType, propVal, GET));
+}
+
+static int
+iPsGetSetStmfProp(int propType, char *propVal, int getSet)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_property_t *prop = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_value_t *value = NULL;
+ char *psStmfPropVal;
+ char *psStmfProp;
+ char stmfPropGet[MAXNAMELEN] = {0};
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (propVal == NULL || (getSet != GET && getSet != SET)) {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * 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) ||
+ ((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;
+ }
+ if (getSet == GET) {
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE :
+ psStmfProp = DEFAULT_LU_STATE;
+ psStmfPropVal = STMF_PS_LU_ONLINE;
+ (void) strcpy(stmfPropGet, psStmfPropVal);
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE :
+ psStmfProp = DEFAULT_TARGET_PORT_STATE;
+ psStmfPropVal = STMF_PS_TARGET_PORT_ONLINE;
+ (void) strcpy(stmfPropGet, psStmfPropVal);
+ break;
+ default :
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ if (getSet == SET) {
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE :
+ psStmfProp = DEFAULT_LU_STATE;
+ if (strcasecmp(propVal, "online") == 0) {
+ psStmfPropVal = STMF_PS_LU_ONLINE;
+ } else if (strcasecmp(propVal,
+ "offline") == 0) {
+ psStmfPropVal = STMF_PS_LU_OFFLINE;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE :
+ psStmfProp = DEFAULT_TARGET_PORT_STATE;
+ if (strcasecmp(propVal, "online") == 0) {
+ psStmfPropVal =
+ STMF_PS_TARGET_PORT_ONLINE;
+ } else if (strcasecmp(propVal,
+ "offline") == 0) {
+ psStmfPropVal =
+ STMF_PS_TARGET_PORT_OFFLINE;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ break;
+ default :
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * 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 {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ goto out;
+ }
+
+ /*
+ * get the stmf props property, if exists
+ */
+
+ if (scf_pg_get_property(pg, psStmfProp, prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "start transaction for %s/%s "
+ "failed - %s", STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* if stmf prop is not found or while setting the prop */
+
+ if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (ret) {
+ if (scf_transaction_property_new(tran, entry,
+ psStmfProp, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new "
+ "%s/%s failed - %s", STMF_DATA_GROUP,
+ psStmfProp, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ if (scf_transaction_property_change(tran, entry,
+ psStmfProp, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change "
+ "%s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * set stmf prop value
+ */
+
+ if (scf_value_set_astring(value, psStmfPropVal) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * add the value to the transaction
+ */
+
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s"
+ "failed - %s", STMF_DATA_GROUP,
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ ret = STMF_PS_SUCCESS;
+ } else if (getSet == GET) {
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value "
+ "%s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* get stmfProp */
+
+ if (scf_value_get_astring(value, stmfPropGet, MAXNAMELEN)
+ == -1) {
+ syslog(LOG_ERR, "get string value %s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ if (getSet == GET) {
+ if (strcmp(stmfPropGet, STMF_PS_LU_ONLINE) == 0) {
+ (void) strcpy(propVal, "online");
+ } else if (strcmp(stmfPropGet, STMF_PS_LU_OFFLINE) == 0) {
+ (void) strcpy(propVal, "offline");
+ } else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_ONLINE)
+ == 0) {
+ (void) strcpy(propVal, "online");
+ } else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_OFFLINE)
+ == 0) {
+ (void) strcpy(propVal, "offline");
+ } 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 (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);
+}
+
+/*
+ * 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 %s failed - %s",
+ STMF_DATA_GROUP, 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 %s failed - %s",
+ STMF_DATA_GROUP, 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 %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ 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 for %s failed - %s",
+ STMF_DATA_GROUP, 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 %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ 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 %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ STMF_DATA_GROUP, 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 %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ 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 %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ 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 %s failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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 from %s iter failed - %s",
+ pgName, 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 %s/%s failed - %s",
+ pgName, actualName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get ustring %s/%s failed - %s",
+ pgName, actualName, 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 pg 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 pg 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 %s failed - %s",
+ luPgName, 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 %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, 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 %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, 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 for %s failed - %s",
+ luPgName, 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 iter %s properties failed - %s",
+ luPgName, 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 %s failed - %s",
+ viewEntryPgName, 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_get_ustring(value, groupName,
+ sizeof (groupName)) == -1) {
+ syslog(LOG_ERR, "get value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ 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 value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_get_ustring(value, groupName,
+ sizeof (groupName)) == -1) {
+ syslog(LOG_ERR, "get value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR,
+ 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 %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR,
+ 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 %s failed - %s", pgName,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, dataPropertyName,
+ 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 %s/%s "
+ "failed - %s", pgName, dataPropertyName,
+ 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 %s/%s failed - %s",
+ buf, STMF_PROVIDER_DATA_PROP_TYPE,
+ 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 %s/%s failed - %s",
+ buf, STMF_PROVIDER_DATA_PROP_TYPE,
+ 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 %s/%s failed - %s",
+ buf, STMF_PROVIDER_DATA_PROP_TYPE,
+ 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 %s failed - %s",
+ pgName, 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 %s failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 for %s failed",
+ pgName);
+ 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 for %s failed", pgName);
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ addValue = (scf_value_t **)calloc(1, sizeof (*addValue)
+ * blockCnt);
+ if (addValue == NULL) {
+ syslog(LOG_ERR, "value alloc for %s failed", pgName);
+ 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 for %s failed",
+ pgName);
+ 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 for %s failed - %s",
+ pgName, 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 %s/%s failed - %s",
+ pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new %s/%s "
+ "failed - %s", pgName, dataPropertyName,
+ 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 for %s failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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 for %s failed - %s",
+ pgName, 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, "delete property %s/%s failed - %s",
+ pgName, dataPropertyName,
+ 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 %s/%s new "
+ "failed - %s", pgName, "read_authorization",
+ 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 %s/%s failed - %s",
+ pgName, "read_authorization",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_entry_add_value(entry1, value1) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ pgName, "read_authorization",
+ 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 "
+ "%s/%s failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property %s/%s new "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ 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 %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ 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 %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE,
+ 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 %s/%s failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ pgName, 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 %s failed - %s",
+ viewEntryPgName, 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 %s failed - %s",
+ viewEntryPgName, 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 %s failed - %s", viewEntryPgName,
+ scf_strerror(scf_error()));
+ if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ ADD)) != STMF_PS_SUCCESS) {
+ syslog(LOG_ERR, "add of view entry %s failed, possible"
+ "inconsistency - %s", viewEntryPgName,
+ 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 0000000..48eb547
--- /dev/null
+++ b/usr/src/lib/libstmf/common/store.h
@@ -0,0 +1,84 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+#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);
+int psSetServicePersist(uint8_t persistType);
+int psGetServicePersist(uint8_t *persistType);
+int psSetStmfProp(int propType, char *propVal);
+int psGetStmfProp(int propType, char *propVal);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STORE_H */