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