diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-05-15 14:28:09 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-05-15 14:28:09 +0400 |
commit | 4b587d510fc5e6d58d4b87327224bfe4e8b81c0a (patch) | |
tree | 90e40f900bb25680ef56597d4f8d4be04c17de23 /usr/src/lib/libstmf | |
download | stmf-illumos.tar.gz |
Initial illumos sourcesillumos
Diffstat (limited to 'usr/src/lib/libstmf')
-rw-r--r-- | usr/src/lib/libstmf/common/libstmf.h | 392 | ||||
-rw-r--r-- | usr/src/lib/libstmf/common/libstmf_impl.h | 80 | ||||
-rw-r--r-- | usr/src/lib/libstmf/common/stmf.c | 6949 | ||||
-rw-r--r-- | usr/src/lib/libstmf/common/store.c | 5385 | ||||
-rw-r--r-- | usr/src/lib/libstmf/common/store.h | 84 |
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, ¤tActionQuit) != 0) { + return (1); + } + + if (sigaction(SIGINT, &act, ¤tActionInt) != 0) { + return (1); + } + + if (sigaction(SIGTERM, &act, ¤tActionTerm) != 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, ¤tActionQuit, NULL) != 0) { + ret = 1; + } + + if (sigaction(SIGINT, ¤tActionInt, NULL) != 0) { + ret = 1; + } + + if (sigaction(SIGTERM, ¤tActionTerm, 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 */ |