stmf.c revision 450396635f70344c58b6b1e4db38cf17ff34445c
/*
* 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.
*/
#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>
#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 OUI_SIZE 3
#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 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 viewEntryCompare(const void *, const void *);
static void deleteNonActiveLus();
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->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) {
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;
}
}
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);
break;
default:
return (STMF_STATUS_ERROR);
break;
}
}
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;
/* 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);
}
/*
* 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_NO_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];
unsigned int oui[OUI_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:
(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];
diskLu->companyIdValid = 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_NO_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;
}
if (stmfIoctl.stmf_obuf_nentries == 0) {
ret = STMF_ERROR_NOT_FOUND;
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 (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);
}
/*
* 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);
}