summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-15 14:28:09 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-15 14:28:09 +0400
commit4b587d510fc5e6d58d4b87327224bfe4e8b81c0a (patch)
tree90e40f900bb25680ef56597d4f8d4be04c17de23
downloadstmf-4b587d510fc5e6d58d4b87327224bfe4e8b81c0a.tar.gz
Initial illumos sourcesillumos
-rw-r--r--usr/src/cmd/stmfadm/stmfadm.c3514
-rw-r--r--usr/src/cmd/stmfadm/stmfadm.h73
-rw-r--r--usr/src/cmd/stmfsvc/stmf.xml119
-rw-r--r--usr/src/cmd/stmfsvc/stmfsvc.c307
-rw-r--r--usr/src/common/cmdparse/cmdparse.c681
-rw-r--r--usr/src/common/cmdparse/cmdparse.h222
-rw-r--r--usr/src/lib/libstmf/common/libstmf.h392
-rw-r--r--usr/src/lib/libstmf/common/libstmf_impl.h80
-rw-r--r--usr/src/lib/libstmf/common/stmf.c6949
-rw-r--r--usr/src/lib/libstmf/common/store.c5385
-rw-r--r--usr/src/lib/libstmf/common/store.h84
-rw-r--r--usr/src/man/man1m/stmfadm.1m1136
-rw-r--r--usr/src/man/man3lib/libstmf.3lib201
-rw-r--r--usr/src/man/man3stmf/stmfAddToHostGroup.3stmf96
-rw-r--r--usr/src/man/man3stmf/stmfAddToTargetGroup.3stmf97
-rw-r--r--usr/src/man/man3stmf/stmfAddViewEntry.3stmf113
-rw-r--r--usr/src/man/man3stmf/stmfClearProviderData.3stmf86
-rw-r--r--usr/src/man/man3stmf/stmfCreateHostGroup.3stmf84
-rw-r--r--usr/src/man/man3stmf/stmfCreateLu.3stmf155
-rw-r--r--usr/src/man/man3stmf/stmfCreateLuResource.3stmf86
-rw-r--r--usr/src/man/man3stmf/stmfCreateTargetGroup.3stmf84
-rw-r--r--usr/src/man/man3stmf/stmfDeleteHostGroup.3stmf75
-rw-r--r--usr/src/man/man3stmf/stmfDeleteLu.3stmf79
-rw-r--r--usr/src/man/man3stmf/stmfDeleteTargetGroup.3stmf76
-rw-r--r--usr/src/man/man3stmf/stmfDevidFromIscsiName.3stmf91
-rw-r--r--usr/src/man/man3stmf/stmfDevidFromWwn.3stmf89
-rw-r--r--usr/src/man/man3stmf/stmfFreeLuResource.3stmf79
-rw-r--r--usr/src/man/man3stmf/stmfFreeMemory.3stmf58
-rw-r--r--usr/src/man/man3stmf/stmfGetHostGroupList.3stmf78
-rw-r--r--usr/src/man/man3stmf/stmfGetHostGroupMembers.3stmf88
-rw-r--r--usr/src/man/man3stmf/stmfGetLogicalUnitList.3stmf78
-rw-r--r--usr/src/man/man3stmf/stmfGetLogicalUnitProperties.3stmf91
-rw-r--r--usr/src/man/man3stmf/stmfGetLuResource.3stmf91
-rw-r--r--usr/src/man/man3stmf/stmfGetPersistMethod.3stmf89
-rw-r--r--usr/src/man/man3stmf/stmfGetProviderData.3stmf105
-rw-r--r--usr/src/man/man3stmf/stmfGetProviderDataProt.3stmf111
-rw-r--r--usr/src/man/man3stmf/stmfGetState.3stmf66
-rw-r--r--usr/src/man/man3stmf/stmfGetTargetGroupList.3stmf78
-rw-r--r--usr/src/man/man3stmf/stmfGetTargetGroupMembers.3stmf90
-rw-r--r--usr/src/man/man3stmf/stmfGetTargetList.3stmf78
-rw-r--r--usr/src/man/man3stmf/stmfGetTargetProperties.3stmf88
-rw-r--r--usr/src/man/man3stmf/stmfGetViewEntryList.3stmf90
-rw-r--r--usr/src/man/man3stmf/stmfModifyLu.3stmf196
-rw-r--r--usr/src/man/man3stmf/stmfOfflineLogicalUnit.3stmf86
-rw-r--r--usr/src/man/man3stmf/stmfOfflineTarget.3stmf84
-rw-r--r--usr/src/man/man3stmf/stmfOnlineLogicalUnit.3stmf68
-rw-r--r--usr/src/man/man3stmf/stmfOnlineTarget.3stmf68
-rw-r--r--usr/src/man/man3stmf/stmfRemoveFromHostGroup.3stmf100
-rw-r--r--usr/src/man/man3stmf/stmfRemoveFromTargetGroup.3stmf110
-rw-r--r--usr/src/man/man3stmf/stmfRemoveViewEntry.3stmf86
-rw-r--r--usr/src/man/man3stmf/stmfSetLuProp.3stmf321
-rw-r--r--usr/src/man/man3stmf/stmfSetPersistMethod.3stmf87
-rw-r--r--usr/src/man/man3stmf/stmfSetProviderData.3stmf102
-rw-r--r--usr/src/man/man3stmf/stmfSetProviderDataProt.3stmf114
54 files changed, 23134 insertions, 0 deletions
diff --git a/usr/src/cmd/stmfadm/stmfadm.c b/usr/src/cmd/stmfadm/stmfadm.c
new file mode 100644
index 0000000..0c98614
--- /dev/null
+++ b/usr/src/cmd/stmfadm/stmfadm.c
@@ -0,0 +1,3514 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <libintl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <cmdparse.h>
+#include <stmfadm.h>
+#include <libstmf.h>
+#include <signal.h>
+#include <pthread.h>
+#include <locale.h>
+
+static int addHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
+static int addTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
+static int addViewFunc(int, char **, cmdOptions_t *, void *);
+static int createHostGroupFunc(int, char **, cmdOptions_t *, void *);
+static int createLuFunc(int, char **, cmdOptions_t *, void *);
+static int modifyLuFunc(int, char **, cmdOptions_t *, void *);
+static int importLuFunc(int, char **, cmdOptions_t *, void *);
+static int deleteLuFunc(int, char **, cmdOptions_t *, void *);
+static int createTargetGroupFunc(int, char **, cmdOptions_t *, void *);
+static int deleteHostGroupFunc(int, char **, cmdOptions_t *, void *);
+static int deleteTargetGroupFunc(int, char **, cmdOptions_t *, void *);
+static int listLuFunc(int, char **, cmdOptions_t *, void *);
+static int listTargetFunc(int, char **, cmdOptions_t *, void *);
+static int listViewFunc(int, char **, cmdOptions_t *, void *);
+static int listHostGroupFunc(int, char **, cmdOptions_t *, void *);
+static int listStateFunc(int, char **, cmdOptions_t *, void *);
+static int listTargetGroupFunc(int, char **, cmdOptions_t *, void *);
+static int offlineTargetFunc(int, char **, cmdOptions_t *, void *);
+static int offlineLuFunc(int, char **, cmdOptions_t *, void *);
+static int onlineTargetFunc(int, char **, cmdOptions_t *, void *);
+static int onlineLuFunc(int, char **, cmdOptions_t *, void *);
+static int onlineOfflineTarget(char *, int);
+static int onlineOfflineLu(char *, int);
+static int removeHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
+static int removeTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
+static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *);
+static int removeViewFunc(int, char **, cmdOptions_t *, void *);
+static char *getExecBasename(char *);
+static int parseDevid(char *input, stmfDevid *devid);
+static void printGroupProps(stmfGroupProperties *groupProps);
+static int checkScsiNameString(wchar_t *, stmfDevid *);
+static int checkHexUpper(char *);
+static int checkIscsiName(wchar_t *);
+static void printLuProps(stmfLogicalUnitProperties *luProps);
+static int printExtLuProps(stmfGuid *guid);
+static void printGuid(stmfGuid *guid, FILE *printWhere);
+static void printTargetProps(stmfTargetProperties *);
+static void printSessionProps(stmfSessionList *);
+static int setLuPropFromInput(luResource, char *);
+static int convertCharToPropId(char *, uint32_t *);
+
+
+
+/*
+ * MAJOR - This should only change when there is an incompatible change made
+ * to the interfaces or the output.
+ *
+ * MINOR - This should change whenever there is a new command or new feature
+ * with no incompatible change.
+ */
+#define VERSION_STRING_MAJOR "1"
+#define VERSION_STRING_MINOR "0"
+#define MAX_DEVID_INPUT 256
+#define GUID_INPUT 32
+#define MAX_LU_NBR 16383
+#define ONLINE_LU 0
+#define OFFLINE_LU 1
+#define ONLINE_TARGET 2
+#define OFFLINE_TARGET 3
+#define PROPS_FORMAT " %-18s: "
+#define VIEW_FORMAT " %-13s: "
+#define LVL3_FORMAT " %s"
+#define LVL4_FORMAT " %s"
+#define DELAYED_EXEC_WAIT_INTERVAL 300 * 1000 * 1000 /* in nano sec */
+#define DELAYED_EXEC_WAIT_MAX 30 /* Maximum number of interval times */
+
+/* SCSI Name String length definitions */
+#define SNS_EUI_16 16
+#define SNS_EUI_24 24
+#define SNS_EUI_32 32
+#define SNS_NAA_16 16
+#define SNS_NAA_32 32
+#define SNS_WWN_16 16
+#define SNS_IQN_223 223
+
+/* LU Property strings */
+#define GUID "GUID"
+#define ALIAS "ALIAS"
+#define VID "VID"
+#define PID "PID"
+#define META_FILE "META"
+#define WRITE_PROTECT "WP"
+#define WRITEBACK_CACHE_DISABLE "WCD"
+#define COMPANY_ID "OUI"
+#define BLOCK_SIZE "BLK"
+#define SERIAL_NUMBER "SERIAL"
+#define MGMT_URL "MGMT-URL"
+#define HOST_ID "HOST-ID"
+
+#define STMFADM_SUCCESS 0
+#define STMFADM_FAILURE 1
+
+#define MODIFY_HELP "\n"\
+"Description: Modify properties of a logical unit. \n" \
+"Valid properties for -p, --lu-prop are: \n" \
+" alias - alias for logical unit (up to 255 chars)\n" \
+" mgmt-url - Management URL address\n" \
+" wcd - write cache disabled (true, false)\n" \
+" wp - write protect (true, false)\n\n" \
+"-f alters the meaning of the operand to be a file name\n" \
+"rather than a LU name. This allows for modification\n" \
+"of a logical unit that is not yet imported into stmf\n"
+
+#define CREATE_HELP "\n"\
+"Description: Create a logical unit. \n" \
+"Valid properties for -p, --lu-prop are: \n" \
+" alias - alias for logical unit (up to 255 chars)\n" \
+" blk - block size in bytes in 2^n\n" \
+" guid - 32 ascii hex characters in NAA format \n" \
+" host-id - host identifier to be used for GUID generation \n" \
+" 8 ascii hex characters\n" \
+" meta - separate meta data file name\n" \
+" mgmt-url - Management URL address\n" \
+" oui - organizational unique identifier\n" \
+" 6 ascii hex characters of valid format\n" \
+" pid - product identifier (up to 16 chars)\n" \
+" serial - serial number (up to 252 chars)\n" \
+" vid - vendor identifier (up to 8 chars)\n" \
+" wcd - write cache disabled (true, false)\n" \
+" wp - write protect (true, false)\n"
+#define ADD_VIEW_HELP "\n"\
+"Description: Add a view entry to a logical unit. \n" \
+"A view entry is comprised of three elements; the \n" \
+"logical unit number, the target group name and the\n" \
+"host group name. These three elements combine together\n" \
+"to form a view for a given COMSTAR logical unit.\n" \
+"This view is realized by a client, a SCSI initiator,\n" \
+"via a REPORT LUNS command. \n"
+
+
+
+/* tables set up based on cmdparse instructions */
+
+/* add new options here */
+optionTbl_t longOptions[] = {
+ {"all", no_arg, 'a', NULL},
+ {"group-name", required_arg, 'g', "group-name"},
+ {"keep-views", no_arg, 'k', NULL},
+ {"lu-name", required_arg, 'l', "LU-Name"},
+ {"lun", required_arg, 'n', "logical-unit-number"},
+ {"lu-prop", required_arg, 'p', "logical-unit-property=value"},
+ {"file", no_arg, 'f', "filename"},
+ {"size", required_arg, 's', "size K/M/G/T/P"},
+ {"target-group", required_arg, 't', "group-name"},
+ {"host-group", required_arg, 'h', "group-name"},
+ {"verbose", no_arg, 'v', NULL},
+ {NULL, 0, 0, 0}
+};
+
+/*
+ * Add new subcommands here
+ */
+subCommandProps_t subcommands[] = {
+ {"add-hg-member", addHostGroupMemberFunc, "g", "g", NULL,
+ OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
+ {"add-tg-member", addTargetGroupMemberFunc, "g", "g", NULL,
+ OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
+ {"add-view", addViewFunc, "nth", NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, ADD_VIEW_HELP},
+ {"create-hg", createHostGroupFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+ {"create-tg", createTargetGroupFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+ {"create-lu", createLuFunc, "ps", NULL, NULL, OPERAND_MANDATORY_SINGLE,
+ "lu file", CREATE_HELP},
+ {"delete-hg", deleteHostGroupFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+ {"modify-lu", modifyLuFunc, "psf", NULL, NULL, OPERAND_MANDATORY_SINGLE,
+ OPERANDSTRING_LU, MODIFY_HELP},
+ {"delete-lu", deleteLuFunc, "k", NULL, NULL,
+ OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_LU, NULL},
+ {"delete-tg", deleteTargetGroupFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+ {"import-lu", importLuFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, "file name", NULL},
+ {"list-hg", listHostGroupFunc, "v", NULL, NULL,
+ OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
+ {"list-lu", listLuFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE,
+ OPERANDSTRING_LU, NULL},
+ {"list-state", listStateFunc, NULL, NULL, NULL, OPERAND_NONE, NULL},
+ {"list-target", listTargetFunc, "v", NULL, NULL,
+ OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET, NULL},
+ {"list-tg", listTargetGroupFunc, "v", NULL, NULL,
+ OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
+ {"list-view", listViewFunc, "l", "l", NULL,
+ OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
+ {"online-lu", onlineLuFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
+ {"offline-lu", offlineLuFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
+ {"online-target", onlineTargetFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
+ {"offline-target", offlineTargetFunc, NULL, NULL, NULL,
+ OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
+ {"remove-hg-member", removeHostGroupMemberFunc, "g", "g", NULL,
+ OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
+ {"remove-tg-member", removeTargetGroupMemberFunc, "g", "g", NULL,
+ OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
+ {"remove-view", removeViewFunc, "la", "l", NULL,
+ OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
+ {NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
+};
+
+/* globals */
+char *cmdName;
+
+/*
+ * addHostGroupMemberFunc
+ *
+ * Add members to a host group
+ *
+ */
+/*ARGSUSED*/
+static int
+addHostGroupMemberFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int i;
+ int ret = 0;
+ int stmfRet;
+ stmfGroupName groupName = {0};
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+ stmfDevid devid;
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ /* host group name */
+ case 'g':
+ (void) mbstowcs(groupNamePrint, options->optarg,
+ sizeof (stmfGroupName) - 1);
+ bcopy(options->optarg, groupName,
+ strlen(options->optarg));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ for (i = 0; i < operandLen; i++) {
+ if (parseDevid(operands[i], &devid) != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, operands[i],
+ gettext("unrecognized device id"));
+ ret++;
+ continue;
+ }
+ stmfRet = stmfAddToHostGroup(&groupName, &devid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_EXISTS:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("already exists"));
+ ret++;
+ break;
+ case STMF_ERROR_GROUP_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("unknown error"));
+ ret++;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * addTargetGroupMemberFunc
+ *
+ * Add members to a target group
+ *
+ */
+/*ARGSUSED*/
+static int
+addTargetGroupMemberFunc(int operandLen, char *operands[],
+ cmdOptions_t *options, void *args)
+{
+ int i;
+ int ret = 0;
+ int stmfRet;
+ stmfGroupName groupName = {0};
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+ stmfDevid devid;
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ /* target group name */
+ case 'g':
+ (void) mbstowcs(groupNamePrint, options->optarg,
+ sizeof (stmfGroupName) - 1);
+ bcopy(options->optarg, groupName,
+ strlen(options->optarg));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ for (i = 0; i < operandLen; i++) {
+ if (parseDevid(operands[i], &devid) != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, operands[i],
+ gettext("unrecognized device id"));
+ ret++;
+ continue;
+ }
+ stmfRet = stmfAddToTargetGroup(&groupName, &devid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_EXISTS:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("already exists"));
+ ret++;
+ break;
+ case STMF_ERROR_GROUP_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_ONLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service must be offline"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ case STMF_ERROR_TG_ONLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF target must be offline"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("unknown error"));
+ ret++;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * parseDevid
+ *
+ * Converts char * input to a stmfDevid
+ *
+ * input - this should be in the following format with either a
+ * wwn. iqn. or eui. representation.
+ * A name string of the format:
+ * wwn.<WWN> (FC/SAS address)
+ * iqn.<iSCSI name> (iSCSI iqn)
+ * eui.<WWN> (iSCSI eui name)
+ *
+ * devid - pointer to stmfDevid structure allocated by the caller.
+ *
+ * Returns:
+ * 0 on success
+ * non-zero on failure
+ */
+static int
+parseDevid(char *input, stmfDevid *devid)
+{
+ wchar_t inputWc[MAX_DEVID_INPUT + 1] = {0};
+
+ /* convert to wcs */
+ (void) mbstowcs(inputWc, input, MAX_DEVID_INPUT);
+
+ /*
+ * Check for known scsi name string formats
+ * If one is found, we're done
+ * If not, then it's a failure to parse
+ */
+ if (checkScsiNameString(inputWc, devid) == 0) {
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * checkScsiNameString
+ *
+ * Validates known SCSI name string formats and converts to stmfDevid
+ * format
+ *
+ * input - input SCSI name string
+ * devid - pointer to stmfDevid structure allocated by the caller
+ * on successful return, contains the devid based on input
+ *
+ * returns:
+ * 0 on success
+ * -1 on failure
+ */
+static int
+checkScsiNameString(wchar_t *input, stmfDevid *devid)
+{
+ char *mbString = NULL;
+ int mbStringLen;
+ int len;
+ int i;
+
+ /*
+ * Convert to multi-byte string
+ *
+ * This is used for either eui or naa formats
+ */
+ mbString = calloc(1, (mbStringLen = wcstombs(mbString, input, 0)) + 1);
+ if (mbString == NULL) {
+ (void) fprintf(stderr, "%s: %s\n",
+ cmdName, "Insufficient memory\n");
+ return (-1);
+ }
+ if (wcstombs(mbString, input, mbStringLen) == (size_t)-1) {
+ return (-1);
+ }
+
+ /*
+ * check for iqn format
+ */
+ if (strncmp(mbString, "iqn.", 4) == 0) {
+ if ((len = strlen(mbString)) > (SNS_IQN_223)) {
+ return (-1);
+ }
+ for (i = 0; i < len; i++) {
+ mbString[i] = tolower(mbString[i]);
+ }
+ if (checkIscsiName(input + 4) != 0) {
+ return (-1);
+ }
+ } else if (strncmp(mbString, "wwn.", 4) == 0) {
+ if ((len = strlen(mbString + 4)) != SNS_WWN_16) {
+ return (-1);
+ } else if (checkHexUpper(mbString + 4) != 0) {
+ return (-1);
+ }
+ } else if (strncmp(mbString, "eui.", 4) == 0) {
+ if ((len = strlen(mbString + 4)) != SNS_EUI_16) {
+ return (-1);
+ } else if (checkHexUpper(mbString + 4) != 0) {
+ return (-1);
+ }
+ } else {
+ return (-1);
+ }
+
+ /*
+ * We have a validated name string.
+ * Go ahead and set the length and copy it.
+ */
+ devid->identLength = strlen(mbString);
+ bzero(devid->ident, STMF_IDENT_LENGTH);
+ bcopy(mbString, devid->ident, devid->identLength);
+
+ return (0);
+}
+
+
+/*
+ * Checks whether the entire string is in hex and converts to upper
+ */
+static int
+checkHexUpper(char *input)
+{
+ int i;
+
+ for (i = 0; i < strlen(input); i++) {
+ if (isxdigit(input[i])) {
+ input[i] = toupper(input[i]);
+ continue;
+ }
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * checkIscsiName
+ *
+ * Purpose: Basic string checking on name
+ */
+static int
+checkIscsiName(wchar_t *input)
+{
+ int i;
+
+ for (i = 0; input[i] != 0; i++) {
+ if (!iswalnum(input[i]) && input[i] != '-' &&
+ input[i] != '.' && input[i] != ':') {
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * addViewFunc
+ *
+ * Adds a view entry to a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+addViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ stmfViewEntry viewEntry;
+ stmfGuid inGuid;
+ unsigned int guid[sizeof (stmfGuid)];
+ uint16_t inputLuNbr;
+ int ret = 0;
+ int stmfRet;
+ int i;
+ char sGuid[GUID_INPUT + 1];
+
+ bzero(&viewEntry, sizeof (viewEntry));
+ /* init view entry structure */
+ viewEntry.allHosts = B_TRUE;
+ viewEntry.allTargets = B_TRUE;
+ viewEntry.luNbrValid = B_FALSE;
+
+ /* check input length */
+ if (strlen(operands[0]) != GUID_INPUT) {
+ (void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
+ gettext("must be "), GUID_INPUT,
+ gettext(" hexadecimal digits"));
+ return (1);
+ }
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ /* logical unit number */
+ case 'n':
+ viewEntry.luNbrValid = B_TRUE;
+ inputLuNbr = atoi(options->optarg);
+ if (inputLuNbr > MAX_LU_NBR) {
+ (void) fprintf(stderr, "%s: %d: %s\n",
+ cmdName, inputLuNbr,
+ gettext("Logical unit number"
+ " must be less than 16384"));
+ return (1);
+ }
+ viewEntry.luNbr[0] = inputLuNbr >> 8;
+ viewEntry.luNbr[1] = inputLuNbr & 0xff;
+ break;
+ /* host group */
+ case 'h':
+ viewEntry.allHosts = B_FALSE;
+ bcopy(options->optarg, viewEntry.hostGroup,
+ strlen(options->optarg));
+ break;
+ /* target group */
+ case 't':
+ viewEntry.allTargets = B_FALSE;
+ bcopy(options->optarg, viewEntry.targetGroup,
+ strlen(options->optarg));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ /* convert to lower case for scan */
+ for (i = 0; i < 32; i++)
+ sGuid[i] = tolower(operands[0][i]);
+ sGuid[i] = 0;
+
+ (void) sscanf(sGuid, "%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 (stmfGuid); i++) {
+ inGuid.guid[i] = guid[i];
+ }
+
+ /* add the view entry */
+ stmfRet = stmfAddViewEntry(&inGuid, &viewEntry);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_EXISTS:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("already exists"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_LUN_IN_USE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("LUN already in use"));
+ ret++;
+ break;
+ case STMF_ERROR_VE_CONFLICT:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("view entry exists"));
+ ret++;
+ break;
+ case STMF_ERROR_CONFIG_NONE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service is not initialized"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ case STMF_ERROR_INVALID_HG:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid host group"));
+ ret++;
+ break;
+ case STMF_ERROR_INVALID_TG:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid target group"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * createHostGroupFunc
+ *
+ * Create a host group
+ *
+ */
+/*ARGSUSED*/
+static int
+createHostGroupFunc(int operandLen, char *operands[],
+ cmdOptions_t *options, void *args)
+{
+ int ret = 0;
+ int stmfRet;
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+ stmfGroupName groupName = {0};
+
+ (void) strlcpy(groupName, operands[0], sizeof (groupName));
+ (void) mbstowcs(groupNamePrint, (char *)groupName,
+ sizeof (stmfGroupName) - 1);
+ /* call create group */
+ stmfRet = stmfCreateHostGroup(&groupName);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_EXISTS:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("already exists"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[0], gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * createLuFunc
+ *
+ * Create a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+createLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ luResource hdl = NULL;
+ int ret = 0;
+ int stmfRet = 0;
+ char guidAsciiBuf[33];
+ stmfGuid createdGuid;
+
+ stmfRet = stmfCreateLuResource(STMF_DISK, &hdl);
+
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ (void) fprintf(stderr, "%s: %s\n",
+ cmdName, gettext("Failure to create lu resource\n"));
+ return (1);
+ }
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'p':
+ ret = setLuPropFromInput(hdl, options->optarg);
+ if (ret != 0) {
+ (void) stmfFreeLuResource(hdl);
+ return (1);
+ }
+ break;
+ case 's':
+ stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE,
+ options->optarg);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("size param invalid"));
+ (void) stmfFreeLuResource(hdl);
+ return (1);
+ }
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]);
+
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ (void) fprintf(stderr, "%s: %s\n",
+ cmdName, gettext("could not set filename"));
+ return (1);
+ }
+
+ stmfRet = stmfCreateLu(hdl, &createdGuid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_BUSY:
+ case STMF_ERROR_LU_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_FILE_IN_USE:
+ (void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
+ operands[0], gettext("in use"));
+ ret++;
+ break;
+ case STMF_ERROR_INVALID_BLKSIZE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid block size"));
+ ret++;
+ break;
+ case STMF_ERROR_GUID_IN_USE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("guid in use"));
+ ret++;
+ break;
+ case STMF_ERROR_META_FILE_NAME:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("meta file error"));
+ ret++;
+ break;
+ case STMF_ERROR_DATA_FILE_NAME:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("data file error"));
+ ret++;
+ break;
+ case STMF_ERROR_FILE_SIZE_INVALID:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("file size invalid"));
+ ret++;
+ break;
+ case STMF_ERROR_SIZE_OUT_OF_RANGE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid size"));
+ ret++;
+ break;
+ case STMF_ERROR_META_CREATION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("could not create meta file"));
+ ret++;
+ break;
+ case STMF_ERROR_WRITE_CACHE_SET:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("could not set write cache"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ if (ret != 0) {
+ goto done;
+ }
+
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X",
+ createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
+ createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
+ createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
+ createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
+ createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
+ createdGuid.guid[15]);
+ (void) printf("Logical unit created: %s\n", guidAsciiBuf);
+
+done:
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+}
+
+/*
+ * createLuFunc
+ *
+ * Create a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+modifyLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ stmfGuid inGuid;
+ unsigned int guid[sizeof (stmfGuid)];
+ int ret = 0;
+ int i;
+ char *fname = NULL;
+ char *lasts = NULL;
+ char sGuid[GUID_INPUT + 1];
+ char *prop = NULL;
+ char *propVal = NULL;
+ boolean_t fnameUsed = B_FALSE;
+ uint32_t propId;
+ cmdOptions_t *optionStart = options;
+
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'f':
+ fnameUsed = B_TRUE;
+ fname = operands[0];
+ break;
+ }
+ }
+ options = optionStart;
+
+ /* check input length */
+ if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
+ (void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
+ gettext("must be "), GUID_INPUT,
+ gettext(" hexadecimal digits"));
+ return (1);
+ }
+
+ if (!fnameUsed) {
+ /* convert to lower case for scan */
+ for (i = 0; i < 32; i++)
+ sGuid[i] = tolower(operands[0][i]);
+ sGuid[i] = 0;
+ (void) sscanf(sGuid,
+ "%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 (stmfGuid); i++) {
+ inGuid.guid[i] = guid[i];
+ }
+ }
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'p':
+ prop = strtok_r(options->optarg, "=", &lasts);
+ propVal = strtok_r(NULL, "=", &lasts);
+ ret = convertCharToPropId(prop, &propId);
+ if (ret != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName,
+ gettext("invalid property specified"),
+ prop);
+ return (1);
+ }
+ if (propVal == NULL &&
+ propId != STMF_LU_PROP_MGMT_URL) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, options->optarg,
+ gettext("invalid property specifier"
+ "- prop=val\n"));
+ return (1);
+ }
+ if (propVal == NULL) {
+ ret = callModify(fname, &inGuid, propId,
+ "", prop);
+ } else {
+ ret = callModify(fname, &inGuid, propId,
+ propVal, prop);
+ }
+ if (ret != 0) {
+ return (1);
+ }
+ break;
+ case 's':
+ if (callModify(fname, &inGuid,
+ STMF_LU_PROP_SIZE, options->optarg,
+ "size") != 0) {
+ return (1);
+ }
+ break;
+ case 'f':
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+ return (ret);
+}
+
+static int
+callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
+ const char *propString)
+{
+ int ret = 0;
+ int stmfRet = 0;
+
+ if (!fname) {
+ stmfRet = stmfModifyLu(luGuid, prop, propVal);
+ } else {
+ stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
+ propVal);
+ }
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_BUSY:
+ case STMF_ERROR_LU_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_INVALID_BLKSIZE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid block size"));
+ ret++;
+ break;
+ case STMF_ERROR_GUID_IN_USE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("guid in use"));
+ ret++;
+ break;
+ case STMF_ERROR_META_FILE_NAME:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("meta file error"));
+ ret++;
+ break;
+ case STMF_ERROR_DATA_FILE_NAME:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("data file error"));
+ ret++;
+ break;
+ case STMF_ERROR_FILE_SIZE_INVALID:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("file size invalid"));
+ ret++;
+ break;
+ case STMF_ERROR_SIZE_OUT_OF_RANGE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid size"));
+ ret++;
+ break;
+ case STMF_ERROR_META_CREATION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("could not create meta file"));
+ ret++;
+ break;
+ case STMF_ERROR_INVALID_PROP:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("invalid property for modify"));
+ ret++;
+ break;
+ case STMF_ERROR_WRITE_CACHE_SET:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("could not set write cache"));
+ ret++;
+ break;
+ case STMF_ERROR_ACCESS_STATE_SET:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("cannot modify while in standby mode"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
+ gettext("could not set property"), propString,
+ stmfRet);
+ ret++;
+ break;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * importLuFunc
+ *
+ * Create a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+importLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int stmfRet = 0;
+ int ret = 0;
+ char guidAsciiBuf[33];
+ stmfGuid createdGuid;
+
+ stmfRet = stmfImportLu(STMF_DISK, operands[0], &createdGuid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_BUSY:
+ case STMF_ERROR_LU_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_FILE_IN_USE:
+ (void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
+ operands[0], gettext("in use"));
+ ret++;
+ break;
+ case STMF_ERROR_GUID_IN_USE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("guid in use"));
+ ret++;
+ break;
+ case STMF_ERROR_META_FILE_NAME:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("meta file error"));
+ ret++;
+ break;
+ case STMF_ERROR_DATA_FILE_NAME:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("data file error"));
+ ret++;
+ break;
+ case STMF_ERROR_META_CREATION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("could not create meta file"));
+ ret++;
+ break;
+ case STMF_ERROR_WRITE_CACHE_SET:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("could not set write cache"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X",
+ createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
+ createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
+ createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
+ createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
+ createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
+ createdGuid.guid[15]);
+ (void) printf("Logical unit imported: %s\n", guidAsciiBuf);
+
+done:
+ return (ret);
+}
+
+static int
+setLuPropFromInput(luResource hdl, char *optarg)
+{
+ char *prop = NULL;
+ char *propVal = NULL;
+ char *lasts = NULL;
+ uint32_t propId;
+ int ret = 0;
+
+ prop = strtok_r(optarg, "=", &lasts);
+ if ((propVal = strtok_r(NULL, "=", &lasts)) == NULL) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, optarg,
+ gettext("invalid property specifier - prop=val\n"));
+ return (1);
+ }
+
+ ret = convertCharToPropId(prop, &propId);
+ if (ret != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, gettext("invalid property specified"), prop);
+ return (1);
+ }
+
+ ret = stmfSetLuProp(hdl, propId, propVal);
+ if (ret != STMF_STATUS_SUCCESS) {
+ (void) fprintf(stderr, "%s: %s %s: ",
+ cmdName, gettext("unable to set"), prop);
+ switch (ret) {
+ case STMF_ERROR_INVALID_PROPSIZE:
+ (void) fprintf(stderr, "invalid length\n");
+ break;
+ case STMF_ERROR_INVALID_ARG:
+ (void) fprintf(stderr, "bad format\n");
+ break;
+ default:
+ (void) fprintf(stderr, "\n");
+ break;
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+convertCharToPropId(char *prop, uint32_t *propId)
+{
+ if (strcasecmp(prop, GUID) == 0) {
+ *propId = STMF_LU_PROP_GUID;
+ } else if (strcasecmp(prop, ALIAS) == 0) {
+ *propId = STMF_LU_PROP_ALIAS;
+ } else if (strcasecmp(prop, VID) == 0) {
+ *propId = STMF_LU_PROP_VID;
+ } else if (strcasecmp(prop, PID) == 0) {
+ *propId = STMF_LU_PROP_PID;
+ } else if (strcasecmp(prop, WRITE_PROTECT) == 0) {
+ *propId = STMF_LU_PROP_WRITE_PROTECT;
+ } else if (strcasecmp(prop, WRITEBACK_CACHE_DISABLE) == 0) {
+ *propId = STMF_LU_PROP_WRITE_CACHE_DISABLE;
+ } else if (strcasecmp(prop, BLOCK_SIZE) == 0) {
+ *propId = STMF_LU_PROP_BLOCK_SIZE;
+ } else if (strcasecmp(prop, SERIAL_NUMBER) == 0) {
+ *propId = STMF_LU_PROP_SERIAL_NUM;
+ } else if (strcasecmp(prop, COMPANY_ID) == 0) {
+ *propId = STMF_LU_PROP_COMPANY_ID;
+ } else if (strcasecmp(prop, META_FILE) == 0) {
+ *propId = STMF_LU_PROP_META_FILENAME;
+ } else if (strcasecmp(prop, MGMT_URL) == 0) {
+ *propId = STMF_LU_PROP_MGMT_URL;
+ } else if (strcasecmp(prop, HOST_ID) == 0) {
+ *propId = STMF_LU_PROP_HOST_ID;
+ } else {
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * deleteLuFunc
+ *
+ * Delete a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+deleteLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int i, j;
+ int ret = 0;
+ int stmfRet;
+ unsigned int inGuid[sizeof (stmfGuid)];
+ stmfGuid delGuid;
+ boolean_t keepViews = B_FALSE;
+ boolean_t viewEntriesRemoved = B_FALSE;
+ boolean_t noLunFound = B_FALSE;
+ boolean_t views = B_FALSE;
+ boolean_t notValidHexNumber = B_FALSE;
+ char sGuid[GUID_INPUT + 1];
+ stmfViewEntryList *viewEntryList = NULL;
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ /* Keep views for logical unit */
+ case 'k':
+ keepViews = B_TRUE;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+
+ for (i = 0; i < operandLen; i++) {
+ for (j = 0; j < GUID_INPUT; j++) {
+ if (!isxdigit(operands[i][j])) {
+ notValidHexNumber = B_TRUE;
+ break;
+ }
+ sGuid[j] = tolower(operands[i][j]);
+ }
+ if ((notValidHexNumber == B_TRUE) ||
+ (strlen(operands[i]) != GUID_INPUT)) {
+ (void) fprintf(stderr, "%s: %s: %s%d%s\n",
+ cmdName, operands[i], gettext("must be "),
+ GUID_INPUT,
+ gettext(" hexadecimal digits long"));
+ notValidHexNumber = B_FALSE;
+ ret++;
+ continue;
+ }
+
+ sGuid[j] = 0;
+
+ (void) sscanf(sGuid,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
+ &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
+ &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
+ &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
+
+ for (j = 0; j < sizeof (stmfGuid); j++) {
+ delGuid.guid[j] = inGuid[j];
+ }
+
+ stmfRet = stmfDeleteLu(&delGuid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ noLunFound = B_TRUE;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ if (!keepViews) {
+ stmfRet = stmfGetViewEntryList(&delGuid,
+ &viewEntryList);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ for (j = 0; j < viewEntryList->cnt; j++) {
+ (void) stmfRemoveViewEntry(&delGuid,
+ viewEntryList->ve[j].veIndex);
+ }
+ /* check if viewEntryList is empty */
+ if (viewEntryList->cnt != 0)
+ viewEntriesRemoved = B_TRUE;
+ stmfFreeMemory(viewEntryList);
+ } else {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unable to remove view entries\n"));
+ ret++;
+ }
+
+ }
+ if (keepViews) {
+ stmfRet = stmfGetViewEntryList(&delGuid,
+ &viewEntryList);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ views = B_TRUE;
+ stmfFreeMemory(viewEntryList);
+ }
+ }
+
+ if ((!viewEntriesRemoved && noLunFound && !views) ||
+ (!views && keepViews && noLunFound)) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, sGuid,
+ gettext("not found"));
+ ret++;
+ }
+ noLunFound = viewEntriesRemoved = views = B_FALSE;
+ }
+ return (ret);
+}
+
+
+/*
+ * createTargetGroupFunc
+ *
+ * Create a target group
+ *
+ */
+/*ARGSUSED*/
+static int
+createTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret = 0;
+ int stmfRet;
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+ stmfGroupName groupName = {0};
+
+ (void) strlcpy(groupName, operands[0], sizeof (groupName));
+ (void) mbstowcs(groupNamePrint, (char *)groupName,
+ sizeof (stmfGroupName) - 1);
+ /* call create group */
+ stmfRet = stmfCreateTargetGroup(&groupName);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_EXISTS:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("already exists"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * deleteHostGroupFunc
+ *
+ * Delete a host group
+ *
+ */
+/*ARGSUSED*/
+static int
+deleteHostGroupFunc(int operandLen, char *operands[],
+ cmdOptions_t *options, void *args)
+{
+ int ret = 0;
+ int stmfRet;
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+ stmfGroupName groupName = {0};
+
+ (void) strlcpy(groupName, operands[0], sizeof (groupName));
+ (void) mbstowcs(groupNamePrint, (char *)groupName,
+ sizeof (stmfGroupName) - 1);
+ /* call delete group */
+ stmfRet = stmfDeleteHostGroup(&groupName);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_GROUP_IN_USE:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint,
+ gettext("group is in use by existing view entry"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * deleteTargetGroupFunc
+ *
+ * Delete a target group
+ *
+ */
+/*ARGSUSED*/
+static int
+deleteTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret = 0;
+ int stmfRet;
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+ stmfGroupName groupName = {0};
+
+ (void) strlcpy(groupName, operands[0], sizeof (groupName));
+ (void) mbstowcs(groupNamePrint, (char *)groupName,
+ sizeof (stmfGroupName) - 1);
+ /* call delete group */
+ stmfRet = stmfDeleteTargetGroup(&groupName);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_GROUP_IN_USE:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint,
+ gettext("group is in use by existing view entry"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("unknown error"));
+ ret++;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * listHostGroupFunc
+ *
+ * Lists the specified host groups or all if none are specified
+ *
+ */
+/*ARGSUSED*/
+static int
+listHostGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret = 0;
+ int stmfRet;
+ int i, j, outerLoop;
+ boolean_t verbose = B_FALSE;
+ boolean_t found = B_TRUE;
+ boolean_t operandEntered;
+ stmfGroupList *groupList;
+ stmfGroupProperties *groupProps;
+ wchar_t operandName[sizeof (stmfGroupName)];
+ wchar_t groupNamePrint[sizeof (stmfGroupName)];
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'v':
+ verbose = B_TRUE;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ if (operandLen > 0) {
+ outerLoop = operandLen;
+ operandEntered = B_TRUE;
+ } else {
+ outerLoop = 1;
+ operandEntered = B_FALSE;
+ }
+
+ stmfRet = stmfGetHostGroupList(&groupList);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ break;
+ }
+ return (1);
+ }
+
+ for (i = 0; i < outerLoop; i++) {
+ for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
+ (void) mbstowcs(groupNamePrint,
+ (char *)groupList->name[j],
+ sizeof (stmfGroupName) - 1);
+ groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
+ if (operandEntered) {
+ (void) mbstowcs(operandName, operands[i],
+ sizeof (stmfGroupName) - 1);
+ operandName[sizeof (stmfGroupName) - 1] = 0;
+ if (wcscmp(operandName, groupNamePrint)
+ == 0) {
+ found = B_TRUE;
+ }
+ }
+ if ((found && operandEntered) || !operandEntered) {
+ (void) printf("Host Group: %ws\n",
+ groupNamePrint);
+ if (verbose) {
+ stmfRet = stmfGetHostGroupMembers(
+ &(groupList->name[j]), &groupProps);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ return (1);
+ }
+ printGroupProps(groupProps);
+ }
+ if (found && operandEntered) {
+ break;
+ }
+ }
+
+ }
+ if (operandEntered && !found) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("not found"));
+ ret = 1;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * printGroupProps
+ *
+ * Prints group members for target or host groups
+ *
+ */
+static void
+printGroupProps(stmfGroupProperties *groupProps)
+{
+ int i;
+ wchar_t memberIdent[sizeof (groupProps->name[0].ident) + 1] = {0};
+
+
+ for (i = 0; i < groupProps->cnt; i++) {
+ (void) mbstowcs(memberIdent, (char *)groupProps->name[i].ident,
+ sizeof (groupProps->name[0].ident));
+ (void) printf("\tMember: %ws\n", memberIdent);
+ }
+}
+
+/*
+ * listTargetGroupFunc
+ *
+ * Lists the specified target groups or all if none are specified
+ *
+ */
+/*ARGSUSED*/
+static int
+listTargetGroupFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret = 0;
+ int stmfRet;
+ int i, j, outerLoop;
+ boolean_t verbose = B_FALSE;
+ boolean_t found = B_TRUE;
+ boolean_t operandEntered;
+ stmfGroupList *groupList;
+ stmfGroupProperties *groupProps;
+ wchar_t operandName[sizeof (stmfGroupName)];
+ wchar_t groupNamePrint[sizeof (stmfGroupName)];
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'v':
+ verbose = B_TRUE;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ if (operandLen > 0) {
+ outerLoop = operandLen;
+ operandEntered = B_TRUE;
+ } else {
+ outerLoop = 1;
+ operandEntered = B_FALSE;
+ }
+
+ stmfRet = stmfGetTargetGroupList(&groupList);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ break;
+ }
+ return (1);
+ }
+
+ for (i = 0; i < outerLoop; i++) {
+ for (found = B_FALSE, j = 0; j < groupList->cnt; j++) {
+ (void) mbstowcs(groupNamePrint,
+ (char *)groupList->name[j],
+ sizeof (stmfGroupName) - 1);
+ groupNamePrint[sizeof (stmfGroupName) - 1] = 0;
+ if (operandEntered) {
+ (void) mbstowcs(operandName, operands[i],
+ sizeof (stmfGroupName) - 1);
+ operandName[sizeof (stmfGroupName) - 1] = 0;
+ if (wcscmp(operandName, groupNamePrint)
+ == 0) {
+ found = B_TRUE;
+ }
+ }
+ if ((found && operandEntered) || !operandEntered) {
+ (void) printf("Target Group: %ws\n",
+ groupNamePrint);
+ if (verbose) {
+ stmfRet = stmfGetTargetGroupMembers(
+ &(groupList->name[j]), &groupProps);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ return (1);
+ }
+ printGroupProps(groupProps);
+ }
+ if (found && operandEntered) {
+ break;
+ }
+ }
+
+ }
+ if (operandEntered && !found) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("not found"));
+ ret = 1;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * listLuFunc
+ *
+ * List the logical units and optionally the properties
+ *
+ */
+/*ARGSUSED*/
+static int
+listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args)
+{
+ cmdOptions_t *optionList = options;
+ boolean_t operandEntered;
+ int i, j;
+ int ret = 0;
+ int stmfRet;
+ int outerLoop;
+ unsigned int inGuid[sizeof (stmfGuid)];
+ stmfGuid cmpGuid;
+ boolean_t verbose = B_FALSE;
+ boolean_t found;
+ char sGuid[GUID_INPUT + 1];
+ stmfGuidList *luList;
+ stmfLogicalUnitProperties luProps;
+ boolean_t invalidInput = B_FALSE;
+ stmfViewEntryList *viewEntryList;
+
+ for (; optionList->optval; optionList++) {
+ switch (optionList->optval) {
+ case 'v':
+ verbose = B_TRUE;
+ break;
+ }
+ }
+
+ if ((stmfRet = stmfGetLogicalUnitList(&luList))
+ != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("list failed"));
+ break;
+ }
+ return (1);
+ }
+
+ if (operandLen > 0) {
+ operandEntered = B_TRUE;
+ outerLoop = operandLen;
+ } else {
+ operandEntered = B_FALSE;
+ outerLoop = 1;
+ }
+
+
+ for (invalidInput = B_FALSE, i = 0; i < outerLoop; i++) {
+ if (operandEntered) {
+ if (strlen(operands[i]) != GUID_INPUT) {
+ invalidInput = B_TRUE;
+ } else {
+ for (j = 0; j < GUID_INPUT; j++) {
+ if (!isxdigit(operands[i][j])) {
+ invalidInput = B_TRUE;
+ break;
+ }
+ }
+ }
+ if (invalidInput) {
+ (void) fprintf(stderr, "%s: %s: %s%d%s\n",
+ cmdName, operands[i], gettext("must be "),
+ GUID_INPUT,
+ gettext(" hexadecimal digits long"));
+ invalidInput = B_FALSE;
+ continue;
+ }
+
+ for (j = 0; j < GUID_INPUT; j++) {
+ sGuid[j] = tolower(operands[i][j]);
+ }
+ sGuid[j] = 0;
+
+ (void) sscanf(sGuid,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
+ &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
+ &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
+ &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
+
+ for (j = 0; j < sizeof (stmfGuid); j++) {
+ cmpGuid.guid[j] = inGuid[j];
+ }
+ }
+
+ for (found = B_FALSE, j = 0; j < luList->cnt; j++) {
+ if (operandEntered) {
+ if (bcmp(luList->guid[j].guid, cmpGuid.guid,
+ sizeof (stmfGuid)) == 0) {
+ found = B_TRUE;
+ }
+ }
+ if ((found && operandEntered) || !operandEntered) {
+ (void) printf("LU Name: ");
+ printGuid(&luList->guid[j], stdout);
+ (void) printf("\n");
+
+ if (verbose) {
+ stmfRet = stmfGetLogicalUnitProperties(
+ &(luList->guid[j]), &luProps);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ printLuProps(&luProps);
+ } else {
+ (void) fprintf(stderr, "%s:",
+ cmdName);
+ printGuid(&luList->guid[j],
+ stderr);
+ (void) fprintf(stderr, "%s\n",
+ gettext(" get properties "
+ "failed"));
+ }
+ stmfRet = stmfGetViewEntryList(
+ &(luList->guid[j]),
+ &viewEntryList);
+ (void) printf(PROPS_FORMAT,
+ "View Entry Count");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%d",
+ viewEntryList->cnt);
+ } else {
+ (void) printf("unknown");
+ }
+ (void) printf("\n");
+ ret = printExtLuProps(
+ &(luList->guid[j]));
+ }
+ if (found && operandEntered) {
+ break;
+ }
+ }
+
+ }
+ if (operandEntered && !found) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("not found"));
+ ret = 1;
+ }
+ }
+
+ return (ret);
+}
+
+static void
+printGuid(stmfGuid *guid, FILE *stream)
+{
+ int i;
+ for (i = 0; i < 16; i++) {
+ (void) fprintf(stream, "%02X", guid->guid[i]);
+ }
+}
+
+static int
+printExtLuProps(stmfGuid *guid)
+{
+ int stmfRet;
+ luResource hdl = NULL;
+ int ret = 0;
+ char propVal[MAXNAMELEN];
+ size_t propValSize = sizeof (propVal);
+
+ if ((stmfRet = stmfGetLuResource(guid, &hdl))
+ != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ /* No error here */
+ return (0);
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("get extended properties failed"));
+ break;
+ }
+ return (1);
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Data File");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_META_FILENAME, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Meta File");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Size");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_BLOCK_SIZE, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Block Size");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_MGMT_URL, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Management URL");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Vendor ID");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_PID, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Product ID");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SERIAL_NUM, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Serial Num");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n", propVal);
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_PROTECT, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Write Protect");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n",
+ strcasecmp(propVal, "true") ? "Disabled" : "Enabled");
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_CACHE_DISABLE, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Writeback Cache");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ (void) printf("%s\n",
+ strcasecmp(propVal, "true") ? "Enabled" : "Disabled");
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else if (stmfRet == STMF_ERROR_NO_PROP_STANDBY) {
+ (void) printf("prop unavailable in standby\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
+ &propValSize);
+ (void) printf(PROPS_FORMAT, "Access State");
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ if (strcmp(propVal, STMF_ACCESS_ACTIVE) == 0) {
+ (void) printf("%s\n", "Active");
+ } else if (strcmp(propVal,
+ STMF_ACCESS_ACTIVE_TO_STANDBY) == 0) {
+ (void) printf("%s\n", "Active->Standby");
+ } else if (strcmp(propVal, STMF_ACCESS_STANDBY) == 0) {
+ (void) printf("%s\n", "Standby");
+ } else if (strcmp(propVal,
+ STMF_ACCESS_STANDBY_TO_ACTIVE) == 0) {
+ (void) printf("%s\n", "Standby->Active");
+ } else {
+ (void) printf("%s\n", "Unknown");
+ }
+ } else if (stmfRet == STMF_ERROR_NO_PROP) {
+ (void) printf("not set\n");
+ } else {
+ (void) printf("<error retrieving property>\n");
+ ret++;
+ }
+
+done:
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+
+}
+
+
+/*
+ * printLuProps
+ *
+ * Prints the properties for a logical unit
+ *
+ */
+static void
+printLuProps(stmfLogicalUnitProperties *luProps)
+{
+ (void) printf(PROPS_FORMAT, "Operational Status");
+ switch (luProps->status) {
+ case STMF_LOGICAL_UNIT_ONLINE:
+ (void) printf("Online");
+ break;
+ case STMF_LOGICAL_UNIT_OFFLINE:
+ (void) printf("Offline");
+ break;
+ case STMF_LOGICAL_UNIT_ONLINING:
+ (void) printf("Onlining");
+ break;
+ case STMF_LOGICAL_UNIT_OFFLINING:
+ (void) printf("Offlining");
+ break;
+ case STMF_LOGICAL_UNIT_UNREGISTERED:
+ (void) printf("unregistered");
+ (void) strncpy(luProps->providerName, "unregistered",
+ sizeof (luProps->providerName));
+ break;
+ default:
+ (void) printf("unknown");
+ break;
+ }
+ (void) printf("\n");
+ (void) printf(PROPS_FORMAT, "Provider Name");
+ if (luProps->providerName[0] != 0) {
+ (void) printf("%s", luProps->providerName);
+ } else {
+ (void) printf("unknown");
+ }
+ (void) printf("\n");
+ (void) printf(PROPS_FORMAT, "Alias");
+ if (luProps->alias[0] != 0) {
+ (void) printf("%s", luProps->alias);
+ } else {
+ (void) printf("-");
+ }
+ (void) printf("\n");
+}
+
+/*
+ * printTargetProps
+ *
+ * Prints the properties for a target
+ *
+ */
+static void
+printTargetProps(stmfTargetProperties *targetProps)
+{
+ (void) printf(PROPS_FORMAT, "Operational Status");
+ switch (targetProps->status) {
+ case STMF_TARGET_PORT_ONLINE:
+ (void) printf("Online");
+ break;
+ case STMF_TARGET_PORT_OFFLINE:
+ (void) printf("Offline");
+ break;
+ case STMF_TARGET_PORT_ONLINING:
+ (void) printf("Onlining");
+ break;
+ case STMF_TARGET_PORT_OFFLINING:
+ (void) printf("Offlining");
+ break;
+ default:
+ (void) printf("unknown");
+ break;
+ }
+ (void) printf("\n");
+ (void) printf(PROPS_FORMAT, "Provider Name");
+ if (targetProps->providerName[0] != 0) {
+ (void) printf("%s", targetProps->providerName);
+ }
+ (void) printf("\n");
+ (void) printf(PROPS_FORMAT, "Alias");
+ if (targetProps->alias[0] != 0) {
+ (void) printf("%s", targetProps->alias);
+ } else {
+ (void) printf("-");
+ }
+ (void) printf("\n");
+ (void) printf(PROPS_FORMAT, "Protocol");
+ switch (targetProps->protocol) {
+ case STMF_PROTOCOL_FIBRE_CHANNEL:
+ (void) printf("%s", "Fibre Channel");
+ break;
+ case STMF_PROTOCOL_ISCSI:
+ (void) printf("%s", "iSCSI");
+ break;
+ case STMF_PROTOCOL_SRP:
+ (void) printf("%s", "SRP");
+ break;
+ case STMF_PROTOCOL_SAS:
+ (void) printf("%s", "SAS");
+ break;
+ default:
+ (void) printf("%s", "unknown");
+ break;
+ }
+
+ (void) printf("\n");
+}
+
+/*
+ * printSessionProps
+ *
+ * Prints the session data
+ *
+ */
+static void
+printSessionProps(stmfSessionList *sessionList)
+{
+ int i;
+ char *cTime;
+ wchar_t initiator[STMF_IDENT_LENGTH + 1];
+
+ (void) printf(PROPS_FORMAT, "Sessions");
+ (void) printf("%d\n", sessionList->cnt);
+ for (i = 0; i < sessionList->cnt; i++) {
+ (void) mbstowcs(initiator,
+ (char *)sessionList->session[i].initiator.ident,
+ STMF_IDENT_LENGTH);
+ initiator[STMF_IDENT_LENGTH] = 0;
+ (void) printf(LVL3_FORMAT, "Initiator: ");
+ (void) printf("%ws\n", initiator);
+ (void) printf(LVL4_FORMAT, "Alias: ");
+ if (sessionList->session[i].alias[0] != 0) {
+ (void) printf("%s", sessionList->session[i].alias);
+ } else {
+ (void) printf("-");
+ }
+ (void) printf("\n");
+ (void) printf(LVL4_FORMAT, "Logged in since: ");
+ cTime = ctime(&(sessionList->session[i].creationTime));
+ if (cTime != NULL) {
+ (void) printf("%s", cTime);
+ } else {
+ (void) printf("unknown\n");
+ }
+ }
+}
+
+static int
+getStmfState(stmfState *state)
+{
+ int ret;
+
+ ret = stmfGetState(state);
+ switch (ret) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %d\n", cmdName,
+ gettext("unknown error"), ret);
+ break;
+ }
+ return (ret);
+}
+
+/*
+ * listStateFunc
+ *
+ * List the operational and config state of the stmf service
+ *
+ */
+/*ARGSUSED*/
+static int
+listStateFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret;
+ stmfState state;
+ boolean_t aluaEnabled;
+ uint32_t node;
+
+ if ((ret = getStmfState(&state)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ (void) printf("%-18s: ", "Operational Status");
+ switch (state.operationalState) {
+ case STMF_SERVICE_STATE_ONLINE:
+ (void) printf("online");
+ break;
+ case STMF_SERVICE_STATE_OFFLINE:
+ (void) printf("offline");
+ break;
+ case STMF_SERVICE_STATE_ONLINING:
+ (void) printf("onlining");
+ break;
+ case STMF_SERVICE_STATE_OFFLINING:
+ (void) printf("offlining");
+ break;
+ default:
+ (void) printf("unknown");
+ break;
+ }
+ (void) printf("\n");
+ (void) printf("%-18s: ", "Config Status");
+ switch (state.configState) {
+ case STMF_CONFIG_STATE_NONE:
+ (void) printf("uninitialized");
+ break;
+ case STMF_CONFIG_STATE_INIT:
+ (void) printf("initializing");
+ break;
+ case STMF_CONFIG_STATE_INIT_DONE:
+ (void) printf("initialized");
+ break;
+ default:
+ (void) printf("unknown");
+ break;
+ }
+ (void) printf("\n");
+ ret = stmfGetAluaState(&aluaEnabled, &node);
+ switch (ret) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %d\n", cmdName,
+ gettext("unknown error"), ret);
+ break;
+ }
+ (void) printf("%-18s: ", "ALUA Status");
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (aluaEnabled == B_TRUE) {
+ (void) printf("enabled");
+ } else {
+ (void) printf("disabled");
+ }
+ } else {
+ (void) printf("unknown");
+ }
+
+ (void) printf("\n");
+ (void) printf("%-18s: ", "ALUA Node");
+ if (ret == STMF_STATUS_SUCCESS) {
+ (void) printf("%d", node);
+ } else {
+ (void) printf("unknown");
+ }
+ (void) printf("\n");
+ return (ret);
+}
+
+/*
+ * listTargetFunc
+ *
+ * list the targets and optionally their properties
+ *
+ */
+/*ARGSUSED*/
+static int
+listTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ cmdOptions_t *optionList = options;
+ int ret = 0;
+ int stmfRet;
+ int i, j;
+ int outerLoop;
+ stmfSessionList *sessionList;
+ stmfDevid devid;
+ boolean_t operandEntered, found, verbose = B_FALSE;
+ stmfDevidList *targetList;
+ wchar_t targetIdent[STMF_IDENT_LENGTH + 1];
+ stmfTargetProperties targetProps;
+
+ if ((stmfRet = stmfGetTargetList(&targetList)) != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_NOT_FOUND:
+ ret = 0;
+ break;
+ case STMF_ERROR_SERVICE_OFFLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service offline"));
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ break;
+ }
+ return (1);
+ }
+
+ for (; optionList->optval; optionList++) {
+ switch (optionList->optval) {
+ case 'v':
+ verbose = B_TRUE;
+ break;
+ }
+ }
+
+ if (operandLen > 0) {
+ outerLoop = operandLen;
+ operandEntered = B_TRUE;
+ } else {
+ outerLoop = 1;
+ operandEntered = B_FALSE;
+ }
+
+ for (i = 0; i < outerLoop; i++) {
+ if (operandEntered) {
+ bzero(&devid, sizeof (devid));
+ (void) parseDevid(operands[i], &devid);
+ }
+ for (found = B_FALSE, j = 0; j < targetList->cnt; j++) {
+ if (operandEntered) {
+ if (bcmp(&devid, &(targetList->devid[j]),
+ sizeof (devid)) == 0) {
+ found = B_TRUE;
+ }
+ }
+ if ((found && operandEntered) || !operandEntered) {
+ (void) mbstowcs(targetIdent,
+ (char *)targetList->devid[j].ident,
+ STMF_IDENT_LENGTH);
+ targetIdent[STMF_IDENT_LENGTH] = 0;
+ (void) printf("Target: %ws\n", targetIdent);
+ if (verbose) {
+ stmfRet = stmfGetTargetProperties(
+ &(targetList->devid[j]),
+ &targetProps);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ printTargetProps(&targetProps);
+ } else {
+ (void) fprintf(stderr, "%s:",
+ cmdName);
+ (void) fprintf(stderr, "%s\n",
+ gettext(" get properties"
+ " failed"));
+ }
+ stmfRet = stmfGetSessionList(
+ &(targetList->devid[j]),
+ &sessionList);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ printSessionProps(sessionList);
+ } else {
+ (void) fprintf(stderr, "%s:",
+ cmdName);
+ (void) fprintf(stderr, "%s\n",
+ gettext(" get session info"
+ " failed"));
+ }
+ }
+ if (found && operandEntered) {
+ break;
+ }
+ }
+
+ }
+ if (operandEntered && !found) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], "not found");
+ ret = 1;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * listViewFunc
+ *
+ * list the view entries for the specified logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+listViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ stmfViewEntryList *viewEntryList;
+ stmfGuid inGuid;
+ unsigned int guid[sizeof (stmfGuid)];
+ int ret = 0;
+ int stmfRet;
+ int i, j, outerLoop;
+ boolean_t found = B_TRUE;
+ boolean_t operandEntered;
+ uint16_t outputLuNbr;
+ wchar_t groupName[sizeof (stmfGroupName)];
+ char sGuid[GUID_INPUT + 1];
+
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'l':
+ if (strlen(options->optarg) != GUID_INPUT) {
+ (void) fprintf(stderr,
+ "%s: %s: %s%d%s\n",
+ cmdName, options->optarg,
+ gettext("must be "), GUID_INPUT,
+ gettext(" hexadecimal digits"
+ " long"));
+ return (1);
+ }
+ bcopy(options->optarg, sGuid, GUID_INPUT);
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ if (operandLen > 0) {
+ outerLoop = operandLen;
+ operandEntered = B_TRUE;
+ } else {
+ outerLoop = 1;
+ operandEntered = B_FALSE;
+ }
+
+ for (i = 0; i < 32; i++)
+ sGuid[i] = tolower(sGuid[i]);
+ sGuid[i] = 0;
+
+ (void) sscanf(sGuid, "%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 (stmfGuid); i++) {
+ inGuid.guid[i] = guid[i];
+ }
+
+ if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
+ != STMF_STATUS_SUCCESS) {
+
+ switch (stmfRet) {
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("resource busy"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("unknown error"));
+ break;
+ }
+ return (1);
+ }
+
+ if (viewEntryList->cnt == 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("no views found"));
+ return (1);
+ }
+
+ for (i = 0; i < outerLoop; i++) {
+ for (found = B_FALSE, j = 0; j < viewEntryList->cnt; j++) {
+ if (operandEntered) {
+ if (atoi(operands[i]) ==
+ viewEntryList->ve[j].veIndex) {
+ found = B_TRUE;
+ }
+ }
+ if ((found && operandEntered) || !operandEntered) {
+ (void) printf("View Entry: %d\n",
+ viewEntryList->ve[j].veIndex);
+ (void) printf(VIEW_FORMAT, "Host group");
+ if (viewEntryList->ve[j].allHosts) {
+ (void) printf("All\n");
+ } else {
+ (void) mbstowcs(groupName,
+ viewEntryList->ve[j].hostGroup,
+ sizeof (stmfGroupName) - 1);
+ groupName[sizeof (stmfGroupName) - 1]
+ = 0;
+ (void) printf("%ws\n", groupName);
+ }
+ (void) printf(VIEW_FORMAT, "Target group");
+ if (viewEntryList->ve[j].allTargets) {
+ (void) printf("All\n");
+ } else {
+ (void) mbstowcs(groupName,
+ viewEntryList->ve[j].targetGroup,
+ sizeof (stmfGroupName) - 1);
+ groupName[sizeof (stmfGroupName) - 1]
+ = 0;
+ (void) printf("%ws\n", groupName);
+ }
+ outputLuNbr = ((viewEntryList->ve[j].luNbr[0] &
+ 0x3F) << 8) | viewEntryList->ve[j].luNbr[1];
+ (void) printf(VIEW_FORMAT, "LUN");
+ (void) printf("%d\n", outputLuNbr);
+ if (found && operandEntered) {
+ break;
+ }
+ }
+ }
+ if (operandEntered && !found) {
+ (void) fprintf(stderr, "%s: %s, %s: %s\n", cmdName,
+ sGuid, operands[i], gettext("not found"));
+ ret = 1;
+ }
+ }
+
+ return (ret);
+}
+
+
+/*
+ * onlineOfflineLu
+ *
+ * Purpose: Online or offline a logical unit
+ *
+ * lu - logical unit to online or offline
+ *
+ * state - ONLINE_LU
+ * OFFLINE_LU
+ */
+static int
+onlineOfflineLu(char *lu, int state)
+{
+ char sGuid[GUID_INPUT + 1];
+ stmfGuid inGuid;
+ unsigned int guid[sizeof (stmfGuid)];
+ int i;
+ int ret = 0, stmfRet;
+ stmfLogicalUnitProperties luProps;
+
+ if (strlen(lu) != GUID_INPUT) {
+ (void) fprintf(stderr, "%s: %s: %s %d %s\n", cmdName, lu,
+ gettext("must be"), GUID_INPUT,
+ gettext("hexadecimal digits long"));
+ return (1);
+ }
+
+ bcopy(lu, sGuid, GUID_INPUT);
+
+ for (i = 0; i < 32; i++)
+ sGuid[i] = tolower(sGuid[i]);
+ sGuid[i] = 0;
+
+ (void) sscanf(sGuid, "%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 (stmfGuid); i++) {
+ inGuid.guid[i] = guid[i];
+ }
+
+ if (state == ONLINE_LU) {
+ ret = stmfOnlineLogicalUnit(&inGuid);
+ } else if (state == OFFLINE_LU) {
+ ret = stmfOfflineLogicalUnit(&inGuid);
+ } else {
+ return (STMFADM_FAILURE);
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ switch (ret) {
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ lu, gettext("not found"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ break;
+ }
+ } else {
+ struct timespec ts = {0};
+ unsigned int count = 0;
+ uint32_t ret_state;
+
+ ret_state = (state == ONLINE_LU) ?
+ STMF_LOGICAL_UNIT_ONLINING : STMF_LOGICAL_UNIT_OFFLINING;
+ ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL;
+
+ /* CONSTCOND */
+ while (1) {
+ stmfRet = stmfGetLogicalUnitProperties(&inGuid,
+ &luProps);
+ if (stmfRet == STMF_STATUS_SUCCESS)
+ ret_state = luProps.status;
+
+ if ((state == ONLINE_LU &&
+ ret_state == STMF_LOGICAL_UNIT_ONLINE) ||
+ (state == OFFLINE_LU &&
+ ret_state == STMF_LOGICAL_UNIT_OFFLINE))
+ return (STMFADM_SUCCESS);
+
+ if ((state == ONLINE_LU &&
+ ret_state == STMF_LOGICAL_UNIT_OFFLINE) ||
+ (state == OFFLINE_LU &&
+ ret_state == STMF_LOGICAL_UNIT_ONLINE))
+ return (STMFADM_FAILURE);
+
+ if (++count == DELAYED_EXEC_WAIT_MAX) {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("Logical Unit state change request "
+ "submitted. Waiting for completion "
+ "timed out"));
+ return (STMFADM_FAILURE);
+ }
+ (void) nanosleep(&ts, NULL);
+ }
+ }
+ return (STMFADM_FAILURE);
+}
+
+/*
+ * onlineLuFunc
+ *
+ * Purpose: Online a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+onlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret;
+ stmfState state;
+
+ ret = getStmfState(&state);
+ if (ret != STMF_STATUS_SUCCESS)
+ return (ret);
+ if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
+ state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service is offline"));
+ return (1);
+ }
+ return (onlineOfflineLu(operands[0], ONLINE_LU));
+}
+
+/*
+ * offlineLuFunc
+ *
+ * Purpose: Offline a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+offlineLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ return (onlineOfflineLu(operands[0], OFFLINE_LU));
+}
+
+/*
+ * onlineOfflineTarget
+ *
+ * Purpose: Online or offline a target
+ *
+ * target - target to online or offline
+ *
+ * state - ONLINE_TARGET
+ * OFFLINE_TARGET
+ */
+static int
+onlineOfflineTarget(char *target, int state)
+{
+ int ret = 0, stmfRet = 0;
+ stmfDevid devid;
+ stmfTargetProperties targetProps;
+
+ if (parseDevid(target, &devid) != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, target, gettext("unrecognized device id"));
+ return (1);
+ }
+ if (state == ONLINE_TARGET) {
+ ret = stmfOnlineTarget(&devid);
+ } else if (state == OFFLINE_TARGET) {
+ ret = stmfOfflineTarget(&devid);
+ } else {
+ return (STMFADM_FAILURE);
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ switch (ret) {
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("resource busy"));
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ target, gettext("not found"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unknown error"));
+ break;
+ }
+ } else {
+ struct timespec ts = {0};
+ unsigned int count = 0;
+ uint32_t ret_state;
+
+ ret_state = (state == ONLINE_TARGET) ?
+ STMF_TARGET_PORT_ONLINING : STMF_TARGET_PORT_OFFLINING;
+ ts.tv_nsec = DELAYED_EXEC_WAIT_INTERVAL;
+
+ /* CONSTCOND */
+ while (1) {
+ stmfRet = stmfGetTargetProperties(&devid, &targetProps);
+ if (stmfRet == STMF_STATUS_SUCCESS)
+ ret_state = targetProps.status;
+
+ if ((state == ONLINE_TARGET &&
+ ret_state == STMF_TARGET_PORT_ONLINE) ||
+ (state == OFFLINE_TARGET &&
+ ret_state == STMF_TARGET_PORT_OFFLINE)) {
+ return (STMFADM_SUCCESS);
+ }
+
+ if ((state == ONLINE_TARGET &&
+ ret_state == STMF_TARGET_PORT_OFFLINE) ||
+ (state == OFFLINE_TARGET &&
+ ret_state == STMF_TARGET_PORT_ONLINE)) {
+ return (STMFADM_FAILURE);
+ }
+
+ if (++count == DELAYED_EXEC_WAIT_MAX) {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("Target state change request "
+ "submitted. Waiting for completion "
+ "timed out."));
+ return (STMFADM_FAILURE);
+ }
+ (void) nanosleep(&ts, NULL);
+ }
+ }
+ return (STMFADM_FAILURE);
+}
+
+/*
+ * onlineTargetFunc
+ *
+ * Purpose: Online a target
+ *
+ */
+/*ARGSUSED*/
+static int
+onlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int ret;
+ stmfState state;
+
+ ret = getStmfState(&state);
+ if (ret != STMF_STATUS_SUCCESS)
+ return (ret);
+ if (state.operationalState == STMF_SERVICE_STATE_OFFLINE ||
+ state.operationalState == STMF_SERVICE_STATE_OFFLINING) {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service is offline"));
+ return (1);
+ }
+ return (onlineOfflineTarget(operands[0], ONLINE_TARGET));
+}
+
+/*
+ * offlineTargetFunc
+ *
+ * Purpose: Offline a target
+ *
+ */
+/*ARGSUSED*/
+static int
+offlineTargetFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ return (onlineOfflineTarget(operands[0], OFFLINE_TARGET));
+}
+
+
+/*ARGSUSED*/
+static int
+removeHostGroupMemberFunc(int operandLen, char *operands[],
+ cmdOptions_t *options, void *args)
+{
+ int i;
+ int ret = 0;
+ int stmfRet;
+ stmfGroupName groupName = {0};
+ stmfDevid devid;
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'g':
+ (void) mbstowcs(groupNamePrint, options->optarg,
+ sizeof (stmfGroupName) - 1);
+ bcopy(options->optarg, groupName,
+ strlen(options->optarg));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ for (i = 0; i < operandLen; i++) {
+ if (parseDevid(operands[i], &devid) != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, operands[i],
+ gettext("unrecognized device id"));
+ ret++;
+ continue;
+ }
+ stmfRet = stmfRemoveFromHostGroup(&groupName, &devid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_MEMBER_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_GROUP_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], "resource busy");
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("unknown error"));
+ ret++;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * removeTargetGroupMemberFunc
+ *
+ * Removes one or more members from a target group
+ *
+ */
+/*ARGSUSED*/
+static int
+removeTargetGroupMemberFunc(int operandLen, char *operands[],
+ cmdOptions_t *options, void *args)
+{
+ int i;
+ int ret = 0;
+ int stmfRet;
+ stmfGroupName groupName = {0};
+ stmfDevid devid;
+ wchar_t groupNamePrint[sizeof (stmfGroupName)] = {0};
+
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'g':
+ (void) mbstowcs(groupNamePrint, options->optarg,
+ sizeof (stmfGroupName) - 1);
+ bcopy(options->optarg, groupName,
+ strlen(options->optarg));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
+ }
+ }
+
+ for (i = 0; i < operandLen; i++) {
+ if (parseDevid(operands[i], &devid) != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n",
+ cmdName, operands[i],
+ gettext("unrecognized device id"));
+ ret++;
+ continue;
+ }
+ stmfRet = stmfRemoveFromTargetGroup(&groupName, &devid);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_MEMBER_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_GROUP_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %ws: %s\n", cmdName,
+ groupNamePrint, gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ case STMF_ERROR_TG_ONLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF target must be offline"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("unknown error"));
+ ret++;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * removeViewFunc
+ *
+ * Removes one or more view entries from a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+removeViewFunc(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ char sGuid[GUID_INPUT + 1];
+ stmfViewEntryList *viewEntryList;
+ stmfGuid inGuid;
+ uint32_t count;
+ unsigned int guid[sizeof (stmfGuid)];
+ char *endPtr;
+ uint32_t veNbr;
+ int i;
+ boolean_t all = B_FALSE;
+ boolean_t luInput = B_FALSE;
+ int ret = 0;
+ int stmfRet;
+
+ /* Note: 'l' is required */
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 'l':
+ if (strlen(options->optarg) != GUID_INPUT) {
+ (void) fprintf(stderr,
+ "%s: %s: %s %d %s\n",
+ cmdName, options->optarg,
+ gettext("must be"), GUID_INPUT,
+ gettext("hexadecimal digits long"));
+ return (1);
+ }
+ bcopy(options->optarg, sGuid, GUID_INPUT);
+ luInput = B_TRUE;
+ break;
+ case 'a':
+ /* removing all view entries for this GUID */
+ all = B_TRUE;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ "unknown option");
+ return (1);
+ }
+ }
+
+ if (!all && operandLen == 0) {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("no view entries specified"));
+ return (1);
+ }
+
+ if (!luInput) {
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("logical unit (-l) not specified"));
+ return (1);
+ }
+
+ for (i = 0; i < 32; i++)
+ sGuid[i] = tolower(sGuid[i]);
+ sGuid[i] = 0;
+
+ (void) sscanf(sGuid, "%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 (stmfGuid); i++) {
+ inGuid.guid[i] = guid[i];
+ }
+
+ if ((stmfRet = stmfGetViewEntryList(&inGuid, &viewEntryList))
+ != STMF_STATUS_SUCCESS) {
+
+ switch (stmfRet) {
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("resource busy"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ break;
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("unknown error"));
+ break;
+ }
+ return (1);
+ }
+
+ if (viewEntryList->cnt == 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("no views found"));
+ return (1);
+ }
+
+ if (all) {
+ count = viewEntryList->cnt;
+ } else {
+ count = operandLen;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (all) {
+ veNbr = viewEntryList->ve[i].veIndex;
+ } else {
+ endPtr = NULL;
+ veNbr = strtol(operands[i], &endPtr, 10);
+ if (endPtr && *endPtr != 0) {
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ operands[i], gettext("invalid input"));
+ continue;
+ }
+ }
+ stmfRet = stmfRemoveViewEntry(&inGuid, veNbr);
+ switch (stmfRet) {
+ case STMF_STATUS_SUCCESS:
+ break;
+ case STMF_ERROR_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s: %d: %s\n",
+ cmdName, sGuid, veNbr,
+ gettext("not found"));
+ ret++;
+ break;
+ case STMF_ERROR_BUSY:
+ (void) fprintf(stderr, "%s: %s: %s\n", cmdName,
+ sGuid, gettext("resource busy"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ ret++;
+ break;
+ case STMF_ERROR_CONFIG_NONE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service is not initialized"));
+ ret++;
+ break;
+ case STMF_ERROR_SERVICE_DATA_VERSION:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service version incorrect"));
+ ret++;
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s, %d: %s",
+ cmdName, sGuid, veNbr,
+ gettext("unknown error"));
+ ret++;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * input:
+ * execFullName - exec name of program (argv[0])
+ *
+ * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
+ * (changed name to lowerCamelCase to keep consistent with this file)
+ *
+ * Returns:
+ * command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+ char *lastSlash, *execBasename;
+
+ /* guard against '/' at end of command invocation */
+ for (;;) {
+ lastSlash = strrchr(execFullname, '/');
+ if (lastSlash == NULL) {
+ execBasename = execFullname;
+ break;
+ } else {
+ execBasename = lastSlash + 1;
+ if (*execBasename == '\0') {
+ *lastSlash = '\0';
+ continue;
+ }
+ break;
+ }
+ }
+ return (execBasename);
+}
+
+int
+main(int argc, char *argv[])
+{
+ synTables_t synTables;
+ char versionString[VERSION_STRING_MAX_LEN];
+ int ret;
+ int funcRet;
+ void *subcommandArgs = NULL;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+ /* set global command name */
+ cmdName = getExecBasename(argv[0]);
+
+ (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
+ VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
+ synTables.versionString = versionString;
+ synTables.longOptionTbl = &longOptions[0];
+ synTables.subCommandPropsTbl = &subcommands[0];
+
+ ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ return (funcRet);
+} /* end main */
diff --git a/usr/src/cmd/stmfadm/stmfadm.h b/usr/src/cmd/stmfadm/stmfadm.h
new file mode 100644
index 0000000..2224db9
--- /dev/null
+++ b/usr/src/cmd/stmfadm/stmfadm.h
@@ -0,0 +1,73 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _STMFADM_H
+#define _STMFADM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <cmdparse.h>
+
+/* DEFINES */
+
+/* subcommands */
+#define ADD_MEMBER SUBCOMMAND(0)
+#define ADD_VIEW SUBCOMMAND(1)
+#define CREATE_I_GROUP SUBCOMMAND(2)
+#define CREATE_T_GROUP SUBCOMMAND(3)
+#define DELETE_GROUP SUBCOMMAND(4)
+#define LIST_INIT SUBCOMMAND(5)
+#define LIST_INIT_GROUP SUBCOMMAND(6)
+#define LIST_TARGET_GROUP SUBCOMMAND(7)
+#define LIST_VIEW SUBCOMMAND(8)
+#define REMOVE_MEMBER SUBCOMMAND(9)
+#define REMOVE_VIEW SUBCOMMAND(10)
+
+
+#define OPERANDSTRING_INITIATOR "initiator-name"
+#define OPERANDSTRING_LU "LU-name"
+#define OPERANDSTRING_GROUP_MEMBER "group-member"
+#define OPERANDSTRING_GROUP_NAME "group-name"
+#define OPERANDSTRING_TARGET "target-name"
+#define OPERANDSTRING_VIEW_ENTRY "ve-number"
+
+#define VERSION_STRING_MAX_LEN 10
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STMFADM_H */
diff --git a/usr/src/cmd/stmfsvc/stmf.xml b/usr/src/cmd/stmfsvc/stmf.xml
new file mode 100644
index 0000000..b3119da
--- /dev/null
+++ b/usr/src/cmd/stmfsvc/stmf.xml
@@ -0,0 +1,119 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+
+<!--
+
+CDDL HEADER START
+
+The contents of this file are subject to the terms of the
+Common Development and Distribution License (the "License").
+You may not use this file except in compliance with the License.
+
+You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+or http://www.opensolaris.org/os/licensing.
+See the License for the specific language governing permissions
+and limitations under the License.
+
+When distributing Covered Code, include this CDDL HEADER in each
+file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+If applicable, add the following below this CDDL HEADER, with the
+fields enclosed by brackets "[]" replaced with your own identifying
+information: Portions Copyright [yyyy] [name of copyright owner]
+
+CDDL HEADER END
+
+Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+Use is subject to license terms.
+
+
+Service manifests for SCSI Target Mode Framework
+-->
+
+<!--
+
+-->
+
+<service_bundle type='manifest' name='stmf'>
+
+<service
+ name='system/stmf'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance/>
+
+ <dependency name = 'filesystem_local'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri
+ value='svc:/system/filesystem/local:default'/>
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/svc-stmf start'
+ timeout_seconds='600'>
+ <method_context>
+ <method_credential
+ user='root'
+ group='root'
+ privileges='basic,sys_devices'
+ />
+ </method_context>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/lib/svc/method/svc-stmf stop'
+ timeout_seconds='600'>
+ <method_context>
+ <method_credential
+ user='root'
+ group='root'
+ privileges='basic,sys_devices'
+ />
+ </method_context>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring'
+ value='transient' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <!-- to start stop stmf -->
+ <propval name='action_authorization' type='astring'
+ value='solaris.smf.manage.stmf' />
+ </property_group>
+
+ <property_group name='host_groups' type='application'>
+ </property_group>
+
+ <property_group name='target_groups' type='application'>
+ </property_group>
+
+
+ <stability value='Evolving' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ STMF
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='stmf' section='7D'
+ manpath='/usr/share/man' />
+ <manpage title='stmfadm' section='1M'
+ manpath='/usr/share /man' />
+ </documentation>
+ </template>
+
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/stmfsvc/stmfsvc.c b/usr/src/cmd/stmfsvc/stmfsvc.c
new file mode 100644
index 0000000..814ebc2
--- /dev/null
+++ b/usr/src/cmd/stmfsvc/stmfsvc.c
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <cmdparse.h>
+#include <libstmf.h>
+#include <signal.h>
+#include <pthread.h>
+#include <locale.h>
+
+static int svcStart(int, char **, cmdOptions_t *, void *);
+static int svcStop(int, char **, cmdOptions_t *, void *);
+static int online();
+
+/*
+ * MAJOR - This should only change when there is an incompatible change made
+ * to the interfaces or the output.
+ *
+ * MINOR - This should change whenever there is a new command or new feature
+ * with no incompatible change.
+ */
+#define VERSION_STRING_MAJOR "1"
+#define VERSION_STRING_MINOR "0"
+#define VERSION_STRING_MAX_LEN 10
+
+/* 10 ms sleep in nanoseconds */
+#define TEN_MS_NANOSLEEP 10000000
+
+/* tables set up based on cmdparse instructions */
+
+/* add new options here */
+optionTbl_t longOptions[] = {
+ {NULL, 0, 0, 0}
+};
+
+/*
+ * Add new subcommands here
+ */
+subCommandProps_t subcommands[] = {
+ {"start", svcStart, NULL, NULL, NULL, OPERAND_NONE, NULL},
+ {"stop", svcStop, NULL, NULL, NULL, OPERAND_NONE, NULL},
+ {NULL, 0, NULL, NULL, 0, NULL, 0, NULL}
+};
+
+/* globals */
+char *cmdName;
+
+/*
+ * svcStop
+ *
+ * Offlines the stmf service
+ *
+ */
+/*ARGSUSED*/
+static int
+svcStop(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int stmfRet;
+ int ret = 0;
+ stmfState state;
+ boolean_t serviceOffline = B_FALSE;
+ struct timespec rqtp;
+
+ bzero(&rqtp, sizeof (rqtp));
+
+ rqtp.tv_nsec = TEN_MS_NANOSLEEP;
+
+ if ((stmfRet = stmfOffline()) != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_SERVICE_OFFLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service already offline"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unable to offline service"));
+ break;
+ }
+ return (1);
+ }
+
+ /* wait for service offline */
+ while (!serviceOffline) {
+ stmfRet = stmfGetState(&state);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ ret = 1;
+ break;
+ }
+ if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
+ serviceOffline = B_TRUE;
+ } else {
+ (void) nanosleep(&rqtp, NULL);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * loadConfig
+ *
+ * Loads the stmf config from the SMF repository
+ *
+ */
+/*ARGSUSED*/
+static int
+svcStart(int operandLen, char *operands[], cmdOptions_t *options,
+ void *args)
+{
+ int stmfRet;
+ int ret = 0;
+ (void) stmfLoadStmfProps();
+ if ((stmfRet = stmfLoadConfig()) != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_SERVICE_ONLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service must be offline"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("Unable to load the configuration. "
+ "See /var/adm/messages for details"));
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("For information on reverting the "
+ "stmf:default instance to a previously "
+ "running configuration see the man page "
+ "for svccfg(1M)"));
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("After reverting the instance "
+ "you must clear the service maintenance "
+ "state. See the man page for svcadm(1M)"));
+ break;
+ }
+ return (1);
+ }
+ ret = online();
+ return (ret);
+
+}
+
+/*
+ * online
+ *
+ * Onlines the stmf service
+ *
+ */
+/*ARGSUSED*/
+static int
+online()
+{
+ int stmfRet;
+ int ret = 0;
+ stmfState state;
+ boolean_t serviceOnline = B_FALSE;
+ struct timespec rqtp;
+
+ bzero(&rqtp, sizeof (rqtp));
+
+ rqtp.tv_nsec = TEN_MS_NANOSLEEP;
+
+ if ((stmfRet = stmfOnline()) != STMF_STATUS_SUCCESS) {
+ switch (stmfRet) {
+ case STMF_ERROR_PERM:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("permission denied"));
+ break;
+ case STMF_ERROR_SERVICE_NOT_FOUND:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service not found"));
+ break;
+ case STMF_ERROR_SERVICE_ONLINE:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("STMF service already online"));
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %s\n", cmdName,
+ gettext("unable to online service"));
+ break;
+ }
+ return (1);
+ }
+
+ /* wait for service online */
+ while (!serviceOnline) {
+ stmfRet = stmfGetState(&state);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ ret = 1;
+ break;
+ }
+ if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
+ serviceOnline = B_TRUE;
+ } else {
+ (void) nanosleep(&rqtp, NULL);
+ }
+ }
+
+ return (ret);
+}
+
+
+/*
+ * input:
+ * execFullName - exec name of program (argv[0])
+ *
+ * copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
+ * (changed name to lowerCamelCase to keep consistent with this file)
+ *
+ * Returns:
+ * command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+ char *lastSlash, *execBasename;
+
+ /* guard against '/' at end of command invocation */
+ for (;;) {
+ lastSlash = strrchr(execFullname, '/');
+ if (lastSlash == NULL) {
+ execBasename = execFullname;
+ break;
+ } else {
+ execBasename = lastSlash + 1;
+ if (*execBasename == '\0') {
+ *lastSlash = '\0';
+ continue;
+ }
+ break;
+ }
+ }
+ return (execBasename);
+}
+
+int
+main(int argc, char *argv[])
+{
+ synTables_t synTables;
+ char versionString[VERSION_STRING_MAX_LEN];
+ int ret;
+ int funcRet;
+ void *subcommandArgs = NULL;
+
+ (void) setlocale(LC_ALL, "");
+ /* set global command name */
+ cmdName = getExecBasename(argv[0]);
+
+ (void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
+ VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
+ synTables.versionString = versionString;
+ synTables.longOptionTbl = &longOptions[0];
+ synTables.subCommandPropsTbl = &subcommands[0];
+
+ ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ return (funcRet);
+} /* end main */
diff --git a/usr/src/common/cmdparse/cmdparse.c b/usr/src/common/cmdparse/cmdparse.c
new file mode 100644
index 0000000..7a9e575
--- /dev/null
+++ b/usr/src/common/cmdparse/cmdparse.c
@@ -0,0 +1,681 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <cmdparse.h>
+
+
+/* Usage types */
+#define GENERAL_USAGE 1
+#define DETAIL_USAGE 2
+
+/* printable ascii character set len */
+#define MAXOPTIONS (uint_t)('~' - '!' + 1)
+
+/*
+ * MAXOPTIONSTRING is the max length of the options string used in getopt and
+ * will be the printable character set + ':' for each character,
+ * providing for options with arguments. e.g. "t:Cs:hglr:"
+ */
+#define MAXOPTIONSTRING MAXOPTIONS * 2
+
+/* standard command options table to support -?, -V */
+struct option standardCmdOptions[] = {
+ {"help", no_argument, NULL, '?'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+/* standard subcommand options table to support -? */
+struct option standardSubCmdOptions[] = {
+ {"help", no_argument, NULL, '?'},
+ {NULL, 0, NULL, 0}
+};
+
+/* forward declarations */
+static int getSubcommandProps(char *, subCommandProps_t **);
+static char *getExecBasename(char *);
+static void usage(uint_t);
+static void subUsage(uint_t, subCommandProps_t *);
+static char *getLongOption(int);
+static char *getOptionArgDesc(int);
+
+/* global data */
+static struct option *_longOptions;
+static subCommandProps_t *_subCommandProps;
+static optionTbl_t *_clientOptionTbl;
+static char *commandName;
+
+
+/*
+ * input:
+ * subCommand - subcommand value
+ * output:
+ * subCommandProps - pointer to subCommandProps_t structure allocated by caller
+ *
+ * On successful return, subCommandProps contains the properties for the value
+ * in subCommand. On failure, the contents of subCommandProps is unspecified.
+ *
+ * Returns:
+ * zero on success
+ * non-zero on failure
+ *
+ */
+static int
+getSubcommandProps(char *subCommand, subCommandProps_t **subCommandProps)
+{
+ subCommandProps_t *sp;
+ int len;
+
+ for (sp = _subCommandProps; sp->name; sp++) {
+ len = strlen(subCommand);
+ if (len == strlen(sp->name) &&
+ strncasecmp(subCommand, sp->name, len) == 0) {
+ *subCommandProps = sp;
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * input:
+ * shortOption - short option character for which to return the
+ * associated long option string
+ *
+ * Returns:
+ * on success, long option name
+ * on failure, NULL
+ */
+static char *
+getLongOption(int shortOption)
+{
+ struct option *op;
+ for (op = _longOptions; op->name; op++) {
+ if (shortOption == op->val) {
+ return (op->name);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * input
+ * shortOption - short option character for which to return the
+ * option argument
+ * Returns:
+ * on success, argument string
+ * on failure, NULL
+ */
+static char *
+getOptionArgDesc(int shortOption)
+{
+ optionTbl_t *op;
+ for (op = _clientOptionTbl; op->name; op++) {
+ if (op->val == shortOption &&
+ op->has_arg == required_argument) {
+ return (op->argDesc);
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * Print usage for a subcommand.
+ *
+ * input:
+ * usage type - GENERAL_USAGE, DETAIL_USAGE
+ * subcommand - pointer to subCommandProps_t structure
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+subUsage(uint_t usageType, subCommandProps_t *subcommand)
+{
+ int i;
+ char *optionArgDesc;
+ char *longOpt;
+
+ if (usageType == GENERAL_USAGE) {
+ (void) printf("%s:\t%s %s [", gettext("Usage"), commandName,
+ subcommand->name);
+ for (i = 0; standardSubCmdOptions[i].name; i++) {
+ (void) printf("-%c", standardSubCmdOptions[i].val);
+ if (standardSubCmdOptions[i+1].name)
+ (void) printf(",");
+ }
+ (void) fprintf(stdout, "]\n");
+ return;
+ }
+
+ /* print subcommand usage */
+ (void) printf("\n%s:\t%s %s ", gettext("Usage"), commandName,
+ subcommand->name);
+
+ /* print options if applicable */
+ if (subcommand->optionString != NULL) {
+ if (subcommand->required) {
+ (void) printf("%s", gettext("<"));
+ } else {
+ (void) printf("%s", gettext("["));
+ }
+ (void) printf("%s", gettext("OPTIONS"));
+ if (subcommand->required) {
+ (void) printf("%s ", gettext(">"));
+ } else {
+ (void) printf("%s ", gettext("]"));
+ }
+ }
+
+ /* print operand requirements */
+ if (!(subcommand->operand & OPERAND_NONE) &&
+ !(subcommand->operand & OPERAND_MANDATORY)) {
+ (void) printf(gettext("["));
+ }
+
+ if (subcommand->operand & OPERAND_MANDATORY) {
+ (void) printf(gettext("<"));
+ }
+
+ if (!(subcommand->operand & OPERAND_NONE)) {
+ assert(subcommand->operandDefinition);
+ (void) printf("%s", subcommand->operandDefinition);
+ }
+
+ if (subcommand->operand & OPERAND_MULTIPLE) {
+ (void) printf(gettext(" ..."));
+ }
+
+ if (subcommand->operand & OPERAND_MANDATORY) {
+ (void) printf(gettext(">"));
+ }
+
+ if (!(subcommand->operand & OPERAND_NONE) &&
+ !(subcommand->operand & OPERAND_MANDATORY)) {
+ (void) printf(gettext("]"));
+ }
+
+ /* print options for subcommand */
+ if (subcommand->optionString != NULL) {
+ (void) printf("\n\t%s:", gettext("OPTIONS"));
+ for (i = 0; i < strlen(subcommand->optionString); i++) {
+ assert((longOpt = getLongOption(
+ subcommand->optionString[i])) != NULL);
+ (void) printf("\n\t\t-%c, --%s ",
+ subcommand->optionString[i],
+ longOpt);
+ optionArgDesc =
+ getOptionArgDesc(subcommand->optionString[i]);
+ if (optionArgDesc != NULL) {
+ (void) printf("<%s>", optionArgDesc);
+ }
+ if (subcommand->exclusive &&
+ strchr(subcommand->exclusive,
+ subcommand->optionString[i])) {
+ (void) printf(" (%s)", gettext("exclusive"));
+ }
+ }
+ }
+ (void) fprintf(stdout, "\n");
+ if (subcommand->helpText) {
+ (void) printf("%s\n", subcommand->helpText);
+ }
+}
+
+/*
+ * input:
+ * type of usage statement to print
+ *
+ * Returns:
+ * return value of subUsage
+ */
+static void
+usage(uint_t usageType)
+{
+ int i;
+ subCommandProps_t *sp;
+
+ /* print general command usage */
+ (void) printf("%s:\t%s ", gettext("Usage"), commandName);
+
+ for (i = 0; standardCmdOptions[i].name; i++) {
+ (void) printf("-%c", standardCmdOptions[i].val);
+ if (standardCmdOptions[i+1].name)
+ (void) printf(",");
+ }
+
+ if (usageType == GENERAL_USAGE) {
+ for (i = 0; standardSubCmdOptions[i].name; i++) {
+ (void) printf(",--%s", standardSubCmdOptions[i].name);
+ if (standardSubCmdOptions[i+1].name)
+ (void) printf(",");
+ }
+ }
+
+ (void) fprintf(stdout, "\n");
+
+
+ /* print all subcommand usage */
+ for (sp = _subCommandProps; sp->name; sp++) {
+ subUsage(usageType, sp);
+ }
+}
+
+/*
+ * input:
+ * execFullName - exec name of program (argv[0])
+ *
+ * Returns:
+ * command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+ char *lastSlash, *execBasename;
+
+ /* guard against '/' at end of command invocation */
+ for (;;) {
+ lastSlash = strrchr(execFullname, '/');
+ if (lastSlash == NULL) {
+ execBasename = execFullname;
+ break;
+ } else {
+ execBasename = lastSlash + 1;
+ if (*execBasename == '\0') {
+ *lastSlash = '\0';
+ continue;
+ }
+ break;
+ }
+ }
+ return (execBasename);
+}
+
+/*
+ * cmdParse is a parser that checks syntax of the input command against
+ * various rules tables.
+ *
+ * It provides usage feedback based upon the passed rules tables by calling
+ * two usage functions, usage, subUsage
+ *
+ * When syntax is successfully validated, the associated function is called
+ * using the subcommands table functions.
+ *
+ * Syntax is as follows:
+ * command subcommand [<options>] [<operand>]
+ *
+ * There are two standard short and long options assumed:
+ * -?, --help Provides usage on a command or subcommand
+ * and stops further processing of the arguments
+ *
+ * -V, --version Provides version information on the command
+ * and stops further processing of the arguments
+ *
+ * These options are loaded by this function.
+ *
+ * input:
+ * argc, argv from main
+ * syntax rules tables (synTables_t structure)
+ * callArgs - void * passed by caller to be passed to subcommand function
+ *
+ * output:
+ * funcRet - pointer to int that holds subcommand function return value
+ *
+ * Returns:
+ *
+ * zero on successful syntax parse and function call
+ *
+ * 1 on unsuccessful syntax parse (no function has been called)
+ * This could be due to a version or help call or simply a
+ * general usage call.
+ *
+ * -1 check errno, call failed
+ *
+ * This module is not MT-safe.
+ *
+ */
+int
+cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs,
+ int *funcRet)
+{
+ int getoptargc;
+ char **getoptargv;
+ int opt;
+ int operInd;
+ int i, j;
+ int len;
+ int requiredOptionCnt = 0, requiredOptionEntered = 0;
+ char *availOptions;
+ char *versionString;
+ char optionStringAll[MAXOPTIONSTRING + 1];
+ subCommandProps_t *subcommand;
+ cmdOptions_t cmdOptions[MAXOPTIONS + 1];
+ optionTbl_t *optionTbl;
+ struct option *lp;
+ struct option intLongOpt[MAXOPTIONS + 1];
+
+ /*
+ * Check for NULLs on mandatory input arguments
+ *
+ * Note: longOptionTbl can be NULL in the case
+ * where there is no caller defined options
+ *
+ */
+ assert(synTable.versionString);
+ assert(synTable.subCommandPropsTbl);
+ assert(funcRet);
+
+ versionString = synTable.versionString;
+
+ /* set global command name */
+ commandName = getExecBasename(argv[0]);
+
+ /* Set unbuffered output */
+ setbuf(stdout, NULL);
+
+ /* load globals */
+ _subCommandProps = synTable.subCommandPropsTbl;
+ _clientOptionTbl = synTable.longOptionTbl;
+
+ /* There must be at least two arguments */
+ if (argc < 2) {
+ usage(GENERAL_USAGE);
+ return (1);
+ }
+
+ (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt));
+
+ /*
+ * load standard subcommand options to internal long options table
+ * Two separate getopt_long(3C) tables are used.
+ */
+ for (i = 0; standardSubCmdOptions[i].name; i++) {
+ intLongOpt[i].name = standardSubCmdOptions[i].name;
+ intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg;
+ intLongOpt[i].flag = standardSubCmdOptions[i].flag;
+ intLongOpt[i].val = standardSubCmdOptions[i].val;
+ }
+
+ /*
+ * copy caller's long options into internal long options table
+ * We do this for two reasons:
+ * 1) We need to use the getopt_long option structure internally
+ * 2) We need to prepend the table with the standard option
+ * for all subcommands (currently -?)
+ */
+ for (optionTbl = synTable.longOptionTbl;
+ optionTbl && optionTbl->name; optionTbl++, i++) {
+ if (i > MAXOPTIONS - 1) {
+ /* option table too long */
+ assert(0);
+ }
+ intLongOpt[i].name = optionTbl->name;
+ intLongOpt[i].has_arg = optionTbl->has_arg;
+ intLongOpt[i].flag = NULL;
+ intLongOpt[i].val = optionTbl->val;
+ }
+
+ /* set option table global */
+ _longOptions = &intLongOpt[0];
+
+
+ /*
+ * Check for help/version request immediately following command
+ * '+' in option string ensures POSIX compliance in getopt_long()
+ * which means that processing will stop at first non-option
+ * argument.
+ */
+ while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions,
+ NULL)) != EOF) {
+ switch (opt) {
+ case '?':
+ /*
+ * getopt can return a '?' when no
+ * option letters match string. Check for
+ * the 'real' '?' in optopt.
+ */
+ if (optopt == '?') {
+ usage(DETAIL_USAGE);
+ exit(0);
+ } else {
+ usage(GENERAL_USAGE);
+ return (1);
+ }
+ break;
+ case 'V':
+ (void) fprintf(stdout, "%s: %s %s\n",
+ commandName, gettext("Version"),
+ versionString);
+ exit(0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * subcommand is always in the second argument. If there is no
+ * recognized subcommand in the second argument, print error,
+ * general usage and then return.
+ */
+ if (getSubcommandProps(argv[1], &subcommand) != 0) {
+ (void) printf("%s: %s\n", commandName,
+ gettext("invalid subcommand"));
+ usage(GENERAL_USAGE);
+ return (1);
+ }
+
+ getoptargv = argv;
+ getoptargv++;
+ getoptargc = argc;
+ getoptargc -= 1;
+
+ (void) memset(optionStringAll, 0, sizeof (optionStringAll));
+ (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions));
+
+ j = 0;
+ /*
+ * Build optionStringAll from long options table
+ */
+ for (lp = _longOptions; lp->name; lp++, j++) {
+ /* sanity check on string length */
+ if (j + 1 >= sizeof (optionStringAll)) {
+ /* option table too long */
+ assert(0);
+ }
+ optionStringAll[j] = lp->val;
+ if (lp->has_arg == required_argument) {
+ optionStringAll[++j] = ':';
+ }
+ }
+
+ i = 0;
+ /*
+ * Run getopt for all arguments against all possible options
+ * Store all options/option arguments in an array for retrieval
+ * later.
+ *
+ * Once all options are retrieved, a validity check against
+ * subcommand table is performed.
+ */
+ while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll,
+ _longOptions, NULL)) != EOF) {
+ switch (opt) {
+ case '?':
+ subUsage(DETAIL_USAGE, subcommand);
+ /*
+ * getopt can return a '?' when no
+ * option letters match string. Check for
+ * the 'real' '?' in optopt.
+ */
+ if (optopt == '?') {
+ exit(0);
+ } else {
+ exit(1);
+ }
+ default:
+ cmdOptions[i].optval = opt;
+ if (optarg) {
+ len = strlen(optarg);
+ if (len > sizeof (cmdOptions[i].optarg)
+ - 1) {
+ (void) printf("%s: %s\n",
+ commandName,
+ gettext("option too long"));
+ errno = EINVAL;
+ return (-1);
+ }
+ (void) strncpy(cmdOptions[i].optarg,
+ optarg, len);
+ }
+ i++;
+ break;
+ }
+ }
+
+ /*
+ * increment past last option
+ */
+ operInd = optind + 1;
+
+ /*
+ * Check validity of given options, if any were given
+ */
+
+ /* get option string for this subcommand */
+ availOptions = subcommand->optionString;
+
+ /* Get count of required options */
+ if (subcommand->required) {
+ requiredOptionCnt = strlen(subcommand->required);
+ }
+
+ if (cmdOptions[0].optval != 0) { /* options were input */
+ if (availOptions == NULL) { /* no options permitted */
+ (void) printf("%s: %s\n", commandName,
+ gettext("no options permitted"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+ for (i = 0; cmdOptions[i].optval; i++) {
+ /* is the option in the available option string? */
+ if (!(strchr(availOptions, cmdOptions[i].optval))) {
+ (void) printf("%s: '-%c': %s\n", commandName,
+ cmdOptions[i].optval,
+ gettext("invalid option"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ /* increment required options entered */
+ } else if (subcommand->required &&
+ (strchr(subcommand->required,
+ cmdOptions[i].optval))) {
+ requiredOptionEntered++;
+ /* Check for exclusive options */
+ } else if (cmdOptions[1].optval != 0 &&
+ subcommand->exclusive &&
+ strchr(subcommand->exclusive,
+ cmdOptions[i].optval)) {
+ (void) printf("%s: '-%c': %s\n",
+ commandName, cmdOptions[i].optval,
+ gettext("is an exclusive option"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+ }
+ } else { /* no options were input */
+ if (availOptions != NULL && subcommand->required) {
+ (void) printf("%s: %s\n", commandName,
+ gettext("at least one option required"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+ }
+
+ /* Were all required options entered? */
+ if (requiredOptionEntered != requiredOptionCnt) {
+ (void) printf("%s: %s: %s\n", commandName,
+ gettext("Following option(s) required"),
+ subcommand->required);
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+
+ /*
+ * If there are no operands,
+ * check to see if this is okay
+ */
+ if ((operInd == argc) &&
+ (subcommand->operand & OPERAND_MANDATORY)) {
+ (void) printf("%s: %s %s\n", commandName, subcommand->name,
+ gettext("requires an operand"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+ /*
+ * If there are more operands,
+ * check to see if this is okay
+ */
+ if ((argc > operInd) &&
+ (subcommand->operand & OPERAND_NONE)) {
+ (void) fprintf(stderr, "%s: %s %s\n", commandName,
+ subcommand->name, gettext("takes no operands"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+ /*
+ * If there is more than one more operand,
+ * check to see if this is okay
+ */
+ if ((argc > operInd) && ((argc - operInd) != 1) &&
+ (subcommand->operand & OPERAND_SINGLE)) {
+ (void) printf("%s: %s %s\n", commandName,
+ subcommand->name, gettext("accepts only a single operand"));
+ subUsage(DETAIL_USAGE, subcommand);
+ return (1);
+ }
+
+ /* Finished syntax checks */
+
+
+ /* Call appropriate function */
+ *funcRet = subcommand->handler(argc - operInd, &argv[operInd],
+ &cmdOptions[0], callArgs);
+
+ return (0);
+}
diff --git a/usr/src/common/cmdparse/cmdparse.h b/usr/src/common/cmdparse/cmdparse.h
new file mode 100644
index 0000000..47dab55
--- /dev/null
+++ b/usr/src/common/cmdparse/cmdparse.h
@@ -0,0 +1,222 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CMDPARSE_H
+#define _CMDPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <getopt.h>
+
+#define SUBCOMMAND_BASE 1
+
+/* bit defines for operand macros */
+#define OPERAND_SINGLE 0x2
+#define OPERAND_MULTIPLE 0x4
+#define OPERAND_MANDATORY 0x8
+#define OPERAND_OPTIONAL 0x10
+
+/* maximum length of an option argument */
+#define MAXOPTARGLEN 512
+
+
+/* Following are used to express operand requirements */
+#define OPERAND_NONE 0x1
+#define OPERAND_MANDATORY_SINGLE (OPERAND_MANDATORY | OPERAND_SINGLE)
+#define OPERAND_OPTIONAL_SINGLE (OPERAND_OPTIONAL | OPERAND_SINGLE)
+#define OPERAND_MANDATORY_MULTIPLE (OPERAND_MANDATORY | OPERAND_MULTIPLE)
+#define OPERAND_OPTIONAL_MULTIPLE (OPERAND_OPTIONAL | OPERAND_MULTIPLE)
+
+/* subcommands must have a single bit on and must have exclusive values */
+#define SUBCOMMAND(x) (SUBCOMMAND_BASE << x)
+
+/*
+ * This structure is passed into the caller's callback function and
+ * will contain a list of all options entered and their associated
+ * option arguments if applicable
+ */
+typedef struct _cmdOptions {
+ int optval;
+ char optarg[MAXOPTARGLEN + 1];
+} cmdOptions_t;
+
+/*
+ * subcommand callback function
+ *
+ * argc - number of arguments in argv
+ * argv - operand arguments
+ * options - options entered on command line
+ * callData - pointer to caller data to be passed to subcommand function
+ */
+typedef int (*handler_t)(int argc, char *argv[], cmdOptions_t *options,
+ void *callData);
+
+/*
+ * list of subcommands and associated properties
+ *
+ * name -> subcommand name
+ * handler -> function to call on successful syntax check
+ * optionString -> short options that are valid
+ * required -> Does it require at least one option?
+ * exclusive -> short options that are required to be exclusively entered
+ * operand -> Type of operand input. Can be:
+ *
+ * NO_OPERAND
+ * OPERAND_MANDATORY_SINGLE
+ * OPERAND_OPTIONAL_SINGLE
+ * OPERAND_MANDATORY_MULTIPLE
+ * OPERAND_OPTIONAL_MULTIPLE
+ *
+ * operandDefinition -> char * definition of the operand
+ *
+ * The long options table specifies whether an option argument is required.
+ *
+ *
+ * EXAMPLE:
+ *
+ * Based on "list-target" entry below:
+ *
+ * "list-target" is expected as the subcommand input
+ * listTarget is the function to be called on success
+ * "list-target" accepts -i, -s, -t and -l
+ * "list-target" requires the option 'i'.
+ * "list-target" has no exclusive options
+ * "list-target" may have one or more operands
+ * "list-target" operand description is "target-name"
+ *
+ *
+ * optionRules_t optionRules[] = {
+ * {"list-target", listTarget, "istl", "i", NULL,
+ * OPERAND_OPTIONAL_MULTIPLE, "target-name"},
+ * {"modify-target", modifyTarget, "t", "t", NULL,
+ * OPERAND_MANDATORY_MULTIPLE, "target-name"},
+ * {"enable", enable, NULL, NULL, NULL, NO_OPERAND, NULL},
+ * {NULL, 0, 0, NULL, 0, NULL}
+ * };
+ */
+typedef struct _subCommandProps {
+ char *name;
+ handler_t handler;
+ char *optionString;
+ char *required;
+ char *exclusive;
+ int operand;
+ char *operandDefinition;
+ char *helpText;
+ uint8_t reserved[60];
+} subCommandProps_t;
+
+
+
+#define required_arg required_argument
+#define no_arg no_argument
+
+/*
+ * Add short options and long options here
+ *
+ * name -> long option name
+ * has_arg -> required_arg, no_arg
+ * val -> short option character
+ * argDesc -> description of option argument
+ *
+ * Note: This structure may not be used if your CLI has no
+ * options. However, -?, --help and -V, --version will still be supported
+ * as they are standard for every CLI.
+ *
+ * EXAMPLE:
+ *
+ * optionTbl_t options[] = {
+ * {"filename", arg_required, 'f', "out-filename"},
+ * {NULL, 0, 0}
+ * };
+ *
+ */
+typedef struct _optionTbl {
+ char *name;
+ int has_arg;
+ int val;
+ char *argDesc;
+} optionTbl_t;
+
+/*
+ * After tables are set, assign them to this structure
+ * for passing into cmdparse()
+ */
+typedef struct _synTables {
+ char *versionString;
+ optionTbl_t *longOptionTbl;
+ subCommandProps_t *subCommandPropsTbl;
+} synTables_t;
+
+/*
+ * cmdParse is a parser that checks syntax of the input command against
+ * rules and property tables.
+ *
+ * When syntax is successfully validated, the function associated with the
+ * subcommand is called using the subcommands table functions.
+ *
+ * Syntax for the command is as follows:
+ *
+ * command [options] subcommand [<options>] [<operand ...>]
+ *
+ *
+ * There are two standard short and long options assumed:
+ * -?, --help Provides usage on a command or subcommand
+ * and stops further processing of the arguments
+ *
+ * -V, --version Provides version information on the command
+ * and stops further processing of the arguments
+ *
+ * These options are loaded by this function.
+ *
+ * input:
+ * argc, argv from main
+ * syntax rules tables (synTables_t structure)
+ * callArgs - void * passed by caller to be passed to subcommand function
+ *
+ * output:
+ * funcRet - pointer to int that holds subcommand function return value
+ *
+ * Returns:
+ *
+ * zero on successful syntax parse and function call
+ *
+ * 1 on unsuccessful syntax parse (no function has been called)
+ * This could be due to a version or help call or simply a
+ * general usage call.
+ *
+ * -1 check errno, call failed
+ *
+ */
+int cmdParse(int numOperands, char *operands[], synTables_t synTables,
+ void *callerArgs, int *funcRet);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CMDPARSE_H */
diff --git a/usr/src/lib/libstmf/common/libstmf.h b/usr/src/lib/libstmf/common/libstmf.h
new file mode 100644
index 0000000..f9d05ad
--- /dev/null
+++ b/usr/src/lib/libstmf/common/libstmf.h
@@ -0,0 +1,392 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _LIBSTMF_H
+#define _LIBSTMF_H
+
+#include <time.h>
+#include <sys/param.h>
+#include <libnvpair.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Constants and Types */
+
+/* LU and Local Port states */
+#define STMF_LOGICAL_UNIT_OFFLINE 0
+#define STMF_LOGICAL_UNIT_OFFLINING 1
+#define STMF_LOGICAL_UNIT_ONLINE 2
+#define STMF_LOGICAL_UNIT_ONLINING 3
+#define STMF_LOGICAL_UNIT_UNREGISTERED 4
+#define STMF_TARGET_PORT_OFFLINE 5
+#define STMF_TARGET_PORT_OFFLINING 6
+#define STMF_TARGET_PORT_ONLINE 7
+#define STMF_TARGET_PORT_ONLINING 8
+#define STMF_SERVICE_STATE_ONLINE 9
+#define STMF_SERVICE_STATE_OFFLINE 10
+#define STMF_SERVICE_STATE_ONLINING 11
+#define STMF_SERVICE_STATE_OFFLINING 12
+#define STMF_SERVICE_STATE_UNKNOWN 13
+#define STMF_CONFIG_STATE_NONE 14
+#define STMF_CONFIG_STATE_INIT 15
+#define STMF_CONFIG_STATE_INIT_DONE 16
+#define STMF_CONFIG_STATE_UNKNOWN 17
+#define STMF_DEFAULT_LU_STATE 18
+#define STMF_DEFAULT_TARGET_PORT_STATE 19
+
+#define STMF_IDENT_LENGTH 255
+
+/* API status return values */
+#define STMF_STATUS_SUCCESS 0x0000
+#define STMF_STATUS_ERROR 0x8000
+#define STMF_ERROR_BUSY (STMF_STATUS_ERROR | 0x01)
+#define STMF_ERROR_NOT_FOUND (STMF_STATUS_ERROR | 0x02)
+#define STMF_ERROR_MEMBER_NOT_FOUND (STMF_STATUS_ERROR | 0x03)
+#define STMF_ERROR_GROUP_NOT_FOUND (STMF_STATUS_ERROR | 0x04)
+#define STMF_ERROR_PERM (STMF_STATUS_ERROR | 0x05)
+#define STMF_ERROR_NOMEM (STMF_STATUS_ERROR | 0x06)
+#define STMF_ERROR_INVALID_ARG (STMF_STATUS_ERROR | 0x07)
+#define STMF_ERROR_EXISTS (STMF_STATUS_ERROR | 0x08)
+#define STMF_ERROR_SERVICE_NOT_FOUND (STMF_STATUS_ERROR | 0x09)
+#define STMF_ERROR_SERVICE_ONLINE (STMF_STATUS_ERROR | 0x0a)
+#define STMF_ERROR_SERVICE_OFFLINE (STMF_STATUS_ERROR | 0x0b)
+#define STMF_ERROR_GROUP_IN_USE (STMF_STATUS_ERROR | 0x0c)
+#define STMF_ERROR_LUN_IN_USE (STMF_STATUS_ERROR | 0x0d)
+#define STMF_ERROR_VE_CONFLICT (STMF_STATUS_ERROR | 0x0e)
+#define STMF_ERROR_CONFIG_NONE (STMF_STATUS_ERROR | 0x0f)
+#define STMF_ERROR_SERVICE_DATA_VERSION (STMF_STATUS_ERROR | 0x10)
+#define STMF_ERROR_INVALID_HG (STMF_STATUS_ERROR | 0x11)
+#define STMF_ERROR_INVALID_TG (STMF_STATUS_ERROR | 0x12)
+#define STMF_ERROR_PROV_DATA_STALE (STMF_STATUS_ERROR | 0x13)
+#define STMF_ERROR_NO_PROP (STMF_STATUS_ERROR | 0x14)
+#define STMF_ERROR_NO_PROP_VAL (STMF_STATUS_ERROR | 0x15)
+#define STMF_ERROR_MISSING_PROP_VAL (STMF_STATUS_ERROR | 0x16)
+#define STMF_ERROR_INVALID_BLOCKSIZE (STMF_STATUS_ERROR | 0x17)
+#define STMF_ERROR_FILE_ALREADY (STMF_STATUS_ERROR | 0x18)
+#define STMF_ERROR_INVALID_PROPSIZE (STMF_STATUS_ERROR | 0x19)
+#define STMF_ERROR_INVALID_PROP (STMF_STATUS_ERROR | 0x20)
+#define STMF_ERROR_PERSIST_TYPE (STMF_STATUS_ERROR | 0x21)
+#define STMF_ERROR_TG_ONLINE (STMF_STATUS_ERROR | 0x22)
+#define STMF_ERROR_ACCESS_STATE_SET (STMF_STATUS_ERROR | 0x23)
+#define STMF_ERROR_NO_PROP_STANDBY (STMF_STATUS_ERROR | 0x24)
+#define STMF_ERROR_POST_MSG_FAILED (STMF_STATUS_ERROR | 0x25)
+#define STMF_ERROR_DOOR_INSTALLED (STMF_STATUS_ERROR | 0x26)
+
+/* Failures for stmfCreateLu */
+#define STMF_ERROR_FILE_IN_USE (STMF_STATUS_ERROR | 0x100)
+#define STMF_ERROR_INVALID_BLKSIZE (STMF_STATUS_ERROR | 0x101)
+#define STMF_ERROR_GUID_IN_USE (STMF_STATUS_ERROR | 0x102)
+#define STMF_ERROR_META_FILE_NAME (STMF_STATUS_ERROR | 0x103)
+#define STMF_ERROR_DATA_FILE_NAME (STMF_STATUS_ERROR | 0x104)
+#define STMF_ERROR_SIZE_OUT_OF_RANGE (STMF_STATUS_ERROR | 0x105)
+#define STMF_ERROR_LU_BUSY (STMF_STATUS_ERROR | 0x106)
+#define STMF_ERROR_META_CREATION (STMF_STATUS_ERROR | 0x107)
+#define STMF_ERROR_FILE_SIZE_INVALID (STMF_STATUS_ERROR | 0x108)
+#define STMF_ERROR_WRITE_CACHE_SET (STMF_STATUS_ERROR | 0x109)
+
+/* Initiator Name Types */
+#define STMF_FC_PORT_WWN 1
+#define STMF_ISCSI_NAME 2
+
+
+/* provider types */
+#define STMF_LU_PROVIDER_TYPE 1
+#define STMF_PORT_PROVIDER_TYPE 2
+
+/* LU Resource types */
+#define STMF_DISK 0
+
+/* Persistence methods */
+#define STMF_PERSIST_SMF 1
+#define STMF_PERSIST_NONE 2
+
+/* Logical unit access states */
+#define STMF_ACCESS_ACTIVE "0"
+#define STMF_ACCESS_ACTIVE_TO_STANDBY "1"
+#define STMF_ACCESS_STANDBY "2"
+#define STMF_ACCESS_STANDBY_TO_ACTIVE "3"
+
+/*
+ * LU Disk Properties
+ */
+
+enum {
+ STMF_LU_PROP_ALIAS = 1,
+ STMF_LU_PROP_BLOCK_SIZE,
+ STMF_LU_PROP_COMPANY_ID,
+ STMF_LU_PROP_FILENAME,
+ STMF_LU_PROP_GUID,
+ STMF_LU_PROP_META_FILENAME,
+ STMF_LU_PROP_MGMT_URL,
+ STMF_LU_PROP_NEW,
+ STMF_LU_PROP_SIZE,
+ STMF_LU_PROP_WRITE_PROTECT,
+ STMF_LU_PROP_WRITE_CACHE_DISABLE,
+ STMF_LU_PROP_VID,
+ STMF_LU_PROP_PID,
+ STMF_LU_PROP_SERIAL_NUM,
+ STMF_LU_PROP_ACCESS_STATE,
+ STMF_LU_PROP_HOST_ID
+};
+
+
+/* devid code set and name types */
+#define EUI_64_TYPE 2
+#define NAA_TYPE 3
+#define SCSI_NAME_TYPE 8
+
+#define BINARY_CODE_SET 1
+#define ASCII_CODE_SET 2
+#define UTF_8_CODE_SET 3
+
+typedef enum _stmfProtocol
+{
+ STMF_PROTOCOL_FIBRE_CHANNEL = 0,
+ STMF_PROTOCOL_SCSI = 1,
+ STMF_PROTOCOL_SSA = 2,
+ STMF_PROTOCOL_IEEE_1394 = 3,
+ STMF_PROTOCOL_SRP = 4,
+ STMF_PROTOCOL_ISCSI = 5,
+ STMF_PROTOCOL_SAS = 6
+} stmfProtocol;
+
+
+typedef struct _stmfGuid
+{
+ uchar_t guid[16];
+} stmfGuid;
+
+typedef struct _stmfGuidList
+{
+ uint32_t cnt;
+ stmfGuid guid[1];
+} stmfGuidList;
+
+typedef struct _stmfState
+{
+ int operationalState;
+ int configState;
+} stmfState;
+
+typedef struct _stmfDevid
+{
+ uint8_t identLength; /* length of ident */
+ uint8_t ident[STMF_IDENT_LENGTH]; /* SCSI name string ident */
+} stmfDevid;
+
+typedef struct _stmfDevidList
+{
+ uint32_t cnt;
+ stmfDevid devid[1];
+} stmfDevidList;
+
+typedef char stmfGroupName[256];
+typedef char stmfProviderName[256];
+
+typedef struct _stmfGroupList
+{
+ uint32_t cnt;
+ stmfGroupName name[1];
+} stmfGroupList;
+
+typedef struct _stmfProvider
+{
+ int providerType;
+ stmfProviderName name;
+} stmfProvider;
+
+typedef struct _stmfProviderList
+{
+ uint32_t cnt;
+ stmfProvider provider[1];
+} stmfProviderList;
+
+typedef struct _stmfSession
+{
+ stmfDevid initiator;
+ char alias[256];
+ time_t creationTime;
+} stmfSession;
+
+typedef struct _stmfSessionList
+{
+ uint32_t cnt;
+ stmfSession session[1];
+} stmfSessionList;
+
+
+typedef struct _stmfViewEntry
+{
+ boolean_t veIndexValid; /* if B_TRUE, veIndex is valid value */
+ uint32_t veIndex; /* View Entry index */
+ boolean_t allHosts; /* all initiator ports */
+ stmfGroupName hostGroup; /* Host Group Name */
+ boolean_t allTargets; /* B_TRUE = targetGroup is invalid */
+ stmfGroupName targetGroup; /* Target Group Name */
+ boolean_t luNbrValid; /* if B_TRUE, luNbr is a valid value */
+ uchar_t luNbr[8]; /* LU number for this view entry */
+} stmfViewEntry;
+
+typedef struct _stmfViewEntryList
+{
+ uint32_t cnt;
+ stmfViewEntry ve[1];
+} stmfViewEntryList;
+
+typedef struct _stmfViewEntryProperties
+{
+ stmfGuid associatedLogicalUnitGuid;
+ stmfViewEntry viewEntry;
+} stmfViewEntryProperties;
+
+typedef struct _stmfGroupProperties
+{
+ uint32_t cnt;
+ stmfDevid name[1];
+} stmfGroupProperties;
+
+typedef struct _stmfTargetProperties
+{
+ stmfProviderName providerName;
+ char alias[256];
+ uint16_t status;
+ stmfProtocol protocol;
+ stmfDevid devid;
+} stmfTargetProperties;
+
+typedef struct _stmfLogicalUnitProperties
+{
+ char alias[256];
+ uchar_t vendor[8];
+ uchar_t product[16];
+ uchar_t revision[4];
+ uint32_t status;
+ char providerName[256];
+ stmfGuid luid;
+} stmfLogicalUnitProperties;
+
+typedef void * luResource;
+
+typedef struct _stmfLogicalUnitProviderProperties
+{
+ char providerName[MAXPATHLEN];
+ uint32_t instance;
+ uint32_t status;
+ uchar_t rsvd[64];
+} stmfLogicalUnitProviderProperties;
+
+typedef struct _stmfLocalPortProviderProperties
+{
+ char providerName[MAXPATHLEN];
+ uint32_t instance;
+ uint32_t status;
+ uchar_t rsvd[64];
+} stmfLocalPortProviderProperties;
+
+/* API prototypes */
+int stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *name);
+int stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName);
+int stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry);
+int stmfClearProviderData(char *providerName, int providerType);
+int stmfCreateHostGroup(stmfGroupName *hostGroupName);
+int stmfCreateLu(luResource hdl, stmfGuid *luGuid);
+int stmfCreateLuResource(uint16_t dType, luResource *hdl);
+int stmfCreateTargetGroup(stmfGroupName *targetGroupName);
+int stmfDeleteHostGroup(stmfGroupName *hostGroupName);
+int stmfDeleteLu(stmfGuid *luGuid);
+int stmfDeleteTargetGroup(stmfGroupName *targetGroupName);
+void stmfDestroyProxyDoor(int hdl);
+int stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid);
+int stmfDevidFromWwn(uchar_t wwn[8], stmfDevid *devid);
+int stmfFreeLuResource(luResource hdl);
+void stmfFreeMemory(void *);
+int stmfGetAluaState(boolean_t *enabled, uint32_t *node);
+int stmfGetGlobalLuProp(uint16_t dType, uint32_t prop, char *propVal,
+ size_t *propLen);
+int stmfGetHostGroupList(stmfGroupList **initiatorGroupList);
+int stmfGetHostGroupMembers(stmfGroupName *hostGroupName,
+ stmfGroupProperties **groupProperties);
+int stmfGetLocalPortProviderList(stmfProviderList **localPortProviderList);
+int stmfGetLocalPortProviderProperties(stmfProviderName *providerName,
+ stmfLocalPortProviderProperties *providerProperties);
+int stmfGetLogicalUnitList(stmfGuidList **logicalUnitList);
+int stmfGetLogicalUnitProperties(stmfGuid *logicalUnit,
+ stmfLogicalUnitProperties *logicalUnitProps);
+int stmfGetLogicalUnitProviderList(stmfProviderList **logicalUnitProviderList);
+int stmfGetLogicalUnitProviderProperties(stmfProviderName *providerName,
+ stmfLogicalUnitProviderProperties *providerProperties);
+int stmfGetLuProp(luResource hdl, uint32_t propType, char *prop,
+ size_t *propLen);
+int stmfGetLuResource(stmfGuid *luGuid, luResource *hdl);
+int stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState);
+int stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType);
+int stmfGetProviderDataProt(char *providerName, nvlist_t **nvl,
+ int providerType, uint64_t *setToken);
+int stmfGetSessionList(stmfDevid *target, stmfSessionList **sessionList);
+int stmfGetState(stmfState *);
+int stmfGetTargetGroupList(stmfGroupList **targetGroupList);
+int stmfGetTargetGroupMembers(stmfGroupName *targetGroupName,
+ stmfGroupProperties **groupProperties);
+int stmfGetTargetList(stmfDevidList **targetList);
+int stmfGetTargetProperties(stmfDevid *target,
+ stmfTargetProperties *targetProps);
+int stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList);
+int stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid);
+int stmfInitProxyDoor(int *hdl, int fd);
+int stmfLoadConfig(void);
+int stmfLuStandby(stmfGuid *luGuid);
+int stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal);
+int stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
+ const char *propVal);
+int stmfOffline(void);
+int stmfOfflineTarget(stmfDevid *devid);
+int stmfOfflineLogicalUnit(stmfGuid *logicalUnit);
+int stmfOnline(void);
+int stmfOnlineTarget(stmfDevid *devid);
+int stmfOnlineLogicalUnit(stmfGuid *logicalUnit);
+int stmfPostProxyMsg(int hdl, void *buf, uint32_t buflen);
+int stmfRemoveFromHostGroup(stmfGroupName *hostGroupName,
+ stmfDevid *initiatorName);
+int stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName,
+ stmfDevid *targetName);
+int stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex);
+int stmfSetAluaState(boolean_t enabled, uint32_t node);
+int stmfSetGlobalLuProp(uint16_t dType, uint32_t propType, const char *propVal);
+int stmfSetLuProp(luResource hdl, uint32_t propType, const char *propVal);
+int stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet);
+int stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType);
+int stmfSetProviderDataProt(char *providerName, nvlist_t *nvl,
+ int providerType, uint64_t *setToken);
+int stmfValidateView(stmfViewEntry *viewEntry);
+int stmfSetStmfProp(uint8_t propType, char *propVal);
+int stmfGetStmfProp(uint8_t propType, char *propVal, size_t *propLen);
+int stmfLoadStmfProps(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSTMF_H */
diff --git a/usr/src/lib/libstmf/common/libstmf_impl.h b/usr/src/lib/libstmf/common/libstmf_impl.h
new file mode 100644
index 0000000..ec02fcd
--- /dev/null
+++ b/usr/src/lib/libstmf/common/libstmf_impl.h
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSTMF_IMPL_H
+#define _LIBSTMF_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libstmf.h>
+
+typedef struct _luResourceImpl {
+ uint16_t type;
+ void *resource;
+} luResourceImpl;
+
+
+typedef struct _diskResource {
+ boolean_t luDataFileNameValid;
+ char luDataFileName[MAXPATHLEN];
+ boolean_t luMetaFileNameValid;
+ char luMetaFileName[MAXPATHLEN];
+ boolean_t luSizeValid;
+ uint64_t luSize;
+ boolean_t blkSizeValid;
+ uint16_t blkSize;
+ boolean_t luGuidValid;
+ uint8_t luGuid[16];
+ boolean_t serialNumValid;
+ char serialNum[253];
+ boolean_t companyIdValid;
+ uint32_t companyId;
+ boolean_t luAliasValid;
+ char luAlias[256];
+ boolean_t luMgmtUrlValid;
+ char luMgmtUrl[1024];
+ boolean_t vidValid;
+ char vid[8];
+ boolean_t pidValid;
+ char pid[16];
+ boolean_t revValid;
+ char rev[4];
+ boolean_t writeProtectEnableValid;
+ boolean_t writeProtectEnable;
+ boolean_t writebackCacheDisableValid;
+ boolean_t writebackCacheDisable;
+ uint16_t accessState;
+ uint32_t hostId;
+ boolean_t hostIdValid;
+} diskResource;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSTMF_IMPL_H */
diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c
new file mode 100644
index 0000000..e12c189
--- /dev/null
+++ b/usr/src/lib/libstmf/common/stmf.c
@@ -0,0 +1,6949 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <libnvpair.h>
+#include <pthread.h>
+#include <syslog.h>
+#include <libstmf.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <store.h>
+#include <locale.h>
+#include <math.h>
+#include <libstmf_impl.h>
+#include <sys/stmf_ioctl.h>
+#include <sys/stmf_sbd_ioctl.h>
+#include <sys/pppt_ioctl.h>
+#include <macros.h>
+
+#define STMF_PATH "/devices/pseudo/stmf@0:admin"
+#define SBD_PATH "/devices/pseudo/stmf_sbd@0:admin"
+#define PPPT_PATH "/devices/pseudo/pppt@0:pppt"
+
+#define EUI "eui."
+#define WWN "wwn."
+#define IQN "iqn."
+#define LU_ASCII_GUID_SIZE 32
+#define LU_GUID_SIZE 16
+#define OUI_ASCII_SIZE 6
+#define HOST_ID_ASCII_SIZE 8
+#define OUI_SIZE 3
+#define HOST_ID_SIZE 4
+#define IDENT_LENGTH_BYTE 3
+
+/* various initial allocation values */
+#define ALLOC_LU 8192
+#define ALLOC_TARGET_PORT 2048
+#define ALLOC_PROVIDER 64
+#define ALLOC_GROUP 2048
+#define ALLOC_SESSION 2048
+#define ALLOC_VE 256
+#define ALLOC_PP_DATA_SIZE 128*1024
+#define ALLOC_GRP_MEMBER 256
+
+#define MAX_ISCSI_NAME 223
+#define MAX_SERIAL_SIZE 252 + 1
+#define MAX_LU_ALIAS_SIZE 256
+#define MAX_SBD_PROPS MAXPATHLEN + MAX_SERIAL_SIZE + MAX_LU_ALIAS_SIZE
+
+#define OPEN_STMF 0
+#define OPEN_EXCL_STMF O_EXCL
+
+#define OPEN_SBD 0
+#define OPEN_EXCL_SBD O_EXCL
+
+#define OPEN_PPPT 0
+#define OPEN_EXCL_PPPT O_EXCL
+
+#define LOGICAL_UNIT_TYPE 0
+#define TARGET_TYPE 1
+#define STMF_SERVICE_TYPE 2
+
+#define HOST_GROUP 1
+#define TARGET_GROUP 2
+
+/* set default persistence here */
+#define STMF_DEFAULT_PERSIST STMF_PERSIST_SMF
+
+#define MAX_PROVIDER_RETRY 30
+
+static int openStmf(int, int *fd);
+static int openSbd(int, int *fd);
+static int openPppt(int, int *fd);
+static int groupIoctl(int fd, int cmd, stmfGroupName *);
+static int loadStore(int fd);
+static int initializeConfig();
+static int groupMemberIoctl(int fd, int cmd, stmfGroupName *, stmfDevid *);
+static int guidCompare(const void *, const void *);
+static int addViewEntryIoctl(int fd, stmfGuid *, stmfViewEntry *);
+static int loadHostGroups(int fd, stmfGroupList *);
+static int loadTargetGroups(int fd, stmfGroupList *);
+static int getStmfState(stmf_state_desc_t *);
+static int setStmfState(int fd, stmf_state_desc_t *, int);
+static int setProviderData(int fd, char *, nvlist_t *, int, uint64_t *);
+static int createDiskResource(luResourceImpl *);
+static int createDiskLu(diskResource *, stmfGuid *);
+static int deleteDiskLu(stmfGuid *luGuid);
+static int getDiskProp(luResourceImpl *, uint32_t, char *, size_t *);
+static int getDiskAllProps(stmfGuid *luGuid, luResource *hdl);
+static int loadDiskPropsFromDriver(luResourceImpl *, sbd_lu_props_t *);
+static int removeGuidFromDiskStore(stmfGuid *);
+static int addGuidToDiskStore(stmfGuid *, char *);
+static int persistDiskGuid(stmfGuid *, char *, boolean_t);
+static int setDiskProp(luResourceImpl *, uint32_t, const char *);
+static int getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen);
+static int checkHexUpper(char *);
+static int strToShift(const char *);
+static int niceStrToNum(const char *, uint64_t *);
+static void diskError(uint32_t, int *);
+static int importDiskLu(char *fname, stmfGuid *);
+static int modifyDiskLu(diskResource *, stmfGuid *, const char *);
+static int modifyDiskLuProp(stmfGuid *, const char *, uint32_t, const char *);
+static int validateModifyDiskProp(uint32_t);
+static uint8_t iGetPersistMethod();
+static int groupListIoctl(stmfGroupList **, int);
+static int iLoadGroupFromPs(stmfGroupList **, int);
+static int groupMemberListIoctl(stmfGroupName *, stmfGroupProperties **, int);
+static int getProviderData(char *, nvlist_t **, int, uint64_t *);
+static int setDiskStandby(stmfGuid *luGuid);
+static int setDiskGlobalProp(uint32_t, const char *);
+static int viewEntryCompare(const void *, const void *);
+static void deleteNonActiveLus();
+static int loadStmfProp(int fd);
+
+static pthread_mutex_t persistenceTypeLock = PTHREAD_MUTEX_INITIALIZER;
+static int iPersistType = 0;
+/* when B_TRUE, no need to access SMF anymore. Just use iPersistType */
+static boolean_t iLibSetPersist = B_FALSE;
+
+/*
+ * Open for stmf module
+ *
+ * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openStmf(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(STMF_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else if (errno == EACCES) {
+ ret = STMF_ERROR_PERM;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openStmf:open failure:%s:errno(%d)",
+ STMF_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * Open for sbd module
+ *
+ * flag - open flag (OPEN_SBD, OPEN_EXCL_SBD)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openSbd(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(SBD_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else if (errno == EACCES) {
+ ret = STMF_ERROR_PERM;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openSbd:open failure:%s:errno(%d)",
+ SBD_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * Open for pppt module
+ *
+ * flag - open flag (OPEN_PPPT, OPEN_EXCL_PPPT)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openPppt(int flag, int *fd)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if ((*fd = open(PPPT_PATH, O_RDONLY | flag)) != -1) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ if (errno == EBUSY) {
+ ret = STMF_ERROR_BUSY;
+ } else if (errno == EACCES) {
+ ret = STMF_ERROR_PERM;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ syslog(LOG_DEBUG, "openPppt:open failure:%s:errno(%d)",
+ PPPT_PATH, errno);
+ }
+
+ return (ret);
+}
+
+/*
+ * initializeConfig
+ *
+ * This routine should be called before any ioctl requiring initialization
+ * which is basically everything except stmfGetState(), setStmfState() and
+ * stmfLoadConfig().
+ */
+static int
+initializeConfig()
+{
+ int ret;
+ stmfState state;
+
+
+ ret = stmfGetState(&state);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /* if we've already initialized or in the process, return success */
+ if (state.configState == STMF_CONFIG_STATE_INIT_DONE ||
+ state.configState == STMF_CONFIG_STATE_INIT) {
+ return (STMF_STATUS_SUCCESS);
+ }
+
+ ret = stmfLoadConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "initializeConfig:stmfLoadConfig:error(%d)", ret);
+ return (ret);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "initializeConfig:stmfGetState:error(%d)", ret);
+ return (ret);
+ }
+
+ if (state.configState != STMF_CONFIG_STATE_INIT_DONE) {
+ syslog(LOG_DEBUG, "initializeConfig:state.configState(%d)",
+ state.configState);
+ ret = STMF_STATUS_ERROR;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * groupIoctl
+ *
+ * Purpose: issue ioctl for create/delete on group
+ *
+ * cmd - valid STMF ioctl group cmd
+ * groupName - groupName to create or delete
+ */
+static int
+groupIoctl(int fd, int cmd, stmfGroupName *groupName)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_group_name_t iGroupName;
+
+ bzero(&iGroupName, sizeof (iGroupName));
+
+ bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
+
+ iGroupName.name_size = strlen((char *)groupName);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to create the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (iGroupName);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_EXISTS:
+ case STMF_IOCERR_HG_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_IOCERR_TG_IN_USE:
+ case STMF_IOCERR_HG_IN_USE:
+ ret = STMF_ERROR_GROUP_IN_USE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupIoctl:error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * groupMemberIoctl
+ *
+ * Purpose: issue ioctl for add/remove member on group
+ *
+ * cmd - valid STMF ioctl group member cmd
+ * groupName - groupName to add to or remove from
+ * devid - group member to add or remove
+ */
+static int
+groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_group_op_data_t stmfGroupData;
+
+ bzero(&stmfGroupData, sizeof (stmfGroupData));
+
+ bcopy(groupName, &stmfGroupData.group.name, strlen((char *)groupName));
+
+ stmfGroupData.group.name_size = strlen((char *)groupName);
+ stmfGroupData.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &stmfGroupData.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGroupData);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&stmfGroupData;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_NEED_TG_OFFLINE:
+ ret = STMF_ERROR_TG_ONLINE;
+ break;
+ default:
+ ret = STMF_ERROR_BUSY;
+ break;
+ }
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_TG_ENTRY_EXISTS:
+ case STMF_IOCERR_HG_ENTRY_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_IOCERR_INVALID_TG_ENTRY:
+ case STMF_IOCERR_INVALID_HG_ENTRY:
+ ret =
+ STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ case STMF_IOCERR_INVALID_HG:
+ ret =
+ STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupMemberIoctl:error"
+ "(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+
+/*
+ * qsort function
+ * sort on veIndex
+ */
+static int
+viewEntryCompare(const void *p1, const void *p2)
+{
+
+ stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
+ if (v1->veIndex > v2->veIndex)
+ return (1);
+ if (v1->veIndex < v2->veIndex)
+ return (-1);
+ return (0);
+}
+
+/*
+ * guidCompare
+ *
+ * qsort function
+ * sort on guid
+ */
+static int
+guidCompare(const void *p1, const void *p2)
+{
+
+ stmfGuid *g1 = (stmfGuid *)p1, *g2 = (stmfGuid *)p2;
+ int i;
+
+ for (i = 0; i < sizeof (stmfGuid); i++) {
+ if (g1->guid[i] > g2->guid[i])
+ return (1);
+ if (g1->guid[i] < g2->guid[i])
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * stmfAddToHostGroup
+ *
+ * Purpose: Adds an initiator to an existing host group
+ *
+ * hostGroupName - name of an existing host group
+ * hostName - name of initiator to add
+ */
+int
+stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || hostName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY, hostGroupName,
+ hostName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psAddHostGroupMember((char *)hostGroupName,
+ (char *)hostName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddToHostGroup:psAddHostGroupMember:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfAddToTargetGroup
+ *
+ * Purpose: Adds a local port to an existing target group
+ *
+ * targetGroupName - name of an existing target group
+ * targetName - name of target to add
+ */
+int
+stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || targetName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
+ targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psAddTargetGroupMember((char *)targetGroupName,
+ (char *)targetName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddToTargetGroup:psAddTargetGroupMember:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * addViewEntryIoctl
+ *
+ * Purpose: Issues ioctl to add a view entry
+ *
+ * lu - Logical Unit identifier to which the view entry is added
+ * viewEntry - view entry to add
+ * init - When set to B_TRUE, we are in the init state, i.e. don't call open
+ */
+static int
+addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ /*
+ * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
+ * false on input
+ */
+ ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
+ ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
+ ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
+
+ if (viewEntry->allHosts == B_FALSE) {
+ bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_host_group.name_size =
+ strlen((char *)viewEntry->hostGroup);
+ }
+ if (viewEntry->allTargets == B_FALSE) {
+ bcopy(viewEntry->targetGroup,
+ &ioctlViewEntry.ve_target_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_target_group.name_size =
+ strlen((char *)viewEntry->targetGroup);
+ }
+ if (viewEntry->luNbrValid) {
+ bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_ADD_VIEW_ENTRY, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_LU_NUMBER_IN_USE:
+ ret = STMF_ERROR_LUN_IN_USE;
+ break;
+ case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
+ ret = STMF_ERROR_VE_CONFLICT;
+ break;
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ ret = STMF_ERROR_INVALID_HG;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_INVALID_TG;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "addViewEntryIoctl"
+ ":error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ goto done;
+ }
+
+ /* copy lu nbr back to caller's view entry on success */
+ viewEntry->veIndex = ioctlViewEntry.ve_ndx;
+ if (ioctlViewEntry.ve_lu_number_valid) {
+ bcopy(&ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ viewEntry->luNbrValid = B_TRUE;
+
+done:
+ return (ret);
+}
+
+/*
+ * stmfAddViewEntry
+ *
+ * Purpose: Adds a view entry to a logical unit
+ *
+ * lu - guid of the logical unit to which the view entry is added
+ * viewEntry - view entry structure to add
+ */
+int
+stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ int ret;
+ int fd;
+ stmfViewEntry iViewEntry;
+
+ if (lu == NULL || viewEntry == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* initialize and set internal view entry */
+ bzero(&iViewEntry, sizeof (iViewEntry));
+
+ if (!viewEntry->allHosts) {
+ bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
+ sizeof (iViewEntry.hostGroup));
+ } else {
+ iViewEntry.allHosts = B_TRUE;
+ }
+
+ if (!viewEntry->allTargets) {
+ bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
+ sizeof (iViewEntry.targetGroup));
+ } else {
+ iViewEntry.allTargets = B_TRUE;
+ }
+
+ if (viewEntry->luNbrValid) {
+ iViewEntry.luNbrValid = B_TRUE;
+ bcopy(viewEntry->luNbr, iViewEntry.luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ /*
+ * set users return view entry index valid flag to false
+ * in case of failure
+ */
+ viewEntry->veIndexValid = B_FALSE;
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * First add the view entry to the driver
+ */
+ ret = addViewEntryIoctl(fd, lu, &iViewEntry);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the add to driver was successful, add it to the persistent
+ * store.
+ */
+ ret = psAddViewEntry(lu, &iViewEntry);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfAddViewEntry:psAddViewEntry:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+
+ if (ret == STMF_STATUS_SUCCESS) {
+ /* set caller's view entry on success */
+ viewEntry->veIndexValid = iViewEntry.veIndexValid;
+ viewEntry->veIndex = iViewEntry.veIndex;
+ viewEntry->luNbrValid = B_TRUE;
+ bcopy(iViewEntry.luNbr, viewEntry->luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+ return (ret);
+}
+
+/*
+ * stmfClearProviderData
+ *
+ * Purpose: delete all provider data for specified provider
+ *
+ * providerName - name of provider for which data should be deleted
+ */
+int
+stmfClearProviderData(char *providerName, int providerType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int savedErrno;
+ stmf_iocdata_t stmfIoctl;
+ stmf_ppioctl_data_t ppi;
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&ppi, sizeof (ppi));
+
+ (void) strncpy(ppi.ppi_name, providerName, sizeof (ppi.ppi_name));
+
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi.ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi.ppi_port_provider = 1;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
+
+ ioctlRet = ioctl(fd, STMF_IOCTL_CLEAR_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfClearProviderData:ioctl error(%d)",
+ ioctlRet);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (savedErrno != ENOENT) {
+ goto done;
+ }
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psClearProviderData(providerName, providerType);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfClearProviderData:psClearProviderData"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfCreateHostGroup
+ *
+ * Purpose: Create a new initiator group
+ *
+ * hostGroupName - name of host group to create
+ */
+int
+stmfCreateHostGroup(stmfGroupName *hostGroupName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName))) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
+ hostGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psCreateHostGroup((char *)hostGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfCreateHostGroup:psCreateHostGroup:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfCreateLu
+ *
+ * Purpose: Create a logical unit
+ *
+ * hdl - handle to logical unit resource created via stmfCreateLuResource
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the created logical
+ * unit
+ */
+int
+stmfCreateLu(luResource hdl, stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResourceImpl *luPropsHdl = hdl;
+
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (luPropsHdl->type == STMF_DISK) {
+ ret = createDiskLu((diskResource *)luPropsHdl->resource,
+ luGuid);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfCreateLuResource
+ *
+ * Purpose: Create resource handle for a logical unit
+ *
+ * dType - Type of logical unit resource to create
+ * Can be: STMF_DISK
+ *
+ * hdl - pointer to luResource
+ */
+int
+stmfCreateLuResource(uint16_t dType, luResource *hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+
+ if (dType != STMF_DISK || hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ *hdl = calloc(1, sizeof (luResourceImpl));
+ if (*hdl == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ ret = createDiskResource((luResourceImpl *)*hdl);
+ if (ret != STMF_STATUS_SUCCESS) {
+ free(*hdl);
+ return (ret);
+ }
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * Creates a disk logical unit
+ *
+ * disk - pointer to diskResource structure that represents the properties
+ * for the disk logical unit to be created.
+ */
+static int
+createDiskLu(diskResource *disk, stmfGuid *createdGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int dataFileNameLen = 0;
+ int metaFileNameLen = 0;
+ int serialNumLen = 0;
+ int luAliasLen = 0;
+ int luMgmtUrlLen = 0;
+ int sluBufSize = 0;
+ int bufOffset = 0;
+ int fd = 0;
+ int ioctlRet;
+ int savedErrno;
+ stmfGuid guid;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ sbd_create_and_reg_lu_t *sbdLu = NULL;
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /* data file name must be specified */
+ if (disk->luDataFileNameValid) {
+ dataFileNameLen = strlen(disk->luDataFileName);
+ } else {
+ (void) close(fd);
+ return (STMF_ERROR_MISSING_PROP_VAL);
+ }
+
+ sluBufSize += dataFileNameLen + 1;
+
+ if (disk->luMetaFileNameValid) {
+ metaFileNameLen = strlen(disk->luMetaFileName);
+ sluBufSize += metaFileNameLen + 1;
+ }
+
+ serialNumLen = strlen(disk->serialNum);
+ sluBufSize += serialNumLen;
+
+ if (disk->luAliasValid) {
+ luAliasLen = strlen(disk->luAlias);
+ sluBufSize += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ luMgmtUrlLen = strlen(disk->luMgmtUrl);
+ sluBufSize += luMgmtUrlLen + 1;
+ }
+
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdLu = (sbd_create_and_reg_lu_t *)calloc(1,
+ sizeof (sbd_create_and_reg_lu_t) + sluBufSize - 8);
+ if (sbdLu == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdLu->slu_struct_size = sizeof (sbd_create_and_reg_lu_t) +
+ sluBufSize - 8;
+
+ if (metaFileNameLen) {
+ sbdLu->slu_meta_fname_valid = 1;
+ sbdLu->slu_meta_fname_off = bufOffset;
+ bcopy(disk->luMetaFileName, &(sbdLu->slu_buf[bufOffset]),
+ metaFileNameLen + 1);
+ bufOffset += metaFileNameLen + 1;
+ }
+
+ bcopy(disk->luDataFileName, &(sbdLu->slu_buf[bufOffset]),
+ dataFileNameLen + 1);
+ sbdLu->slu_data_fname_off = bufOffset;
+ bufOffset += dataFileNameLen + 1;
+
+ /* currently, serial # is not passed null terminated to the driver */
+ if (disk->serialNumValid) {
+ sbdLu->slu_serial_valid = 1;
+ sbdLu->slu_serial_off = bufOffset;
+ sbdLu->slu_serial_size = serialNumLen;
+ bcopy(disk->serialNum, &(sbdLu->slu_buf[bufOffset]),
+ serialNumLen);
+ bufOffset += serialNumLen;
+ }
+
+ if (disk->luAliasValid) {
+ sbdLu->slu_alias_valid = 1;
+ sbdLu->slu_alias_off = bufOffset;
+ bcopy(disk->luAlias, &(sbdLu->slu_buf[bufOffset]),
+ luAliasLen + 1);
+ bufOffset += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ sbdLu->slu_mgmt_url_valid = 1;
+ sbdLu->slu_mgmt_url_off = bufOffset;
+ bcopy(disk->luMgmtUrl, &(sbdLu->slu_buf[bufOffset]),
+ luMgmtUrlLen + 1);
+ bufOffset += luMgmtUrlLen + 1;
+ }
+
+ if (disk->luSizeValid) {
+ sbdLu->slu_lu_size_valid = 1;
+ sbdLu->slu_lu_size = disk->luSize;
+ }
+
+ if (disk->luGuidValid) {
+ sbdLu->slu_guid_valid = 1;
+ bcopy(disk->luGuid, sbdLu->slu_guid, sizeof (disk->luGuid));
+ }
+
+ if (disk->vidValid) {
+ sbdLu->slu_vid_valid = 1;
+ bcopy(disk->vid, sbdLu->slu_vid, sizeof (disk->vid));
+ }
+
+ if (disk->pidValid) {
+ sbdLu->slu_pid_valid = 1;
+ bcopy(disk->pid, sbdLu->slu_pid, sizeof (disk->pid));
+ }
+
+ if (disk->revValid) {
+ sbdLu->slu_rev_valid = 1;
+ bcopy(disk->rev, sbdLu->slu_rev, sizeof (disk->rev));
+ }
+
+ if (disk->companyIdValid) {
+ sbdLu->slu_company_id_valid = 1;
+ sbdLu->slu_company_id = disk->companyId;
+ }
+
+ if (disk->hostIdValid) {
+ sbdLu->slu_host_id_valid = 1;
+ sbdLu->slu_host_id = disk->hostId;
+ }
+
+ if (disk->blkSizeValid) {
+ sbdLu->slu_blksize_valid = 1;
+ sbdLu->slu_blksize = disk->blkSize;
+ }
+
+ if (disk->writeProtectEnableValid) {
+ if (disk->writeProtectEnable) {
+ sbdLu->slu_write_protected = 1;
+ }
+ }
+
+ if (disk->writebackCacheDisableValid) {
+ sbdLu->slu_writeback_cache_disable_valid = 1;
+ if (disk->writebackCacheDisable) {
+ sbdLu->slu_writeback_cache_disable = 1;
+ }
+ }
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdLu->slu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+ sbdIoctl.stmf_obuf_size = sbdLu->slu_struct_size;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_CREATE_AND_REGISTER_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "createDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * on success, copy the resulting guid into the caller's guid if not
+ * NULL
+ */
+ if (createdGuid) {
+ bcopy(sbdLu->slu_guid, createdGuid->guid,
+ sizeof (sbdLu->slu_guid));
+ }
+
+ bcopy(sbdLu->slu_guid, guid.guid, sizeof (sbdLu->slu_guid));
+ if (disk->luMetaFileNameValid) {
+ ret = addGuidToDiskStore(&guid, disk->luMetaFileName);
+ } else {
+ ret = addGuidToDiskStore(&guid, disk->luDataFileName);
+ }
+done:
+ free(sbdLu);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfImportLu
+ *
+ * Purpose: Import a previously created logical unit
+ *
+ * dType - Type of logical unit
+ * Can be: STMF_DISK
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the imported logical
+ * unit
+ *
+ * fname - A file name where the metadata resides
+ *
+ */
+int
+stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+
+ if (dType == STMF_DISK) {
+ ret = importDiskLu(fname, luGuid);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * importDiskLu
+ *
+ * filename - filename to import
+ * createdGuid - if not NULL, on success contains the imported guid
+ *
+ */
+static int
+importDiskLu(char *fname, stmfGuid *createdGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd = 0;
+ int ioctlRet;
+ int savedErrno;
+ int metaFileNameLen;
+ stmfGuid iGuid;
+ int iluBufSize = 0;
+ sbd_import_lu_t *sbdLu = NULL;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ if (fname == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ metaFileNameLen = strlen(fname);
+ iluBufSize += metaFileNameLen + 1;
+
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdLu = (sbd_import_lu_t *)calloc(1,
+ sizeof (sbd_import_lu_t) + iluBufSize - 8);
+ if (sbdLu == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ /*
+ * Accept either a data file or meta data file.
+ * sbd will do the right thing here either way.
+ * i.e. if it's a data file, it assumes that the
+ * meta data is shared with the data.
+ */
+ (void) strncpy(sbdLu->ilu_meta_fname, fname, metaFileNameLen);
+
+ sbdLu->ilu_struct_size = sizeof (sbd_import_lu_t) + iluBufSize - 8;
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdLu->ilu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+ sbdIoctl.stmf_obuf_size = sbdLu->ilu_struct_size;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_IMPORT_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+
+ if (createdGuid && sbdIoctl.stmf_error ==
+ SBD_RET_FILE_ALREADY_REGISTERED) {
+ bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
+ sizeof (sbdLu->ilu_ret_guid));
+ }
+
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "importDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /*
+ * on success, copy the resulting guid into the caller's guid if not
+ * NULL and add it to the persistent store for sbd
+ */
+ if (createdGuid) {
+ bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
+ sizeof (sbdLu->ilu_ret_guid));
+ ret = addGuidToDiskStore(createdGuid, fname);
+ } else {
+ bcopy(sbdLu->ilu_ret_guid, iGuid.guid,
+ sizeof (sbdLu->ilu_ret_guid));
+ ret = addGuidToDiskStore(&iGuid, fname);
+ }
+done:
+ free(sbdLu);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * diskError
+ *
+ * Purpose: Translate sbd driver error
+ */
+static void
+diskError(uint32_t stmfError, int *ret)
+{
+ switch (stmfError) {
+ case SBD_RET_META_CREATION_FAILED:
+ case SBD_RET_ZFS_META_CREATE_FAILED:
+ *ret = STMF_ERROR_META_CREATION;
+ break;
+ case SBD_RET_INVALID_BLKSIZE:
+ *ret = STMF_ERROR_INVALID_BLKSIZE;
+ break;
+ case SBD_RET_FILE_ALREADY_REGISTERED:
+ *ret = STMF_ERROR_FILE_IN_USE;
+ break;
+ case SBD_RET_GUID_ALREADY_REGISTERED:
+ *ret = STMF_ERROR_GUID_IN_USE;
+ break;
+ case SBD_RET_META_PATH_NOT_ABSOLUTE:
+ case SBD_RET_META_FILE_LOOKUP_FAILED:
+ case SBD_RET_META_FILE_OPEN_FAILED:
+ case SBD_RET_META_FILE_GETATTR_FAILED:
+ case SBD_RET_NO_META:
+ *ret = STMF_ERROR_META_FILE_NAME;
+ break;
+ case SBD_RET_DATA_PATH_NOT_ABSOLUTE:
+ case SBD_RET_DATA_FILE_LOOKUP_FAILED:
+ case SBD_RET_DATA_FILE_OPEN_FAILED:
+ case SBD_RET_DATA_FILE_GETATTR_FAILED:
+ *ret = STMF_ERROR_DATA_FILE_NAME;
+ break;
+ case SBD_RET_FILE_SIZE_ERROR:
+ *ret = STMF_ERROR_FILE_SIZE_INVALID;
+ break;
+ case SBD_RET_SIZE_OUT_OF_RANGE:
+ *ret = STMF_ERROR_SIZE_OUT_OF_RANGE;
+ break;
+ case SBD_RET_LU_BUSY:
+ *ret = STMF_ERROR_LU_BUSY;
+ break;
+ case SBD_RET_WRITE_CACHE_SET_FAILED:
+ *ret = STMF_ERROR_WRITE_CACHE_SET;
+ break;
+ case SBD_RET_ACCESS_STATE_FAILED:
+ *ret = STMF_ERROR_ACCESS_STATE_SET;
+ break;
+ default:
+ *ret = STMF_STATUS_ERROR;
+ break;
+ }
+}
+
+/*
+ * Creates a logical unit resource of type STMF_DISK.
+ *
+ * No defaults should be set here as all defaults are derived from the
+ * driver's default settings.
+ */
+static int
+createDiskResource(luResourceImpl *hdl)
+{
+ hdl->type = STMF_DISK;
+
+ hdl->resource = calloc(1, sizeof (diskResource));
+ if (hdl->resource == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfDeleteLu
+ *
+ * Purpose: Delete a logical unit
+ *
+ * hdl - handle to logical unit resource created via stmfCreateLuResource
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the created logical
+ * unit
+ */
+int
+stmfDeleteLu(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (luGuid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = deleteDiskLu(luGuid);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+deleteDiskLu(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int savedErrno;
+ int ioctlRet;
+ sbd_delete_lu_t deleteLu = {0};
+
+ stmf_iocdata_t sbdIoctl = {0};
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = removeGuidFromDiskStore(luGuid);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ bcopy(luGuid, deleteLu.dlu_guid, sizeof (deleteLu.dlu_guid));
+ deleteLu.dlu_by_guid = 1;
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sizeof (deleteLu);
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&deleteLu;
+ ioctlRet = ioctl(fd, SBD_IOCTL_DELETE_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "deleteDiskLu:ioctl error(%d) (%d) (%d)",
+ ioctlRet, sbdIoctl.stmf_error, savedErrno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfLuStandby
+ *
+ * Purpose: Sets access state to standby
+ *
+ * luGuid - guid of registered logical unit
+ *
+ */
+int
+stmfLuStandby(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (luGuid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = setDiskStandby(luGuid);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+static int
+setDiskStandby(stmfGuid *luGuid)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmf_iocdata_t sbdIoctl = {0};
+ sbd_set_lu_standby_t sbdLu = {0};
+ int ioctlRet;
+ int savedErrno;
+ int fd = 0;
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bcopy(luGuid, &sbdLu.stlu_guid, sizeof (stmfGuid));
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sizeof (sbd_set_lu_standby_t);
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_SET_LU_STANDBY, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "setDiskStandby:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfModifyLu
+ *
+ * Purpose: Modify properties of a logical unit
+ *
+ * luGuid - guid of registered logical unit
+ * prop - property to modify
+ * propVal - property value to set
+ *
+ */
+int
+stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (luGuid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = modifyDiskLuProp(luGuid, NULL, prop, propVal);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfModifyLuByFname
+ *
+ * Purpose: Modify a device by filename. Device does not need to be registered.
+ *
+ * dType - type of device to modify
+ * STMF_DISK
+ *
+ * fname - filename or meta filename
+ * prop - valid property identifier
+ * propVal - property value
+ *
+ */
+int
+stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
+ const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (fname == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (dType == STMF_DISK) {
+ ret = modifyDiskLuProp(NULL, fname, prop, propVal);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+static int
+modifyDiskLuProp(stmfGuid *luGuid, const char *fname, uint32_t prop,
+ const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResource hdl = NULL;
+ luResourceImpl *luPropsHdl;
+
+ ret = stmfCreateLuResource(STMF_DISK, &hdl);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ ret = validateModifyDiskProp(prop);
+ if (ret != STMF_STATUS_SUCCESS) {
+ (void) stmfFreeLuResource(hdl);
+ return (STMF_ERROR_INVALID_PROP);
+ }
+ ret = stmfSetLuProp(hdl, prop, propVal);
+ if (ret != STMF_STATUS_SUCCESS) {
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+ }
+ luPropsHdl = hdl;
+ ret = modifyDiskLu((diskResource *)luPropsHdl->resource, luGuid, fname);
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+}
+
+static int
+validateModifyDiskProp(uint32_t prop)
+{
+ switch (prop) {
+ case STMF_LU_PROP_ALIAS:
+ case STMF_LU_PROP_SIZE:
+ case STMF_LU_PROP_MGMT_URL:
+ case STMF_LU_PROP_WRITE_PROTECT:
+ case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+ return (STMF_STATUS_SUCCESS);
+ default:
+ return (STMF_STATUS_ERROR);
+ }
+}
+
+static int
+modifyDiskLu(diskResource *disk, stmfGuid *luGuid, const char *fname)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int luAliasLen = 0;
+ int luMgmtUrlLen = 0;
+ int mluBufSize = 0;
+ int bufOffset = 0;
+ int fd = 0;
+ int ioctlRet;
+ int savedErrno;
+ int fnameSize = 0;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ sbd_modify_lu_t *sbdLu = NULL;
+
+ if (luGuid == NULL && fname == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (fname) {
+ fnameSize = strlen(fname) + 1;
+ mluBufSize += fnameSize;
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if (disk->luAliasValid) {
+ luAliasLen = strlen(disk->luAlias);
+ mluBufSize += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ luMgmtUrlLen = strlen(disk->luMgmtUrl);
+ mluBufSize += luMgmtUrlLen + 1;
+ }
+
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdLu = (sbd_modify_lu_t *)calloc(1,
+ sizeof (sbd_modify_lu_t) + mluBufSize - 8 + fnameSize);
+ if (sbdLu == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdLu->mlu_struct_size = sizeof (sbd_modify_lu_t) +
+ mluBufSize - 8 + fnameSize;
+
+ if (disk->luAliasValid) {
+ sbdLu->mlu_alias_valid = 1;
+ sbdLu->mlu_alias_off = bufOffset;
+ bcopy(disk->luAlias, &(sbdLu->mlu_buf[bufOffset]),
+ luAliasLen + 1);
+ bufOffset += luAliasLen + 1;
+ }
+
+ if (disk->luMgmtUrlValid) {
+ sbdLu->mlu_mgmt_url_valid = 1;
+ sbdLu->mlu_mgmt_url_off = bufOffset;
+ bcopy(disk->luMgmtUrl, &(sbdLu->mlu_buf[bufOffset]),
+ luMgmtUrlLen + 1);
+ bufOffset += luMgmtUrlLen + 1;
+ }
+
+ if (disk->luSizeValid) {
+ sbdLu->mlu_lu_size_valid = 1;
+ sbdLu->mlu_lu_size = disk->luSize;
+ }
+
+ if (disk->writeProtectEnableValid) {
+ sbdLu->mlu_write_protected_valid = 1;
+ if (disk->writeProtectEnable) {
+ sbdLu->mlu_write_protected = 1;
+ }
+ }
+
+ if (disk->writebackCacheDisableValid) {
+ sbdLu->mlu_writeback_cache_disable_valid = 1;
+ if (disk->writebackCacheDisable) {
+ sbdLu->mlu_writeback_cache_disable = 1;
+ }
+ }
+
+ if (luGuid) {
+ bcopy(luGuid, sbdLu->mlu_input_guid, sizeof (stmfGuid));
+ sbdLu->mlu_by_guid = 1;
+ } else {
+ sbdLu->mlu_fname_off = bufOffset;
+ bcopy(fname, &(sbdLu->mlu_buf[bufOffset]), fnameSize + 1);
+ sbdLu->mlu_by_fname = 1;
+ }
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdLu->mlu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_MODIFY_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "modifyDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+done:
+ free(sbdLu);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * removeGuidFromDiskStore
+ *
+ * Purpose: delete a logical unit from the sbd provider data
+ */
+static int
+removeGuidFromDiskStore(stmfGuid *guid)
+{
+ return (persistDiskGuid(guid, NULL, B_FALSE));
+}
+
+
+/*
+ * addGuidToDiskStore
+ *
+ * Purpose: add a logical unit to the sbd provider data
+ */
+static int
+addGuidToDiskStore(stmfGuid *guid, char *filename)
+{
+ return (persistDiskGuid(guid, filename, B_TRUE));
+}
+
+
+/*
+ * persistDiskGuid
+ *
+ * Purpose: Persist or unpersist a guid for the sbd provider data
+ *
+ */
+static int
+persistDiskGuid(stmfGuid *guid, char *filename, boolean_t persist)
+{
+ char guidAsciiBuf[LU_ASCII_GUID_SIZE + 1] = {0};
+ nvlist_t *nvl = NULL;
+
+ uint64_t setToken;
+ boolean_t retryGetProviderData = B_FALSE;
+ boolean_t newData = B_FALSE;
+ int ret = STMF_STATUS_SUCCESS;
+ int retryCnt = 0;
+ int stmfRet;
+
+ /* if we're persisting a guid, there must be a filename */
+ if (persist && !filename) {
+ return (1);
+ }
+
+ /* guid is stored in lowercase ascii hex */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+ "%02x%02x%02x%02x%02x%02x",
+ guid->guid[0], guid->guid[1], guid->guid[2], guid->guid[3],
+ guid->guid[4], guid->guid[5], guid->guid[6], guid->guid[7],
+ guid->guid[8], guid->guid[9], guid->guid[10], guid->guid[11],
+ guid->guid[12], guid->guid[13], guid->guid[14], guid->guid[15]);
+
+
+ do {
+ retryGetProviderData = B_FALSE;
+ stmfRet = stmfGetProviderDataProt("sbd", &nvl,
+ STMF_LU_PROVIDER_TYPE, &setToken);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ if (persist && stmfRet == STMF_ERROR_NOT_FOUND) {
+ ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
+ if (ret != 0) {
+ syslog(LOG_DEBUG,
+ "unpersistGuid:nvlist_alloc(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+ newData = B_TRUE;
+ } else {
+ /*
+ * if we're persisting the data, it's
+ * an error. Otherwise, just return
+ */
+ if (persist) {
+ ret = stmfRet;
+ }
+ goto done;
+ }
+ }
+ if (persist) {
+ ret = nvlist_add_string(nvl, guidAsciiBuf, filename);
+ } else {
+ ret = nvlist_remove(nvl, guidAsciiBuf,
+ DATA_TYPE_STRING);
+ if (ret == ENOENT) {
+ ret = 0;
+ }
+ }
+ if (ret == 0) {
+ if (newData) {
+ stmfRet = stmfSetProviderDataProt("sbd", nvl,
+ STMF_LU_PROVIDER_TYPE, NULL);
+ } else {
+ stmfRet = stmfSetProviderDataProt("sbd", nvl,
+ STMF_LU_PROVIDER_TYPE, &setToken);
+ }
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ if (stmfRet == STMF_ERROR_BUSY) {
+ /* get/set failed, try again */
+ retryGetProviderData = B_TRUE;
+ if (retryCnt++ > MAX_PROVIDER_RETRY) {
+ ret = stmfRet;
+ break;
+ }
+ continue;
+ } else if (stmfRet ==
+ STMF_ERROR_PROV_DATA_STALE) {
+ /* update failed, try again */
+ nvlist_free(nvl);
+ nvl = NULL;
+ retryGetProviderData = B_TRUE;
+ if (retryCnt++ > MAX_PROVIDER_RETRY) {
+ ret = stmfRet;
+ break;
+ }
+ continue;
+ } else {
+ syslog(LOG_DEBUG,
+ "unpersistGuid:error(%x)", stmfRet);
+ ret = stmfRet;
+ }
+ break;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "unpersistGuid:error nvlist_add/remove(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ }
+ } while (retryGetProviderData);
+
+done:
+ nvlist_free(nvl);
+ return (ret);
+}
+
+
+/*
+ * stmfGetLuProp
+ *
+ * Purpose: Get current value for a resource property
+ *
+ * hdl - luResource from a previous call to stmfCreateLuResource
+ *
+ * resourceProp - a valid resource property type
+ *
+ * propVal - void pointer to a pointer of the value to be retrieved
+ */
+int
+stmfGetLuProp(luResource hdl, uint32_t prop, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResourceImpl *luPropsHdl = hdl;
+ if (hdl == NULL || propLen == NULL || propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (luPropsHdl->type == STMF_DISK) {
+ ret = getDiskProp(luPropsHdl, prop, propVal, propLen);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetLuResource
+ *
+ * Purpose: Get a logical unit resource handle for a given logical unit.
+ *
+ * hdl - pointer to luResource
+ */
+int
+stmfGetLuResource(stmfGuid *luGuid, luResource *hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ stmfLogicalUnitProperties luProps;
+
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check logical unit provider name to call correct dtype function */
+ if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ } else {
+ if (strcmp(luProps.providerName, "sbd") == 0) {
+ ret = getDiskAllProps(luGuid, hdl);
+ } else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+ return (STMF_ERROR_NOT_FOUND);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * getDiskAllProps
+ *
+ * Purpose: load all disk properties from sbd driver
+ *
+ * luGuid - guid of disk device for which properties are to be retrieved
+ * hdl - allocated luResource into which properties are to be copied
+ *
+ */
+static int
+getDiskAllProps(stmfGuid *luGuid, luResource *hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ sbd_lu_props_t *sbdProps;
+ int ioctlRet;
+ int savedErrno;
+ int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+
+ *hdl = calloc(1, sizeof (luResourceImpl));
+ if (*hdl == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdProps = calloc(1, sbdPropsSize);
+ if (sbdProps == NULL) {
+ free(*hdl);
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ ret = createDiskResource((luResourceImpl *)*hdl);
+ if (ret != STMF_STATUS_SUCCESS) {
+ free(*hdl);
+ free(sbdProps);
+ (void) close(fd);
+ return (ret);
+ }
+
+ sbdProps->slp_input_guid = 1;
+ bcopy(luGuid, sbdProps->slp_guid, sizeof (sbdProps->slp_guid));
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdPropsSize;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdProps;
+ sbdIoctl.stmf_obuf_size = sbdPropsSize;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
+ ioctlRet = ioctl(fd, SBD_IOCTL_GET_LU_PROPS, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getDiskAllProps:ioctl error(%d) (%d) (%d)",
+ ioctlRet, sbdIoctl.stmf_error, savedErrno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+
+ if (ret == STMF_STATUS_SUCCESS) {
+ ret = loadDiskPropsFromDriver((luResourceImpl *)*hdl, sbdProps);
+ }
+
+ free(sbdProps);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * loadDiskPropsFromDriver
+ *
+ * Purpose: Retrieve all disk type properties from sbd driver
+ *
+ * hdl - Allocated luResourceImpl
+ * sbdProps - sbd_lu_props_t structure returned from sbd driver
+ *
+ */
+static int
+loadDiskPropsFromDriver(luResourceImpl *hdl, sbd_lu_props_t *sbdProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ diskResource *diskLu = hdl->resource;
+ /* copy guid */
+ diskLu->luGuidValid = B_TRUE;
+ bcopy(sbdProps->slp_guid, diskLu->luGuid, sizeof (sbdProps->slp_guid));
+
+ if (sbdProps->slp_separate_meta && sbdProps->slp_meta_fname_valid) {
+ diskLu->luMetaFileNameValid = B_TRUE;
+ if (strlcpy(diskLu->luMetaFileName,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_meta_fname_off]),
+ sizeof (diskLu->luMetaFileName)) >=
+ sizeof (diskLu->luMetaFileName)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+
+ if (sbdProps->slp_data_fname_valid) {
+ diskLu->luDataFileNameValid = B_TRUE;
+ if (strlcpy(diskLu->luDataFileName,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_data_fname_off]),
+ sizeof (diskLu->luDataFileName)) >=
+ sizeof (diskLu->luDataFileName)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+
+ if (sbdProps->slp_serial_valid) {
+ diskLu->serialNumValid = B_TRUE;
+ bcopy(&(sbdProps->slp_buf[sbdProps->slp_serial_off]),
+ diskLu->serialNum, sbdProps->slp_serial_size);
+ }
+
+ if (sbdProps->slp_mgmt_url_valid) {
+ diskLu->luMgmtUrlValid = B_TRUE;
+ if (strlcpy(diskLu->luMgmtUrl,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_mgmt_url_off]),
+ sizeof (diskLu->luMgmtUrl)) >=
+ sizeof (diskLu->luMgmtUrl)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+
+ if (sbdProps->slp_alias_valid) {
+ diskLu->luAliasValid = B_TRUE;
+ if (strlcpy(diskLu->luAlias,
+ (char *)&(sbdProps->slp_buf[sbdProps->slp_alias_off]),
+ sizeof (diskLu->luAlias)) >=
+ sizeof (diskLu->luAlias)) {
+ return (STMF_STATUS_ERROR);
+ }
+ } else { /* set alias to data filename if not set */
+ if (sbdProps->slp_data_fname_valid) {
+ diskLu->luAliasValid = B_TRUE;
+ if (strlcpy(diskLu->luAlias,
+ (char *)&(sbdProps->slp_buf[
+ sbdProps->slp_data_fname_off]),
+ sizeof (diskLu->luAlias)) >=
+ sizeof (diskLu->luAlias)) {
+ return (STMF_STATUS_ERROR);
+ }
+ }
+ }
+
+ diskLu->vidValid = B_TRUE;
+ bcopy(sbdProps->slp_vid, diskLu->vid, sizeof (diskLu->vid));
+
+ diskLu->pidValid = B_TRUE;
+ bcopy(sbdProps->slp_pid, diskLu->pid, sizeof (diskLu->pid));
+
+ diskLu->revValid = B_TRUE;
+ bcopy(sbdProps->slp_rev, diskLu->rev, sizeof (diskLu->rev));
+
+ diskLu->writeProtectEnableValid = B_TRUE;
+ if (sbdProps->slp_write_protected) {
+ diskLu->writeProtectEnable = B_TRUE;
+ }
+
+ diskLu->writebackCacheDisableValid = B_TRUE;
+ if (sbdProps->slp_writeback_cache_disable_cur) {
+ diskLu->writebackCacheDisable = B_TRUE;
+ }
+
+ diskLu->blkSizeValid = B_TRUE;
+ diskLu->blkSize = sbdProps->slp_blksize;
+
+ diskLu->luSizeValid = B_TRUE;
+ diskLu->luSize = sbdProps->slp_lu_size;
+
+ diskLu->accessState = sbdProps->slp_access_state;
+
+ return (ret);
+}
+
+/*
+ * stmfGetGlobalLuProp
+ *
+ * Purpose: get a global property for a device type
+ *
+ */
+int
+stmfGetGlobalLuProp(uint16_t dType, uint32_t prop, char *propVal,
+ size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (dType != STMF_DISK || propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = getDiskGlobalProp(prop, propVal, propLen);
+
+ return (ret);
+}
+
+/*
+ * getDiskGlobalProp
+ *
+ * Purpose: get global property from sbd driver
+ *
+ */
+static int
+getDiskGlobalProp(uint32_t prop, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ sbd_global_props_t *sbdProps;
+ void *sbd_realloc;
+ int retryCnt = 0;
+ boolean_t retry;
+ int ioctlRet;
+ int savedErrno;
+ int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
+ stmf_iocdata_t sbdIoctl = {0};
+ size_t reqLen;
+
+ switch (prop) {
+ case STMF_LU_PROP_MGMT_URL:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_PROP);
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ sbdProps = calloc(1, sbdPropsSize);
+ if (sbdProps == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ do {
+ retry = B_FALSE;
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_obuf_size = sbdPropsSize;
+ sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
+ ioctlRet = ioctl(fd, SBD_IOCTL_GET_GLOBAL_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOMEM:
+ if (sbdIoctl.stmf_error ==
+ SBD_RET_INSUFFICIENT_BUF_SPACE &&
+ retryCnt++ < 3) {
+ sbdPropsSize =
+ sizeof (*sbdProps) +
+ sbdProps->
+ mlu_buf_size_needed;
+
+ sbd_realloc = sbdProps;
+ sbdProps = realloc(sbdProps,
+ sbdPropsSize);
+ if (sbdProps == NULL) {
+ free(sbd_realloc);
+ ret = STMF_ERROR_NOMEM;
+ break;
+ }
+ retry = B_TRUE;
+ } else {
+ ret = STMF_ERROR_NOMEM;
+ }
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getDiskGlobalProp:ioctl error(%d)"
+ "(%d)(%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ }
+ } while (retry);
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ switch (prop) {
+ case STMF_LU_PROP_MGMT_URL:
+ if (sbdProps->mlu_mgmt_url_valid == 0) {
+ ret = STMF_ERROR_NO_PROP;
+ goto done;
+ }
+ if ((reqLen = strlcpy(propVal, (char *)&(
+ sbdProps->mlu_buf[sbdProps->mlu_mgmt_url_off]),
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+ break;
+ }
+
+done:
+ free(sbdProps);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfSetGlobalLuProp
+ *
+ * Purpose: set a global property for a device type
+ *
+ */
+int
+stmfSetGlobalLuProp(uint16_t dType, uint32_t prop, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (dType != STMF_DISK || propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = setDiskGlobalProp(prop, propVal);
+
+ return (ret);
+}
+
+/*
+ * setDiskGlobalProp
+ *
+ * Purpose: set properties for resource of type disk
+ *
+ * resourceProp - valid resource identifier
+ * propVal - valid resource value
+ */
+static int
+setDiskGlobalProp(uint32_t resourceProp, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ sbd_global_props_t *sbdGlobalProps = NULL;
+ int sbdGlobalPropsSize = 0;
+ int propLen;
+ int mluBufSize = 0;
+ int fd;
+ int savedErrno;
+ int ioctlRet;
+ stmf_iocdata_t sbdIoctl = {0};
+
+ switch (resourceProp) {
+ case STMF_LU_PROP_MGMT_URL:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_PROP);
+ }
+
+ /*
+ * Open control node for sbd
+ */
+ if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ propLen = strlen(propVal);
+ mluBufSize += propLen + 1;
+ sbdGlobalPropsSize += sizeof (sbd_global_props_t) - 8 +
+ max(8, mluBufSize);
+ /*
+ * 8 is the size of the buffer set aside for
+ * concatenation of variable length fields
+ */
+ sbdGlobalProps = (sbd_global_props_t *)calloc(1, sbdGlobalPropsSize);
+ if (sbdGlobalProps == NULL) {
+ (void) close(fd);
+ return (STMF_ERROR_NOMEM);
+ }
+
+ sbdGlobalProps->mlu_struct_size = sbdGlobalPropsSize;
+
+ switch (resourceProp) {
+ case STMF_LU_PROP_MGMT_URL:
+ sbdGlobalProps->mlu_mgmt_url_valid = 1;
+ bcopy(propVal, &(sbdGlobalProps->mlu_buf),
+ propLen + 1);
+ break;
+ default:
+ ret = STMF_ERROR_NO_PROP;
+ goto done;
+ }
+
+ sbdIoctl.stmf_version = STMF_VERSION_1;
+ sbdIoctl.stmf_ibuf_size = sbdGlobalProps->mlu_struct_size;
+ sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdGlobalProps;
+
+ ioctlRet = ioctl(fd, SBD_IOCTL_SET_GLOBAL_LU, &sbdIoctl);
+ if (ioctlRet != 0) {
+ savedErrno = errno;
+ switch (savedErrno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ diskError(sbdIoctl.stmf_error, &ret);
+ if (ret == STMF_STATUS_ERROR) {
+ syslog(LOG_DEBUG,
+ "modifyDiskLu:ioctl "
+ "error(%d) (%d) (%d)", ioctlRet,
+ sbdIoctl.stmf_error, savedErrno);
+ }
+ break;
+ }
+ }
+
+done:
+ free(sbdGlobalProps);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfSetLuProp
+ *
+ * Purpose: set a property on an luResource
+ *
+ * hdl - allocated luResource
+ * prop - property identifier
+ * propVal - property value to be set
+ */
+int
+stmfSetLuProp(luResource hdl, uint32_t prop, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ luResourceImpl *luPropsHdl = hdl;
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (luPropsHdl->type == STMF_DISK) {
+ ret = setDiskProp(luPropsHdl, prop, propVal);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ return (ret);
+}
+
+/*
+ * getDiskProp
+ *
+ * Purpose: retrieve a given property from a logical unit resource of type disk
+ *
+ * hdl - allocated luResourceImpl
+ * prop - property identifier
+ * propVal - pointer to character to contain the retrieved property value
+ * propLen - On input this is the length of propVal. On failure, it contains the
+ * number of bytes required for propVal
+ */
+static int
+getDiskProp(luResourceImpl *hdl, uint32_t prop, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ diskResource *diskLu = hdl->resource;
+ char accessState[20];
+ size_t reqLen;
+
+ if (prop == STMF_LU_PROP_ACCESS_STATE) {
+ if (diskLu->accessState == SBD_LU_ACTIVE) {
+ (void) strlcpy(accessState, STMF_ACCESS_ACTIVE,
+ sizeof (accessState));
+ } else if (diskLu->accessState == SBD_LU_TRANSITION_TO_ACTIVE) {
+ (void) strlcpy(accessState,
+ STMF_ACCESS_STANDBY_TO_ACTIVE,
+ sizeof (accessState));
+ } else if (diskLu->accessState == SBD_LU_STANDBY) {
+ (void) strlcpy(accessState, STMF_ACCESS_STANDBY,
+ sizeof (accessState));
+ } else if (diskLu->accessState ==
+ SBD_LU_TRANSITION_TO_STANDBY) {
+ (void) strlcpy(accessState,
+ STMF_ACCESS_ACTIVE_TO_STANDBY,
+ sizeof (accessState));
+ }
+ if ((reqLen = strlcpy(propVal, accessState,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ return (0);
+ }
+
+ if (diskLu->accessState != SBD_LU_ACTIVE) {
+ return (STMF_ERROR_NO_PROP_STANDBY);
+ }
+
+ switch (prop) {
+ case STMF_LU_PROP_BLOCK_SIZE:
+ if (diskLu->blkSizeValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ reqLen = snprintf(propVal, *propLen, "%llu",
+ (u_longlong_t)diskLu->blkSize);
+ if (reqLen >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_FILENAME:
+ if (diskLu->luDataFileNameValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luDataFileName,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_META_FILENAME:
+ if (diskLu->luMetaFileNameValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luMetaFileName,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_MGMT_URL:
+ if (diskLu->luMgmtUrlValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luMgmtUrl,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_GUID:
+ if (diskLu->luGuidValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ reqLen = snprintf(propVal, *propLen,
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X",
+ diskLu->luGuid[0], diskLu->luGuid[1],
+ diskLu->luGuid[2], diskLu->luGuid[3],
+ diskLu->luGuid[4], diskLu->luGuid[5],
+ diskLu->luGuid[6], diskLu->luGuid[7],
+ diskLu->luGuid[8], diskLu->luGuid[9],
+ diskLu->luGuid[10], diskLu->luGuid[11],
+ diskLu->luGuid[12], diskLu->luGuid[13],
+ diskLu->luGuid[14], diskLu->luGuid[15]);
+ if (reqLen >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_SERIAL_NUM:
+ if (diskLu->serialNumValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->serialNum,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_SIZE:
+ if (diskLu->luSizeValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ (void) snprintf(propVal, *propLen, "%llu",
+ (u_longlong_t)diskLu->luSize);
+ break;
+ case STMF_LU_PROP_ALIAS:
+ if (diskLu->luAliasValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if ((reqLen = strlcpy(propVal, diskLu->luAlias,
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ break;
+ case STMF_LU_PROP_VID:
+ if (diskLu->vidValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (*propLen <= sizeof (diskLu->vid)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bcopy(diskLu->vid, propVal, sizeof (diskLu->vid));
+ propVal[sizeof (diskLu->vid)] = 0;
+ break;
+ case STMF_LU_PROP_PID:
+ if (diskLu->pidValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (*propLen <= sizeof (diskLu->pid)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bcopy(diskLu->pid, propVal, sizeof (diskLu->pid));
+ propVal[sizeof (diskLu->pid)] = 0;
+ break;
+ case STMF_LU_PROP_WRITE_PROTECT:
+ if (diskLu->writeProtectEnableValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (diskLu->writeProtectEnable) {
+ if ((reqLen = strlcpy(propVal, "true",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ } else {
+ if ((reqLen = strlcpy(propVal, "false",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+ break;
+ case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+ if (diskLu->writebackCacheDisableValid == B_FALSE) {
+ return (STMF_ERROR_NO_PROP);
+ }
+ if (diskLu->writebackCacheDisable) {
+ if ((reqLen = strlcpy(propVal, "true",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ } else {
+ if ((reqLen = strlcpy(propVal, "false",
+ *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_PROP;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * setDiskProp
+ *
+ * Purpose: set properties for resource of type disk
+ *
+ * hdl - allocated luResourceImpl
+ * resourceProp - valid resource identifier
+ * propVal - valid resource value
+ */
+static int
+setDiskProp(luResourceImpl *hdl, uint32_t resourceProp, const char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int i;
+ diskResource *diskLu = hdl->resource;
+ unsigned long long numericProp = 0;
+ char guidProp[LU_ASCII_GUID_SIZE + 1];
+ char ouiProp[OUI_ASCII_SIZE + 1];
+ char hostIdProp[HOST_ID_ASCII_SIZE + 1];
+ unsigned int oui[OUI_SIZE];
+ unsigned int hostId[HOST_ID_SIZE];
+ unsigned int guid[LU_GUID_SIZE];
+ int propSize;
+
+
+ if (propVal == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ switch (resourceProp) {
+ case STMF_LU_PROP_ALIAS:
+ if (strlcpy(diskLu->luAlias, propVal,
+ sizeof (diskLu->luAlias)) >=
+ sizeof (diskLu->luAlias)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luAliasValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_BLOCK_SIZE: {
+ const char *tmp = propVal;
+ while (*tmp) {
+ if (!isdigit(*tmp++)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ }
+ (void) sscanf(propVal, "%llu", &numericProp);
+ if (numericProp > UINT16_MAX) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->blkSize = numericProp;
+ diskLu->blkSizeValid = B_TRUE;
+ break;
+ }
+ case STMF_LU_PROP_COMPANY_ID:
+ if ((strlcpy(ouiProp, propVal, sizeof (ouiProp))) >=
+ sizeof (ouiProp)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (checkHexUpper(ouiProp) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ (void) sscanf(ouiProp, "%2X%2X%2X",
+ &oui[0], &oui[1], &oui[2]);
+
+ diskLu->companyId = 0;
+ diskLu->companyId += oui[0] << 16;
+ diskLu->companyId += oui[1] << 8;
+ diskLu->companyId += oui[2];
+ if (diskLu->companyId == 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->companyIdValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_HOST_ID:
+ if ((strlcpy(hostIdProp, propVal,
+ sizeof (hostIdProp))) >= sizeof (hostIdProp)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (checkHexUpper(hostIdProp) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ (void) sscanf(hostIdProp, "%2X%2X%2X%2X",
+ &hostId[0], &hostId[1], &hostId[2], &hostId[3]);
+
+ diskLu->hostId = 0;
+ diskLu->hostId += hostId[0] << 24;
+ diskLu->hostId += hostId[1] << 16;
+ diskLu->hostId += hostId[2] << 8;
+ diskLu->hostId += hostId[3];
+ if (diskLu->hostId == 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->hostIdValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_GUID:
+ if (strlen(propVal) != LU_ASCII_GUID_SIZE) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+
+ if ((strlcpy(guidProp, propVal, sizeof (guidProp))) >=
+ sizeof (guidProp)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (checkHexUpper(guidProp) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ (void) sscanf(guidProp,
+ "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
+ &guid[0], &guid[1], &guid[2], &guid[3], &guid[4],
+ &guid[5], &guid[6], &guid[7], &guid[8], &guid[9],
+ &guid[10], &guid[11], &guid[12], &guid[13],
+ &guid[14], &guid[15]);
+ for (i = 0; i < sizeof (diskLu->luGuid); i++) {
+ diskLu->luGuid[i] = guid[i];
+ }
+ diskLu->luGuidValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_FILENAME:
+ if ((strlcpy(diskLu->luDataFileName, propVal,
+ sizeof (diskLu->luDataFileName))) >=
+ sizeof (diskLu->luDataFileName)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luDataFileNameValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_META_FILENAME:
+ if ((strlcpy(diskLu->luMetaFileName, propVal,
+ sizeof (diskLu->luMetaFileName))) >=
+ sizeof (diskLu->luMetaFileName)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luMetaFileNameValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_MGMT_URL:
+ if ((strlcpy(diskLu->luMgmtUrl, propVal,
+ sizeof (diskLu->luMgmtUrl))) >=
+ sizeof (diskLu->luMgmtUrl)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ diskLu->luMgmtUrlValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_PID:
+ if ((propSize = strlen(propVal)) >
+ sizeof (diskLu->pid)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ (void) strncpy(diskLu->pid, propVal, propSize);
+ diskLu->pidValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_SERIAL_NUM:
+ if ((propSize = strlen(propVal)) >
+ (sizeof (diskLu->serialNum) - 1)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ (void) strncpy(diskLu->serialNum, propVal, propSize);
+ diskLu->serialNumValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_SIZE:
+ if ((niceStrToNum(propVal, &diskLu->luSize) != 0)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->luSizeValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_VID:
+ if ((propSize = strlen(propVal)) >
+ sizeof (diskLu->vid)) {
+ return (STMF_ERROR_INVALID_PROPSIZE);
+ }
+ (void) strncpy(diskLu->vid, propVal, propSize);
+ diskLu->vidValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_WRITE_PROTECT:
+ if (strcasecmp(propVal, "TRUE") == 0) {
+ diskLu->writeProtectEnable = B_TRUE;
+ } else if (strcasecmp(propVal, "FALSE") == 0) {
+ diskLu->writeProtectEnable = B_FALSE;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->writeProtectEnableValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+ if (strcasecmp(propVal, "TRUE") == 0) {
+ diskLu->writebackCacheDisable = B_TRUE;
+ } else if (strcasecmp(propVal, "FALSE") == 0) {
+ diskLu->writebackCacheDisable = B_FALSE;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ diskLu->writebackCacheDisableValid = B_TRUE;
+ break;
+ case STMF_LU_PROP_ACCESS_STATE:
+ ret = STMF_ERROR_INVALID_PROP;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_PROP;
+ break;
+ }
+ return (ret);
+}
+
+static int
+checkHexUpper(char *buf)
+{
+ int i;
+
+ for (i = 0; i < strlen(buf); i++) {
+ if (isxdigit(buf[i])) {
+ buf[i] = toupper(buf[i]);
+ continue;
+ }
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Given a numeric suffix, convert the value into a number of bits that the
+ * resulting value must be shifted.
+ * Code lifted from libzfs_util.c
+ */
+static int
+strToShift(const char *buf)
+{
+ const char *ends = "BKMGTPE";
+ int i;
+
+ if (buf[0] == '\0')
+ return (0);
+
+ for (i = 0; i < strlen(ends); i++) {
+ if (toupper(buf[0]) == ends[i])
+ return (10*i);
+ }
+
+ return (-1);
+}
+
+int
+stmfFreeLuResource(luResource hdl)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ luResourceImpl *hdlImpl = hdl;
+ free(hdlImpl->resource);
+ free(hdlImpl);
+ return (ret);
+}
+
+/*
+ * Convert a string of the form '100G' into a real number. Used when setting
+ * the size of a logical unit.
+ * Code lifted from libzfs_util.c
+ */
+static int
+niceStrToNum(const char *value, uint64_t *num)
+{
+ char *end;
+ int shift;
+
+ *num = 0;
+
+ /* Check to see if this looks like a number. */
+ if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
+ return (-1);
+ }
+
+ /* Rely on stroull() to process the numeric portion. */
+ errno = 0;
+ *num = strtoull(value, &end, 10);
+
+ /*
+ * Check for ERANGE, which indicates that the value is too large to fit
+ * in a 64-bit value.
+ */
+ if (errno == ERANGE) {
+ return (-1);
+ }
+
+ /*
+ * If we have a decimal value, then do the computation with floating
+ * point arithmetic. Otherwise, use standard arithmetic.
+ */
+ if (*end == '.') {
+ double fval = strtod(value, &end);
+
+ if ((shift = strToShift(end)) == -1) {
+ return (-1);
+ }
+
+ fval *= pow(2, shift);
+
+ if (fval > UINT64_MAX) {
+ return (-1);
+ }
+
+ *num = (uint64_t)fval;
+ } else {
+ if ((shift = strToShift(end)) == -1) {
+ return (-1);
+ }
+
+ /* Check for overflow */
+ if (shift >= 64 || (*num << shift) >> shift != *num) {
+ return (-1);
+ }
+
+ *num <<= shift;
+ }
+
+ return (0);
+}
+
+/*
+ * stmfCreateTargetGroup
+ *
+ * Purpose: Create a local port group
+ *
+ * targetGroupName - name of local port group to create
+ */
+int
+stmfCreateTargetGroup(stmfGroupName *targetGroupName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName))) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Add the group to the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
+ targetGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the add to the driver was successful, add it to the persistent
+ * store.
+ */
+ ret = psCreateTargetGroup((char *)targetGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfCreateTargetGroup:psCreateTargetGroup"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDeleteHostGroup
+ *
+ * Purpose: Delete an initiator or local port group
+ *
+ * hostGroupName - group to delete
+ */
+int
+stmfDeleteHostGroup(stmfGroupName *hostGroupName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Remove the group from the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_HOST_GROUP,
+ hostGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the remove from the driver was successful, remove it from the
+ * persistent store.
+ */
+ ret = psDeleteHostGroup((char *)hostGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfDeleteHostGroup:psDeleteHostGroup:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDeleteTargetGroup
+ *
+ * Purpose: Delete an initiator or local port group
+ *
+ * targetGroupName - group to delete
+ */
+int
+stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (targetGroupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Remove the group from the driver
+ */
+ if ((ret = groupIoctl(fd, STMF_IOCTL_REMOVE_TARGET_GROUP,
+ targetGroupName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /*
+ * If the remove from the driver was successful, remove it from the
+ * persistent store.
+ */
+ ret = psDeleteTargetGroup((char *)targetGroupName);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfDeleteTargetGroup:psDeleteTargetGroup"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfDevidFromIscsiName
+ *
+ * Purpose: convert an iSCSI name to an stmf devid
+ *
+ * iscsiName - unicode nul terminated utf-8 encoded iSCSI name
+ * devid - on success, contains the converted iscsi name
+ */
+int
+stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid)
+{
+ if (devid == NULL || iscsiName == NULL)
+ return (STMF_ERROR_INVALID_ARG);
+
+ bzero(devid, sizeof (stmfDevid));
+
+ /* Validate size of target */
+ if ((devid->identLength = strlen(iscsiName)) > MAX_ISCSI_NAME ||
+ devid->identLength < strlen(EUI) ||
+ devid->identLength < strlen(IQN)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if ((strncmp(iscsiName, EUI, strlen(EUI)) != 0) &&
+ strncmp(iscsiName, IQN, strlen(IQN)) != 0) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* copy UTF-8 bytes to ident */
+ bcopy(iscsiName, devid->ident, devid->identLength);
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfDevidFromWwn
+ *
+ * Purpose: convert a WWN to an stmf devid
+ *
+ * wwn - 8-byte wwn identifier
+ * devid - on success, contains the converted wwn
+ */
+int
+stmfDevidFromWwn(uchar_t *wwn, stmfDevid *devid)
+{
+ if (wwn == NULL || devid == NULL)
+ return (STMF_ERROR_INVALID_ARG);
+
+ bzero(devid, sizeof (stmfDevid));
+
+ /* Copy eui prefix */
+ (void) bcopy(WWN, devid->ident, strlen(WWN));
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf((char *)&devid->ident[strlen(WWN)],
+ sizeof (devid->ident), "%02X%02X%02X%02X%02X%02X%02X%02X",
+ wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
+
+ devid->identLength = strlen((char *)devid->ident);
+
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfFreeMemory
+ *
+ * Purpose: Free memory allocated by this library
+ *
+ * memory - previously allocated pointer of memory managed by library
+ */
+void
+stmfFreeMemory(void *memory)
+{
+ free(memory);
+}
+
+/*
+ * get host group, target group list from stmf
+ *
+ * groupType - HOST_GROUP, TARGET_GROUP
+ */
+static int
+groupListIoctl(stmfGroupList **groupList, int groupType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+ /* framework group list */
+ stmf_group_name_t *iGroupList = NULL;
+ uint32_t groupListSize;
+
+ if (groupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (groupType == HOST_GROUP) {
+ cmd = STMF_IOCTL_GET_HG_LIST;
+ } else if (groupType == TARGET_GROUP) {
+ cmd = STMF_IOCTL_GET_TG_LIST;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ groupListSize = ALLOC_GROUP;
+ groupListSize = groupListSize * (sizeof (stmf_group_name_t));
+ iGroupList = (stmf_group_name_t *)calloc(1, groupListSize);
+ if (iGroupList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the group list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GROUP) {
+ groupListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (stmf_group_name_t);
+ iGroupList = realloc(iGroupList, groupListSize);
+ if (iGroupList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /* allocate and copy to caller's buffer */
+ *groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
+ sizeof (stmfGroupName) * stmfIoctl.stmf_obuf_nentries);
+ if (*groupList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ (*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
+ bcopy(iGroupList[i].name, (*groupList)->name[i],
+ sizeof (stmfGroupName));
+ }
+
+done:
+ free(iGroupList);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * get host group members, target group members from stmf
+ *
+ * groupProps - allocated on success
+ *
+ * groupType - HOST_GROUP, TARGET_GROUP
+ */
+static int
+groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
+ int groupType)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+ /* framework group list */
+ stmf_group_name_t iGroupName;
+ stmf_ge_ident_t *iGroupMembers;
+ uint32_t groupListSize;
+
+ if (groupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (groupType == HOST_GROUP) {
+ cmd = STMF_IOCTL_GET_HG_ENTRIES;
+ } else if (groupType == TARGET_GROUP) {
+ cmd = STMF_IOCTL_GET_TG_ENTRIES;
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&iGroupName, sizeof (iGroupName));
+
+ bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
+
+ iGroupName.name_size = strlen((char *)groupName);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ groupListSize = ALLOC_GRP_MEMBER;
+ groupListSize = groupListSize * (sizeof (stmf_ge_ident_t));
+ iGroupMembers = (stmf_ge_ident_t *)calloc(1, groupListSize);
+ if (iGroupMembers == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the group list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GRP_MEMBER) {
+ groupListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (stmf_ge_ident_t);
+ iGroupMembers = realloc(iGroupMembers, groupListSize);
+ if (iGroupMembers == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
+ stmfIoctl.stmf_obuf_size = groupListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "groupListIoctl:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /* allocate and copy to caller's buffer */
+ *groupProps = (stmfGroupProperties *)calloc(1,
+ sizeof (stmfGroupProperties) +
+ sizeof (stmfDevid) * stmfIoctl.stmf_obuf_nentries);
+ if (*groupProps == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ (*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
+ (*groupProps)->name[i].identLength =
+ iGroupMembers[i].ident_size;
+ bcopy(iGroupMembers[i].ident, (*groupProps)->name[i].ident,
+ iGroupMembers[i].ident_size);
+ }
+
+done:
+ free(iGroupMembers);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * Purpose: access persistent config data for host groups and target groups
+ */
+static int
+iLoadGroupFromPs(stmfGroupList **groupList, int type)
+{
+ int ret;
+
+ if (groupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (type == HOST_GROUP) {
+ ret = psGetHostGroupList(groupList);
+ } else if (type == TARGET_GROUP) {
+ ret = psGetTargetGroupList(groupList);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetHostGroupList:psGetHostGroupList:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetHostGroupList
+ *
+ * Purpose: Retrieves the list of initiator group oids
+ *
+ * hostGroupList - pointer to pointer to hostGroupList structure
+ * on success, this contains the host group list.
+ */
+int
+stmfGetHostGroupList(stmfGroupList **hostGroupList)
+{
+ int ret = STMF_STATUS_ERROR;
+
+ if (hostGroupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupListIoctl(hostGroupList, HOST_GROUP);
+ return (ret);
+}
+
+
+/*
+ * Purpose: access persistent config data for host groups and target groups
+ */
+static int
+iLoadGroupMembersFromPs(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp, int type)
+{
+ int ret;
+
+ if (groupName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (type == HOST_GROUP) {
+ ret = psGetHostGroupMemberList((char *)groupName, groupProp);
+ } else if (type == TARGET_GROUP) {
+ ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
+ } else {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "iLoadGroupMembersFromPs:psGetHostGroupList:"
+ "error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfGetHostGroupMembers
+ *
+ * Purpose: Retrieves the group properties for a host group
+ *
+ * groupName - name of group for which to retrieve host group members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ * on success, this contains the list of group members.
+ */
+int
+stmfGetHostGroupMembers(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp)
+{
+ int ret;
+
+ if (groupName == NULL || groupProp == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupMemberListIoctl(groupName, groupProp, HOST_GROUP);
+
+ return (ret);
+}
+
+/*
+ * stmfGetProviderData
+ *
+ * Purpose: Get provider data list
+ *
+ * providerName - name of provider for which to retrieve the data
+ * nvl - pointer to nvlist_t pointer which will contain the nvlist data
+ * retrieved.
+ * providerType - type of provider for which to retrieve data.
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ */
+int
+stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType)
+{
+ return (stmfGetProviderDataProt(providerName, nvl, providerType,
+ NULL));
+}
+
+/*
+ * stmfGetProviderDataProt
+ *
+ * Purpose: Get provider data list with token
+ *
+ * providerName - name of provider for which to retrieve the data
+ * nvl - pointer to nvlist_t pointer which will contain the nvlist data
+ * retrieved.
+ * providerType - type of provider for which to retrieve data.
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ * setToken - Returns the stale data token
+ */
+int
+stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret;
+
+ if (providerName == NULL || nvl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ return (getProviderData(providerName, nvl, providerType, setToken));
+}
+
+/*
+ * stmfGetProviderDataList
+ *
+ * Purpose: Get the list of providers currently persisting data
+ *
+ * providerList - pointer to pointer to an stmfProviderList structure allocated
+ * by the caller. Will contain the list of providers on success.
+ */
+int
+stmfGetProviderDataList(stmfProviderList **providerList)
+{
+ int ret;
+
+ ret = psGetProviderDataList(providerList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetProviderDataList:psGetProviderDataList"
+ ":error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * stmfGetSessionList
+ *
+ * Purpose: Retrieves the session list for a target (devid)
+ *
+ * devid - devid of target for which to retrieve session information.
+ * sessionList - pointer to pointer to stmfSessionList structure
+ * on success, this contains the list of initiator sessions.
+ */
+int
+stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_SESSION_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ slist_scsi_session_t *fSessionList, *fSessionListP = NULL;
+ uint8_t ident[260];
+ uint32_t fSessionListSize;
+
+ if (sessionList == NULL || devid == NULL) {
+ ret = STMF_ERROR_INVALID_ARG;
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fSessionListSize = ALLOC_SESSION;
+ fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
+ fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
+ fSessionListP = fSessionList;
+ if (fSessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the session list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ident;
+ stmfIoctl.stmf_ibuf_size = sizeof (ident);
+ stmfIoctl.stmf_obuf_size = fSessionListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetSessionList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_SESSION) {
+ fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_scsi_session_t);
+ fSessionList = realloc(fSessionList, fSessionListSize);
+ if (fSessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ fSessionListP = fSessionList;
+ stmfIoctl.stmf_obuf_size = fSessionListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fSessionList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetSessionList:ioctl "
+ "errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *sessionList = (stmfSessionList *)calloc(1, sizeof (stmfSessionList) +
+ stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfSession));
+ if (*sessionList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ free(sessionList);
+ goto done;
+ }
+
+ (*sessionList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
+
+ /*
+ * copy session info to caller's buffer
+ */
+ for (i = 0; i < (*sessionList)->cnt; i++) {
+ (*sessionList)->session[i].initiator.identLength =
+ fSessionList->initiator[IDENT_LENGTH_BYTE];
+ bcopy(&(fSessionList->initiator[IDENT_LENGTH_BYTE + 1]),
+ (*sessionList)->session[i].initiator.ident,
+ STMF_IDENT_LENGTH);
+ bcopy(&(fSessionList->alias),
+ &((*sessionList)->session[i].alias),
+ sizeof ((*sessionList)->session[i].alias));
+ bcopy(&(fSessionList++->creation_time),
+ &((*sessionList)->session[i].creationTime),
+ sizeof (time_t));
+ }
+done:
+ (void) close(fd);
+ free(fSessionListP);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetGroupList
+ *
+ * Purpose: Retrieves the list of target groups
+ *
+ * targetGroupList - pointer to a pointer to an stmfGroupList structure. On
+ * success, it contains the list of target groups.
+ */
+int
+stmfGetTargetGroupList(stmfGroupList **targetGroupList)
+{
+ int ret;
+
+ if (targetGroupList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupListIoctl(targetGroupList, TARGET_GROUP);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetGroupMembers
+ *
+ * Purpose: Retrieves the group members for a target group
+ *
+ * groupName - name of target group for which to retrieve members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ * on success, this contains the list of group members.
+ */
+int
+stmfGetTargetGroupMembers(stmfGroupName *groupName,
+ stmfGroupProperties **groupProp)
+{
+ int ret;
+
+ if (groupName == NULL || groupProp == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = groupMemberListIoctl(groupName, groupProp, TARGET_GROUP);
+
+ return (ret);
+}
+
+/*
+ * stmfGetTargetList
+ *
+ * Purpose: Retrieves the list of target ports
+ *
+ * targetList - pointer to a pointer to an stmfDevidList structure.
+ * On success, it contains the list of local ports (target).
+ */
+int
+stmfGetTargetList(stmfDevidList **targetList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ /* framework target port list */
+ slist_target_port_t *fTargetList, *fTargetListP = NULL;
+ uint32_t fTargetListSize;
+
+ if (targetList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fTargetListSize = ALLOC_TARGET_PORT * sizeof (slist_target_port_t);
+ fTargetListP = fTargetList =
+ (slist_target_port_t *)calloc(1, fTargetListSize);
+ if (fTargetList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to retrieve target list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = fTargetListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
+ ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetList:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_TARGET_PORT) {
+ fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_target_port_t);
+ fTargetListP = fTargetList =
+ realloc(fTargetList, fTargetListSize);
+ if (fTargetList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_obuf_size = fTargetListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
+ ioctlRet = ioctl(fd, STMF_IOCTL_TARGET_PORT_LIST,
+ &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ *targetList = (stmfDevidList *)calloc(1,
+ stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
+ sizeof (stmfDevidList));
+ if (*targetList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ (*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
+ for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
+ (*targetList)->devid[i].identLength =
+ fTargetList->target[IDENT_LENGTH_BYTE];
+ bcopy(&fTargetList->target[IDENT_LENGTH_BYTE + 1],
+ &(*targetList)->devid[i].ident,
+ fTargetList->target[IDENT_LENGTH_BYTE]);
+ }
+
+done:
+ (void) close(fd);
+ free(fTargetListP);
+ return (ret);
+}
+
+/*
+ * stmfGetTargetProperties
+ *
+ * Purpose: Retrieves the properties for a logical unit
+ *
+ * devid - devid of the target for which to retrieve properties
+ * targetProps - pointer to an stmfTargetProperties structure.
+ * On success, it contains the target properties for
+ * the specified devid.
+ */
+int
+stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ sioc_target_port_props_t targetProperties;
+ scsi_devid_desc_t *scsiDevid;
+
+ if (devid == NULL || targetProps == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ targetProperties.tgt_id[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetProperties.tgt_id[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (targetProperties.tgt_id);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&targetProperties.tgt_id;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&targetProperties;
+ stmfIoctl.stmf_obuf_size = sizeof (targetProperties);
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_TARGET_PORT_PROPERTIES,
+ &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetTargetProperties:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ bcopy(targetProperties.tgt_provider_name, targetProps->providerName,
+ sizeof (targetProperties.tgt_provider_name));
+ if (targetProperties.tgt_state == STMF_STATE_ONLINE) {
+ targetProps->status = STMF_TARGET_PORT_ONLINE;
+ } else if (targetProperties.tgt_state == STMF_STATE_OFFLINE) {
+ targetProps->status = STMF_TARGET_PORT_OFFLINE;
+ } else if (targetProperties.tgt_state == STMF_STATE_ONLINING) {
+ targetProps->status = STMF_TARGET_PORT_ONLINING;
+ } else if (targetProperties.tgt_state == STMF_STATE_OFFLINING) {
+ targetProps->status = STMF_TARGET_PORT_OFFLINING;
+ }
+ bcopy(targetProperties.tgt_alias, targetProps->alias,
+ sizeof (targetProps->alias));
+
+ scsiDevid = (scsi_devid_desc_t *)&targetProperties.tgt_id;
+ targetProps->protocol = scsiDevid->protocol_id;
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetLogicalUnitList
+ *
+ * Purpose: Retrieves list of logical unit Object IDs
+ *
+ * luList - pointer to a pointer to a stmfGuidList structure. On success,
+ * it contains the list of logical unit guids.
+ *
+ */
+int
+stmfGetLogicalUnitList(stmfGuidList **luList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_LU_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ slist_lu_t *fLuList;
+ uint32_t fLuListSize;
+ uint32_t listCnt;
+
+ if (luList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fLuListSize = ALLOC_LU;
+ fLuListSize = fLuListSize * (sizeof (slist_lu_t));
+ fLuList = (slist_lu_t *)calloc(1, fLuListSize);
+ if (fLuList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the LU list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = fLuListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_LU) {
+ fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (slist_lu_t);
+ free(fLuList);
+ fLuList = (slist_lu_t *)calloc(1, fLuListSize);
+ if (fLuList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+ stmfIoctl.stmf_obuf_size = fLuListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ listCnt = stmfIoctl.stmf_obuf_nentries;
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
+ listCnt * sizeof (stmfGuid));
+ if (*luList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ (*luList)->cnt = listCnt;
+
+ /* copy to caller's buffer */
+ for (i = 0; i < listCnt; i++) {
+ bcopy(&fLuList[i].lu_guid, (*luList)->guid[i].guid,
+ sizeof (stmfGuid));
+ }
+
+ /*
+ * sort the list. This gives a consistent view across gets
+ */
+ qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
+ sizeof (stmfGuid), guidCompare);
+
+done:
+ (void) close(fd);
+ /*
+ * free internal buffers
+ */
+ free(fLuList);
+ return (ret);
+}
+
+/*
+ * stmfGetLogicalUnitProperties
+ *
+ * Purpose: Retrieves the properties for a logical unit
+ *
+ * lu - guid of the logical unit for which to retrieve properties
+ * stmfLuProps - pointer to an stmfLogicalUnitProperties structure. On success,
+ * it contains the logical unit properties for the specified guid.
+ */
+int
+stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int stmfRet;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_GET_LU_PROPERTIES;
+ stmfViewEntryList *viewEntryList = NULL;
+ stmf_iocdata_t stmfIoctl;
+ sioc_lu_props_t fLuProps;
+
+ if (lu == NULL || luProps == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(luProps, sizeof (stmfLogicalUnitProperties));
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the host group
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&fLuProps;
+ stmfIoctl.stmf_obuf_size = sizeof (fLuProps);
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ stmfRet = stmfGetViewEntryList(lu,
+ &viewEntryList);
+ if (stmfRet == STMF_STATUS_SUCCESS) {
+ luProps->status =
+ STMF_LOGICAL_UNIT_UNREGISTERED;
+ if (viewEntryList->cnt > 0) {
+ ret = STMF_STATUS_SUCCESS;
+ } else {
+ ret = STMF_ERROR_NOT_FOUND;
+ }
+ } else {
+ ret = STMF_ERROR_NOT_FOUND;
+ }
+ stmfFreeMemory(viewEntryList);
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnit:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ bcopy(fLuProps.lu_provider_name, luProps->providerName,
+ sizeof (fLuProps.lu_provider_name));
+ if (fLuProps.lu_state == STMF_STATE_ONLINE) {
+ luProps->status = STMF_LOGICAL_UNIT_ONLINE;
+ } else if (fLuProps.lu_state == STMF_STATE_OFFLINE) {
+ luProps->status = STMF_LOGICAL_UNIT_OFFLINE;
+ } else if (fLuProps.lu_state == STMF_STATE_ONLINING) {
+ luProps->status = STMF_LOGICAL_UNIT_ONLINING;
+ } else if (fLuProps.lu_state == STMF_STATE_OFFLINING) {
+ luProps->status = STMF_LOGICAL_UNIT_OFFLINING;
+ }
+ bcopy(fLuProps.lu_alias, luProps->alias, sizeof (luProps->alias));
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfGetState
+ *
+ * Purpose: retrieve the current state of the stmf module
+ *
+ * state - pointer to stmfState structure allocated by the caller
+ * On success, contains the state of stmf
+ */
+int
+stmfGetState(stmfState *state)
+{
+ int ret;
+ stmf_state_desc_t iState;
+
+ if (state == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ ret = getStmfState(&iState);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ switch (iState.state) {
+ case STMF_STATE_ONLINE:
+ state->operationalState =
+ STMF_SERVICE_STATE_ONLINE;
+ break;
+ case STMF_STATE_OFFLINE:
+ state->operationalState =
+ STMF_SERVICE_STATE_OFFLINE;
+ break;
+ case STMF_STATE_ONLINING:
+ state->operationalState =
+ STMF_SERVICE_STATE_ONLINING;
+ break;
+ case STMF_STATE_OFFLINING:
+ state->operationalState =
+ STMF_SERVICE_STATE_OFFLINING;
+ break;
+ default:
+ state->operationalState =
+ STMF_SERVICE_STATE_UNKNOWN;
+ break;
+ }
+ switch (iState.config_state) {
+ case STMF_CONFIG_NONE:
+ state->configState = STMF_CONFIG_STATE_NONE;
+ break;
+ case STMF_CONFIG_INIT:
+ state->configState = STMF_CONFIG_STATE_INIT;
+ break;
+ case STMF_CONFIG_INIT_DONE:
+ state->configState =
+ STMF_CONFIG_STATE_INIT_DONE;
+ break;
+ default:
+ state->configState =
+ STMF_CONFIG_STATE_UNKNOWN;
+ break;
+ }
+ return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfGetViewEntryList
+ *
+ * Purpose: Retrieves the list of view entries for the specified
+ * logical unit.
+ *
+ * lu - the guid of the logical unit for which to retrieve the view entry list
+ * viewEntryList - a pointer to a pointer to a stmfViewEntryList structure. On
+ * success, contains the list of view entries.
+ */
+int
+stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
+{
+ int ret;
+ int fd;
+ int ioctlRet;
+ int cmd = STMF_IOCTL_LU_VE_LIST;
+ int i;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t *fVeList;
+ uint32_t fVeListSize;
+ uint32_t listCnt;
+
+ if (lu == NULL || viewEntryList == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Allocate ioctl input buffer
+ */
+ fVeListSize = ALLOC_VE;
+ fVeListSize = fVeListSize * (sizeof (stmf_view_op_entry_t));
+ fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
+ if (fVeList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the LU list
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
+ stmfIoctl.stmf_obuf_size = fVeListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetViewEntryList:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ /*
+ * Check whether input buffer was large enough
+ */
+ if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_VE) {
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ fVeListSize = stmfIoctl.stmf_obuf_max_nentries *
+ sizeof (stmf_view_op_entry_t);
+ free(fVeList);
+ fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
+ if (fVeList == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+ stmfIoctl.stmf_obuf_size = fVeListSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetLogicalUnitList:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ listCnt = stmfIoctl.stmf_obuf_nentries;
+
+ /*
+ * allocate caller's buffer with the final size
+ */
+ *viewEntryList = (stmfViewEntryList *)calloc(1,
+ sizeof (stmfViewEntryList) + listCnt * sizeof (stmfViewEntry));
+ if (*viewEntryList == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ (*viewEntryList)->cnt = listCnt;
+
+ /* copy to caller's buffer */
+ for (i = 0; i < listCnt; i++) {
+ (*viewEntryList)->ve[i].veIndexValid = B_TRUE;
+ (*viewEntryList)->ve[i].veIndex = fVeList[i].ve_ndx;
+ if (fVeList[i].ve_all_hosts == 1) {
+ (*viewEntryList)->ve[i].allHosts = B_TRUE;
+ } else {
+ bcopy(fVeList[i].ve_host_group.name,
+ (*viewEntryList)->ve[i].hostGroup,
+ fVeList[i].ve_host_group.name_size);
+ }
+ if (fVeList[i].ve_all_targets == 1) {
+ (*viewEntryList)->ve[i].allTargets = B_TRUE;
+ } else {
+ bcopy(fVeList[i].ve_target_group.name,
+ (*viewEntryList)->ve[i].targetGroup,
+ fVeList[i].ve_target_group.name_size);
+ }
+ bcopy(fVeList[i].ve_lu_nbr, (*viewEntryList)->ve[i].luNbr,
+ sizeof ((*viewEntryList)->ve[i].luNbr));
+ (*viewEntryList)->ve[i].luNbrValid = B_TRUE;
+ }
+
+ /*
+ * sort the list. This gives a consistent view across gets
+ */
+ qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
+ sizeof (stmfViewEntry), viewEntryCompare);
+
+done:
+ (void) close(fd);
+ /*
+ * free internal buffers
+ */
+ free(fVeList);
+ return (ret);
+}
+
+
+/*
+ * loadHostGroups
+ *
+ * Purpose - issues the ioctl to load the host groups into stmf
+ *
+ * fd - file descriptor for the control node of stmf.
+ * groupList - populated host group list
+ */
+static int
+loadHostGroups(int fd, stmfGroupList *groupList)
+{
+ int i, j;
+ int ret = STMF_STATUS_SUCCESS;
+ stmfGroupProperties *groupProps = NULL;
+
+ for (i = 0; i < groupList->cnt; i++) {
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_HOST_GROUP,
+ &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
+ &groupProps, HOST_GROUP);
+ for (j = 0; j < groupProps->cnt; j++) {
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
+ &(groupList->name[i]), &(groupProps->name[j])))
+ != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+
+out:
+ stmfFreeMemory(groupProps);
+ return (ret);
+}
+
+/*
+ * loadTargetGroups
+ *
+ * Purpose - issues the ioctl to load the target groups into stmf
+ *
+ * fd - file descriptor for the control node of stmf.
+ * groupList - populated target group list.
+ */
+static int
+loadTargetGroups(int fd, stmfGroupList *groupList)
+{
+ int i, j;
+ int ret = STMF_STATUS_SUCCESS;
+ stmfGroupProperties *groupProps = NULL;
+
+ for (i = 0; i < groupList->cnt; i++) {
+ if ((ret = groupIoctl(fd, STMF_IOCTL_CREATE_TARGET_GROUP,
+ &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
+ &groupProps, TARGET_GROUP);
+ for (j = 0; j < groupProps->cnt; j++) {
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
+ &(groupList->name[i]), &(groupProps->name[j])))
+ != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+
+out:
+ stmfFreeMemory(groupProps);
+ return (ret);
+}
+
+
+/*
+ * loadStore
+ *
+ * Purpose: Load the configuration data from the store
+ *
+ * First load the host groups and target groups, then the view entries
+ * and finally the provider data
+ *
+ * fd - file descriptor of control node for stmf.
+ */
+static int
+loadStore(int fd)
+{
+ int ret;
+ int i, j;
+ stmfGroupList *groupList = NULL;
+ stmfGuidList *guidList = NULL;
+ stmfViewEntryList *viewEntryList = NULL;
+ stmfProviderList *providerList = NULL;
+ int providerType;
+ nvlist_t *nvl = NULL;
+
+
+
+ /* load host groups */
+ ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ ret = loadHostGroups(fd, groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ stmfFreeMemory(groupList);
+ groupList = NULL;
+
+ /* load target groups */
+ ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ ret = loadTargetGroups(fd, groupList);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ stmfFreeMemory(groupList);
+ groupList = NULL;
+
+ /* Get the guid list */
+ ret = psGetLogicalUnitList(&guidList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * We have the guid list, now get the corresponding
+ * view entries for each guid
+ */
+ for (i = 0; i < guidList->cnt; i++) {
+ ret = psGetViewEntryList(&guidList->guid[i], &viewEntryList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ for (j = 0; j < viewEntryList->cnt; j++) {
+ ret = addViewEntryIoctl(fd, &guidList->guid[i],
+ &viewEntryList->ve[j]);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+ }
+ }
+
+ /* get the list of providers that have data */
+ ret = psGetProviderDataList(&providerList);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ for (i = 0; i < providerList->cnt; i++) {
+ providerType = providerList->provider[i].providerType;
+ ret = psGetProviderData(providerList->provider[i].name,
+ &nvl, providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ /* call setProviderData */
+ ret = setProviderData(fd, providerList->provider[i].name, nvl,
+ providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ nvlist_free(nvl);
+ nvl = NULL;
+ }
+out:
+ if (groupList != NULL) {
+ free(groupList);
+ }
+ if (guidList != NULL) {
+ free(guidList);
+ }
+ if (viewEntryList != NULL) {
+ free(viewEntryList);
+ }
+ if (nvl != NULL) {
+ nvlist_free(nvl);
+ }
+ return (ret);
+}
+
+/*
+ * stmfGetAluaState
+ *
+ * Purpose - Get the alua state
+ *
+ */
+int
+stmfGetAluaState(boolean_t *enabled, uint32_t *node)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ stmf_iocdata_t stmfIoctl = {0};
+ stmf_alua_state_desc_t alua_state = {0};
+ int ioctlRet;
+
+ if (enabled == NULL || node == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_obuf_size = sizeof (alua_state);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&alua_state;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_ALUA_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ } else {
+ if (alua_state.alua_state == 1) {
+ *enabled = B_TRUE;
+ } else {
+ *enabled = B_FALSE;
+ }
+ *node = alua_state.alua_node;
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfSetAluaState
+ *
+ * Purpose - set the alua state to enabled/disabled
+ *
+ */
+int
+stmfSetAluaState(boolean_t enabled, uint32_t node)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ stmf_iocdata_t stmfIoctl = {0};
+ stmf_alua_state_desc_t alua_state = {0};
+ int ioctlRet;
+
+ if ((enabled != B_TRUE && enabled != B_FALSE) || (node > 1)) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (enabled) {
+ alua_state.alua_state = 1;
+ }
+
+ alua_state.alua_node = node;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (alua_state);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&alua_state;
+ ioctlRet = ioctl(fd, STMF_IOCTL_SET_ALUA_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+ if (!enabled && ret == STMF_STATUS_SUCCESS) {
+ deleteNonActiveLus();
+ }
+
+ return (ret);
+}
+
+static void
+deleteNonActiveLus()
+{
+ int stmfRet;
+ int i;
+ stmfGuidList *luList;
+ luResource hdl = NULL;
+ char propVal[10];
+ size_t propValSize = sizeof (propVal);
+
+ stmfRet = stmfGetLogicalUnitList(&luList);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ return;
+ }
+
+ for (i = 0; i < luList->cnt; i++) {
+ stmfRet = stmfGetLuResource(&luList->guid[i], &hdl);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ goto err;
+ }
+ stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_ACCESS_STATE, propVal,
+ &propValSize);
+ if (stmfRet != STMF_STATUS_SUCCESS) {
+ goto err;
+ }
+ if (propVal[0] == '0') {
+ (void) stmfFreeLuResource(hdl);
+ hdl = NULL;
+ continue;
+ }
+ (void) stmfDeleteLu(&luList->guid[i]);
+ (void) stmfFreeLuResource(hdl);
+ hdl = NULL;
+ }
+
+err:
+ stmfFreeMemory(luList);
+ (void) stmfFreeLuResource(hdl);
+}
+
+/*
+ * stmfLoadConfig
+ *
+ * Purpose - load the configuration data from smf into stmf
+ *
+ */
+int
+stmfLoadConfig(void)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ stmf_state_desc_t stmfStateSet;
+ stmfState state;
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
+ != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+ /*
+ * Configuration not stored persistently; nothing to
+ * initialize so do not set to STMF_CONFIG_INIT.
+ */
+ stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
+ goto done;
+ }
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState != STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+
+
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+ stmfStateSet.config_state = STMF_CONFIG_INIT;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ /* Load the persistent configuration data */
+ ret = loadStore(fd);
+ if (ret != 0) {
+ goto done;
+ }
+
+ stmfStateSet.state = STMF_STATE_OFFLINE;
+ stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
+
+done:
+ if (ret == STMF_STATUS_SUCCESS) {
+ ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+ }
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * getStmfState
+ *
+ * stmfState - pointer to stmf_state_desc_t structure. Will contain the state
+ * information of the stmf service on success.
+ */
+static int
+getStmfState(stmf_state_desc_t *stmfState)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to get the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
+ stmfIoctl.stmf_obuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)stmfState;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_STMF_STATE, &stmfIoctl);
+
+ (void) close(fd);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+ return (ret);
+}
+
+
+/*
+ * setStmfState
+ *
+ * stmfState - pointer to caller set state structure
+ * objectType - one of:
+ * LOGICAL_UNIT_TYPE
+ * TARGET_TYPE
+ * STMF_SERVICE_TYPE
+ */
+static int
+setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ int cmd;
+ stmf_iocdata_t stmfIoctl;
+
+ switch (objectType) {
+ case LOGICAL_UNIT_TYPE:
+ cmd = STMF_IOCTL_SET_LU_STATE;
+ break;
+ case TARGET_TYPE:
+ cmd = STMF_IOCTL_SET_TARGET_PORT_STATE;
+ break;
+ case STMF_SERVICE_TYPE:
+ cmd = STMF_IOCTL_SET_STMF_STATE;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to set the stmf state
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_state_desc_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)stmfState;
+ ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setStmfState:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+done:
+ return (ret);
+}
+int
+stmfSetStmfProp(uint8_t propType, char *propVal)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE:
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ ret = psSetStmfProp(propType, propVal);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfSetStmfProp:psSetStmfProp:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ return (ret);
+}
+
+
+int
+stmfGetStmfProp(uint8_t propType, char *propVal, size_t *propLen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ char prop[MAXNAMELEN] = {0};
+ size_t reqLen;
+
+ if (propVal == NULL || propLen == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE:
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE:
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ ret = psGetStmfProp(propType, prop);
+ if ((reqLen = strlcpy(propVal, prop, *propLen)) >= *propLen) {
+ *propLen = reqLen + 1;
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfGetStmfProp:psGetStmfProp:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ return (ret);
+}
+
+static int
+setStmfProp(stmf_set_props_t *stmf_set_props)
+{
+ char propVal[MAXNAMELEN] = {0};
+ int ret;
+ if ((ret = psGetStmfProp(STMF_DEFAULT_LU_STATE, propVal)) ==
+ STMF_PS_SUCCESS) {
+ if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
+ stmf_set_props->default_lu_state_value =
+ STMF_STATE_OFFLINE;
+ } else {
+ stmf_set_props->default_lu_state_value =
+ STMF_STATE_ONLINE;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "DefaultLuState:psSetStmfProp:error(%d)", ret);
+ goto done;
+ }
+
+ if ((ret = psGetStmfProp(STMF_DEFAULT_TARGET_PORT_STATE, propVal)) ==
+ STMF_PS_SUCCESS) {
+ if (strncmp(propVal, "offline", strlen(propVal)) == 0) {
+ stmf_set_props->default_target_state_value =
+ STMF_STATE_OFFLINE;
+ } else {
+ stmf_set_props->default_target_state_value =
+ STMF_STATE_ONLINE;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "DefaultTargetPortState:psSetStmfProp:error(%d)", ret);
+ goto done;
+ }
+done:
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ return (ret);
+}
+
+static int
+loadStmfProp(int fd)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl = {0};
+ stmf_set_props_t *stmf_set_props = NULL;
+
+ stmf_set_props = (stmf_set_props_t *)
+ calloc(1, (sizeof (stmf_set_props_t)));
+ if (stmf_set_props == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+ }
+
+ /* Loading the default property values from smf */
+
+ if ((ret = setStmfProp(stmf_set_props)) != STMF_STATUS_SUCCESS)
+ goto done;
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_set_props_t);
+ stmfIoctl.stmf_ibuf =
+ (uint64_t)(unsigned long)stmf_set_props;
+
+ ioctlRet = ioctl(fd, STMF_IOCTL_SET_STMF_PROPS,
+ &stmfIoctl);
+
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setDefaultStmfState:"
+ "ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+done:
+ if (stmf_set_props != NULL) {
+ free(stmf_set_props);
+ }
+ return (ret);
+}
+
+int
+stmfLoadStmfProps(void)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ /* open control node for stmf */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
+ != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+ ret = loadStmfProp(fd);
+
+ (void) close(fd);
+done:
+ if (ret != STMF_STATUS_SUCCESS) {
+ syslog(LOG_DEBUG,
+ "stmfLoadStmfProps:Failed");
+ }
+ return (ret);
+}
+
+/*
+ * stmfOnline
+ *
+ * Purpose: Online stmf service
+ *
+ */
+int
+stmfOnline(void)
+{
+ int ret;
+ int fd;
+ stmfState state;
+ stmf_state_desc_t iState;
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState == STMF_SERVICE_STATE_ONLINE) {
+ return (STMF_ERROR_SERVICE_ONLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+ iState.state = STMF_STATE_ONLINE;
+ iState.config_state = STMF_CONFIG_NONE;
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOffline
+ *
+ * Purpose: Offline stmf service
+ *
+ */
+int
+stmfOffline(void)
+{
+ int ret;
+ int fd;
+ stmfState state;
+ stmf_state_desc_t iState;
+
+ ret = stmfGetState(&state);
+ if (ret == STMF_STATUS_SUCCESS) {
+ if (state.operationalState == STMF_SERVICE_STATE_OFFLINE) {
+ return (STMF_ERROR_SERVICE_OFFLINE);
+ }
+ } else {
+ return (STMF_STATUS_ERROR);
+ }
+ iState.state = STMF_STATE_OFFLINE;
+ iState.config_state = STMF_CONFIG_NONE;
+
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &iState, STMF_SERVICE_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+
+/*
+ * stmfOfflineTarget
+ *
+ * Purpose: Change state of target to offline
+ *
+ * devid - devid of the target to offline
+ */
+int
+stmfOfflineTarget(stmfDevid *devid)
+{
+ stmf_state_desc_t targetState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (devid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bzero(&targetState, sizeof (targetState));
+
+ targetState.state = STMF_STATE_OFFLINE;
+ targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &targetState, TARGET_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOfflineLogicalUnit
+ *
+ * Purpose: Change state of logical unit to offline
+ *
+ * lu - guid of the logical unit to offline
+ */
+int
+stmfOfflineLogicalUnit(stmfGuid *lu)
+{
+ stmf_state_desc_t luState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(&luState, sizeof (luState));
+
+ luState.state = STMF_STATE_OFFLINE;
+ bcopy(lu, &luState.ident, sizeof (stmfGuid));
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOnlineTarget
+ *
+ * Purpose: Change state of target to online
+ *
+ * devid - devid of the target to online
+ */
+int
+stmfOnlineTarget(stmfDevid *devid)
+{
+ stmf_state_desc_t targetState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (devid == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ bzero(&targetState, sizeof (targetState));
+
+ targetState.state = STMF_STATE_ONLINE;
+ targetState.ident[IDENT_LENGTH_BYTE] = devid->identLength;
+ bcopy(&(devid->ident), &targetState.ident[IDENT_LENGTH_BYTE + 1],
+ devid->identLength);
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &targetState, TARGET_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfOnlineLogicalUnit
+ *
+ * Purpose: Change state of logical unit to online
+ *
+ * lu - guid of the logical unit to online
+ */
+int
+stmfOnlineLogicalUnit(stmfGuid *lu)
+{
+ stmf_state_desc_t luState;
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ bzero(&luState, sizeof (luState));
+
+ luState.state = STMF_STATE_ONLINE;
+ bcopy(lu, &luState.ident, sizeof (stmfGuid));
+ /*
+ * Open control node for stmf
+ * to make call to setStmfState()
+ */
+ if ((ret = openStmf(OPEN_EXCL_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+ ret = setStmfState(fd, &luState, LOGICAL_UNIT_TYPE);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveFromHostGroup
+ *
+ * Purpose: Removes an initiator from an initiator group
+ *
+ * hostGroupName - name of an initiator group
+ * hostName - name of host group member to remove
+ */
+int
+stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
+{
+ int ret;
+ int fd;
+
+ if (hostGroupName == NULL ||
+ (strnlen((char *)hostGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || hostName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_HG_ENTRY,
+ hostGroupName, hostName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psRemoveHostGroupMember((char *)hostGroupName,
+ (char *)hostName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_MEMBER_NOT_FOUND:
+ ret = STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveFromHostGroup"
+ "psRemoveHostGroupMember:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveFromTargetGroup
+ *
+ * Purpose: Removes a local port from a local port group
+ *
+ * targetGroupName - name of a target group
+ * targetName - name of target to remove
+ */
+int
+stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
+{
+ int ret;
+ int fd;
+
+ if (targetGroupName == NULL ||
+ (strnlen((char *)targetGroupName, sizeof (stmfGroupName))
+ == sizeof (stmfGroupName)) || targetName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ if ((ret = groupMemberIoctl(fd, STMF_IOCTL_REMOVE_TG_ENTRY,
+ targetGroupName, targetName)) != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psRemoveTargetGroupMember((char *)targetGroupName,
+ (char *)targetName->ident);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_MEMBER_NOT_FOUND:
+ ret = STMF_ERROR_MEMBER_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_GROUP_NOT_FOUND:
+ ret = STMF_ERROR_GROUP_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveFromTargetGroup"
+ "psRemoveTargetGroupMember:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfRemoveViewEntry
+ *
+ * Purpose: Removes a view entry from a logical unit
+ *
+ * lu - guid of lu for which view entry is being removed
+ * viewEntryIndex - index of view entry to remove
+ *
+ */
+int
+stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ if (lu == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ ioctlViewEntry.ve_ndx_valid = B_TRUE;
+ ioctlViewEntry.ve_ndx = viewEntryIndex;
+ bcopy(lu, &ioctlViewEntry.ve_guid, sizeof (stmfGuid));
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to add to the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_REMOVE_VIEW_ENTRY, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ case ENODEV:
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveViewEntry:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ ret = psRemoveViewEntry(lu, viewEntryIndex);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_NOT_FOUND:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfRemoveViewEntry" "psRemoveViewEntry:error(%d)",
+ ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * stmfSetProviderData
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - type of provider for which to set data
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ */
+int
+stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType)
+{
+ return (stmfSetProviderDataProt(providerName, nvl, providerType,
+ NULL));
+}
+
+/*
+ * stmfSetProviderDataProt
+ *
+ * Purpose: set the provider data
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - type of provider for which to set data
+ * STMF_LU_PROVIDER_TYPE
+ * STMF_PORT_PROVIDER_TYPE
+ * setToken - Stale data token returned in the stmfGetProviderDataProt()
+ * call or NULL.
+ */
+int
+stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret;
+ int fd;
+
+ if (providerName == NULL || nvl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ if (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ ret = setProviderData(fd, providerName, nvl, providerType, setToken);
+
+ (void) close(fd);
+
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
+ }
+
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
+ /* setting driver provider data successful. Now persist it */
+ ret = psSetProviderData(providerName, nvl, providerType, NULL);
+ switch (ret) {
+ case STMF_PS_SUCCESS:
+ ret = STMF_STATUS_SUCCESS;
+ break;
+ case STMF_PS_ERROR_EXISTS:
+ ret = STMF_ERROR_EXISTS;
+ break;
+ case STMF_PS_ERROR_BUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case STMF_PS_ERROR_SERVICE_NOT_FOUND:
+ ret = STMF_ERROR_SERVICE_NOT_FOUND;
+ break;
+ case STMF_PS_ERROR_VERSION_MISMATCH:
+ ret = STMF_ERROR_SERVICE_DATA_VERSION;
+ break;
+ case STMF_PS_ERROR_PROV_DATA_STALE:
+ ret = STMF_ERROR_PROV_DATA_STALE;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "stmfSetProviderData"
+ "psSetProviderData:error(%d)", ret);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+
+done:
+ return (ret);
+}
+
+/*
+ * getProviderData
+ *
+ * Purpose: set the provider data from stmf
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to load/retrieve
+ * providerType - logical unit or port provider
+ * setToken - returned stale data token
+ */
+int
+getProviderData(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int fd;
+ int ioctlRet;
+ size_t nvlistSize = ALLOC_PP_DATA_SIZE;
+ int retryCnt = 0;
+ int retryCntMax = MAX_PROVIDER_RETRY;
+ stmf_ppioctl_data_t ppi = {0}, *ppi_out = NULL;
+ boolean_t retry = B_TRUE;
+ stmf_iocdata_t stmfIoctl;
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /* set provider name and provider type */
+ if (strlcpy(ppi.ppi_name, providerName,
+ sizeof (ppi.ppi_name)) >=
+ sizeof (ppi.ppi_name)) {
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi.ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi.ppi_port_provider = 1;
+ break;
+ default:
+ ret = STMF_ERROR_INVALID_ARG;
+ goto done;
+ }
+
+ do {
+ /* allocate memory for ioctl */
+ ppi_out = (stmf_ppioctl_data_t *)calloc(1, nvlistSize +
+ sizeof (stmf_ppioctl_data_t));
+ if (ppi_out == NULL) {
+ ret = STMF_ERROR_NOMEM;
+ goto done;
+
+ }
+
+ /* set the size of the ioctl data to allocated buffer */
+ ppi.ppi_data_size = nvlistSize;
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
+ stmfIoctl.stmf_obuf_size = sizeof (stmf_ppioctl_data_t) +
+ nvlistSize;
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)ppi_out;
+ ioctlRet = ioctl(fd, STMF_IOCTL_GET_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EINVAL:
+ if (stmfIoctl.stmf_error ==
+ STMF_IOCERR_INSUFFICIENT_BUF) {
+ nvlistSize =
+ ppi_out->ppi_data_size;
+ free(ppi_out);
+ ppi_out = NULL;
+ if (retryCnt++ > retryCntMax) {
+ retry = B_FALSE;
+ ret = STMF_ERROR_BUSY;
+ } else {
+ ret =
+ STMF_STATUS_SUCCESS;
+ }
+ } else {
+ syslog(LOG_DEBUG,
+ "getProviderData:ioctl"
+ "unable to retrieve "
+ "nvlist");
+ ret = STMF_STATUS_ERROR;
+ }
+ break;
+ case ENOENT:
+ ret = STMF_ERROR_NOT_FOUND;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "getProviderData:ioctl errno(%d)",
+ errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS)
+ goto done;
+ }
+ } while (retry && stmfIoctl.stmf_error == STMF_IOCERR_INSUFFICIENT_BUF);
+
+ if ((ret = nvlist_unpack((char *)ppi_out->ppi_data,
+ ppi_out->ppi_data_size, nvl, 0)) != 0) {
+ ret = STMF_STATUS_ERROR;
+ goto done;
+ }
+
+ /* caller has asked for new token */
+ if (setToken) {
+ *setToken = ppi_out->ppi_token;
+ }
+done:
+ free(ppi_out);
+ (void) close(fd);
+ return (ret);
+}
+
+/*
+ * setProviderData
+ *
+ * Purpose: set the provider data in stmf
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to set
+ * providerType - logical unit or port provider
+ * setToken - stale data token to check if not NULL
+ */
+static int
+setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ size_t nvlistEncodedSize;
+ stmf_ppioctl_data_t *ppi = NULL;
+ uint64_t outToken;
+ char *allocatedNvBuffer;
+ stmf_iocdata_t stmfIoctl;
+
+ if (providerName == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* get size of encoded nvlist */
+ if (nvlist_size(nvl, &nvlistEncodedSize, NV_ENCODE_XDR) != 0) {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* allocate memory for ioctl */
+ ppi = (stmf_ppioctl_data_t *)calloc(1, nvlistEncodedSize +
+ sizeof (stmf_ppioctl_data_t));
+ if (ppi == NULL) {
+ return (STMF_ERROR_NOMEM);
+ }
+
+ if (setToken) {
+ ppi->ppi_token_valid = 1;
+ ppi->ppi_token = *setToken;
+ }
+
+ allocatedNvBuffer = (char *)&ppi->ppi_data;
+ if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
+ NV_ENCODE_XDR, 0) != 0) {
+ return (STMF_STATUS_ERROR);
+ }
+
+ /* set provider name and provider type */
+ (void) strncpy(ppi->ppi_name, providerName, sizeof (ppi->ppi_name));
+ switch (providerType) {
+ case STMF_LU_PROVIDER_TYPE:
+ ppi->ppi_lu_provider = 1;
+ break;
+ case STMF_PORT_PROVIDER_TYPE:
+ ppi->ppi_port_provider = 1;
+ break;
+ default:
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* set the size of the ioctl data to packed data size */
+ ppi->ppi_data_size = nvlistEncodedSize;
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ /*
+ * Subtracting 8 from the size as that is the size of the last member
+ * of the structure where the packed data resides
+ */
+ stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
+ sizeof (stmf_ppioctl_data_t) - 8;
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
+ stmfIoctl.stmf_obuf_size = sizeof (uint64_t);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&outToken;
+ ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EINVAL:
+ if (stmfIoctl.stmf_error ==
+ STMF_IOCERR_PPD_UPDATED) {
+ ret = STMF_ERROR_PROV_DATA_STALE;
+ } else {
+ ret = STMF_STATUS_ERROR;
+ }
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "setProviderData:ioctl errno(%d)", errno);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ if (ret != STMF_STATUS_SUCCESS)
+ goto done;
+ }
+
+ /* caller has asked for new token */
+ if (setToken) {
+ *setToken = outToken;
+ }
+done:
+ free(ppi);
+ return (ret);
+}
+
+/*
+ * set the persistence method in the library only or library and service
+ */
+int
+stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int oldPersist;
+
+ (void) pthread_mutex_lock(&persistenceTypeLock);
+ oldPersist = iPersistType;
+ if (persistType == STMF_PERSIST_NONE ||
+ persistType == STMF_PERSIST_SMF) {
+ iLibSetPersist = B_TRUE;
+ iPersistType = persistType;
+ } else {
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ /* Is this for this library open or in SMF */
+ if (serviceSet == B_TRUE) {
+ ret = psSetServicePersist(persistType);
+ if (ret != STMF_PS_SUCCESS) {
+ ret = STMF_ERROR_PERSIST_TYPE;
+ /* Set to old value */
+ iPersistType = oldPersist;
+ }
+ }
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+
+ return (ret);
+}
+
+/*
+ * Only returns internal state for persist. If unset, goes to ps. If that
+ * fails, returns default setting
+ */
+static uint8_t
+iGetPersistMethod()
+{
+
+ uint8_t persistType = 0;
+
+ (void) pthread_mutex_lock(&persistenceTypeLock);
+ if (iLibSetPersist) {
+ persistType = iPersistType;
+ } else {
+ int ret;
+ ret = psGetServicePersist(&persistType);
+ if (ret != STMF_PS_SUCCESS) {
+ /* set to default */
+ persistType = STMF_DEFAULT_PERSIST;
+ }
+ }
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+ return (persistType);
+}
+
+/*
+ * Returns either library state or persistent config state depending on
+ * serviceState
+ */
+int
+stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState)
+{
+ int ret = STMF_STATUS_SUCCESS;
+
+ if (persistType == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+ if (serviceState) {
+ ret = psGetServicePersist(persistType);
+ if (ret != STMF_PS_SUCCESS) {
+ ret = STMF_ERROR_PERSIST_TYPE;
+ }
+ } else {
+ (void) pthread_mutex_lock(&persistenceTypeLock);
+ if (iLibSetPersist) {
+ *persistType = iPersistType;
+ } else {
+ *persistType = STMF_DEFAULT_PERSIST;
+ }
+ (void) pthread_mutex_unlock(&persistenceTypeLock);
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfPostProxyMsg
+ *
+ * Purpose: Post a message to the proxy port provider
+ *
+ * buf - buffer containing message to post
+ * buflen - buffer length
+ */
+int
+stmfPostProxyMsg(int hdl, void *buf, uint32_t buflen)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ pppt_iocdata_t ppptIoctl = {0};
+
+ if (buf == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Issue ioctl to post the message
+ */
+ ppptIoctl.pppt_version = PPPT_VERSION_1;
+ ppptIoctl.pppt_buf_size = buflen;
+ ppptIoctl.pppt_buf = (uint64_t)(unsigned long)buf;
+ ioctlRet = ioctl(hdl, PPPT_MESSAGE, &ppptIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ default:
+ ret = STMF_ERROR_POST_MSG_FAILED;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * stmfInitProxyDoor
+ *
+ * Purpose: Install door in proxy
+ *
+ * hdl - pointer to returned handle
+ * fd - door from door_create()
+ */
+int
+stmfInitProxyDoor(int *hdl, int door)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ int fd;
+ pppt_iocdata_t ppptIoctl = {0};
+
+ if (hdl == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /*
+ * Open control node for pppt
+ */
+ if ((ret = openPppt(OPEN_PPPT, &fd)) != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Issue ioctl to install the door
+ */
+ ppptIoctl.pppt_version = PPPT_VERSION_1;
+ ppptIoctl.pppt_door_fd = (uint32_t)door;
+ ioctlRet = ioctl(fd, PPPT_INSTALL_DOOR, &ppptIoctl);
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EINVAL:
+ ret = STMF_ERROR_INVALID_ARG;
+ break;
+ case EBUSY:
+ ret = STMF_ERROR_DOOR_INSTALLED;
+ break;
+ default:
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ }
+
+ /* return driver fd to caller */
+ *hdl = fd;
+ return (ret);
+}
+
+void
+stmfDestroyProxyDoor(int hdl)
+{
+ (void) close(hdl);
+}
+
+/*
+ * validateLunNumIoctl
+ *
+ * Purpose: Issues ioctl to check and get available lun# in view entry
+ *
+ * viewEntry - view entry to use
+ */
+static int
+validateLunNumIoctl(int fd, stmfViewEntry *viewEntry)
+{
+ int ret = STMF_STATUS_SUCCESS;
+ int ioctlRet;
+ stmf_iocdata_t stmfIoctl;
+ stmf_view_op_entry_t ioctlViewEntry;
+
+ bzero(&ioctlViewEntry, sizeof (ioctlViewEntry));
+ /*
+ * don't set ve_ndx or ve_ndx_valid as ve_ndx_valid should be
+ * false on input
+ */
+ ioctlViewEntry.ve_lu_number_valid = viewEntry->luNbrValid;
+ ioctlViewEntry.ve_all_hosts = viewEntry->allHosts;
+ ioctlViewEntry.ve_all_targets = viewEntry->allTargets;
+
+ if (viewEntry->allHosts == B_FALSE) {
+ bcopy(viewEntry->hostGroup, &ioctlViewEntry.ve_host_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_host_group.name_size =
+ strlen((char *)viewEntry->hostGroup);
+ }
+ if (viewEntry->allTargets == B_FALSE) {
+ bcopy(viewEntry->targetGroup,
+ &ioctlViewEntry.ve_target_group.name,
+ sizeof (stmfGroupName));
+ ioctlViewEntry.ve_target_group.name_size =
+ strlen((char *)viewEntry->targetGroup);
+ }
+ /* Validating the lun number */
+ if (viewEntry->luNbrValid) {
+ bcopy(viewEntry->luNbr, &ioctlViewEntry.ve_lu_nbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+
+ bzero(&stmfIoctl, sizeof (stmfIoctl));
+ /*
+ * Issue ioctl to validate lun# in the view entry
+ */
+ stmfIoctl.stmf_version = STMF_VERSION_1;
+ stmfIoctl.stmf_ibuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ stmfIoctl.stmf_obuf_size = sizeof (ioctlViewEntry);
+ stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&ioctlViewEntry;
+ ioctlRet = ioctl(fd, STMF_IOCTL_VALIDATE_VIEW, &stmfIoctl);
+
+ /* save available lun number */
+ if (!viewEntry->luNbrValid) {
+ bcopy(ioctlViewEntry.ve_lu_nbr, viewEntry->luNbr,
+ sizeof (ioctlViewEntry.ve_lu_nbr));
+ }
+ if (ioctlRet != 0) {
+ switch (errno) {
+ case EBUSY:
+ ret = STMF_ERROR_BUSY;
+ break;
+ case EPERM:
+ ret = STMF_ERROR_PERM;
+ break;
+ case EACCES:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ default:
+ ret = STMF_ERROR_PERM;
+ break;
+ }
+ break;
+ default:
+ switch (stmfIoctl.stmf_error) {
+ case STMF_IOCERR_LU_NUMBER_IN_USE:
+ ret = STMF_ERROR_LUN_IN_USE;
+ break;
+ case STMF_IOCERR_VIEW_ENTRY_CONFLICT:
+ ret = STMF_ERROR_VE_CONFLICT;
+ break;
+ case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
+ ret = STMF_ERROR_CONFIG_NONE;
+ break;
+ case STMF_IOCERR_INVALID_HG:
+ ret = STMF_ERROR_INVALID_HG;
+ break;
+ case STMF_IOCERR_INVALID_TG:
+ ret = STMF_ERROR_INVALID_TG;
+ break;
+ default:
+ syslog(LOG_DEBUG,
+ "addViewEntryIoctl"
+ ":error(%d)",
+ stmfIoctl.stmf_error);
+ ret = STMF_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * stmfValidateView
+ *
+ * Purpose: Validate or get lun # base on TG, HG of view entry
+ *
+ * viewEntry - view entry structure to use
+ */
+int
+stmfValidateView(stmfViewEntry *viewEntry)
+{
+ int ret;
+ int fd;
+ stmfViewEntry iViewEntry;
+
+ if (viewEntry == NULL) {
+ return (STMF_ERROR_INVALID_ARG);
+ }
+
+ /* initialize and set internal view entry */
+ bzero(&iViewEntry, sizeof (iViewEntry));
+
+ if (!viewEntry->allHosts) {
+ bcopy(viewEntry->hostGroup, iViewEntry.hostGroup,
+ sizeof (iViewEntry.hostGroup));
+ } else {
+ iViewEntry.allHosts = B_TRUE;
+ }
+
+ if (!viewEntry->allTargets) {
+ bcopy(viewEntry->targetGroup, iViewEntry.targetGroup,
+ sizeof (iViewEntry.targetGroup));
+ } else {
+ iViewEntry.allTargets = B_TRUE;
+ }
+
+ if (viewEntry->luNbrValid) {
+ iViewEntry.luNbrValid = B_TRUE;
+ bcopy(viewEntry->luNbr, iViewEntry.luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ /*
+ * set users return view entry index valid flag to false
+ * in case of failure
+ */
+ viewEntry->veIndexValid = B_FALSE;
+
+ /* Check to ensure service exists */
+ if (psCheckService() != STMF_STATUS_SUCCESS) {
+ return (STMF_ERROR_SERVICE_NOT_FOUND);
+ }
+
+ /* call init */
+ ret = initializeConfig();
+ if (ret != STMF_STATUS_SUCCESS) {
+ return (ret);
+ }
+
+ /*
+ * Open control node for stmf
+ */
+ if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+ return (ret);
+
+ /*
+ * Validate lun# in the view entry from the driver
+ */
+ ret = validateLunNumIoctl(fd, &iViewEntry);
+ (void) close(fd);
+
+ /* save available lun number */
+ if (!viewEntry->luNbrValid) {
+ bcopy(iViewEntry.luNbr, viewEntry->luNbr,
+ sizeof (iViewEntry.luNbr));
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libstmf/common/store.c b/usr/src/lib/libstmf/common/store.c
new file mode 100644
index 0000000..b6eabd8
--- /dev/null
+++ b/usr/src/lib/libstmf/common/store.c
@@ -0,0 +1,5385 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ */
+
+#include <libscf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <strings.h>
+#include <libstmf.h>
+#include <store.h>
+#include <syslog.h>
+#include <signal.h>
+#include <pthread.h>
+#include <libnvpair.h>
+#include <limits.h>
+#include <unistd.h>
+
+/*
+ * This file's functions are responsible for all store and retrieve operations
+ * against the STMF smf(5) database. The following shows the currently defined
+ * schema for the STMF database:
+ *
+ * Description of property groups for service: svc:/system/stmf
+ *
+ * Stability: Volatile
+ *
+ * 1. Property Group: host_groups
+ * Properties: group_name-<N> where <N> is an unsigned integer
+ * type: ustring
+ * contains: group name
+ * group_name-<N>-member_list where <N> is an unsigned
+ * integer matching a group_name-<N> property.
+ * type: ustring
+ * contains: list of members
+ *
+ * Description:
+ * Contains the host group names as well as the host group members
+ * for each host group.
+ *
+ * 2. Property Group: target_groups
+ * Properties: group_name-<N> where <N> is an unsigned integer
+ * type: ustring
+ * contains: group name
+ * group_name-<N>-member_list where <N> is an unsigned
+ * integer matching a group_name-<N> property.
+ * type: ustring
+ * contains: list of members
+ *
+ * Description:
+ * Contains the target group names as well as the target group
+ * members for each target group.
+ *
+ * 3. Property Group: lu-<GUID>
+ * where <GUID> is a 32 character hexadecimal string.
+ * Properties: ve_cnt
+ * type: count
+ * contains: the number of current view entries
+ * view-entry-<N>-<GUID> where <N> is an unsigned integer
+ * type: ustring
+ * contains: nothing. Used as reference to the view
+ * entry property group
+ *
+ * Description:
+ * Contains the references to each view entry. One lu-<GUID>
+ * property group will exist for each logical unit with 1 or more
+ * view entries.
+ * Potentially can hold any other data that can be managed on a per
+ * logical unit basis.
+ *
+ * 4. Property Group: view_entry-<N>-<GUID> (matches property in lu-<GUID>
+ * property group)
+ * Properties: all_hosts
+ * type: boolean
+ * contains: when true, the value of host_group is
+ * ignored
+ * all_targets
+ * type: boolean
+ * contains: when true, the value of target_group is
+ * ignored
+ * host_group
+ * type: ustring
+ * contains: host group for logical unit mapping and
+ * masking purposes
+ * target_group
+ * type: ustring
+ * contains: target group for logical unit mapping and
+ * masking purposes
+ * lu_nbr
+ * type: opaque
+ * contains: the 8-byte SCSI logical unit number for
+ * mapping and masking purposes
+ * Description:
+ * One "view_entry-<N>-<GUID>" property group will exist for each
+ * view entry in the system. This property group name maps
+ * directly to the "lu-<GUID>" property group with a matching
+ * <GUID>.
+ *
+ * 5. Property Group: provider_data_pg_<provider-name>
+ * where <provider-name> is the name of the provider
+ * registered with stmf.
+ * Properties: provider_data_prop-<N>
+ * where <N> is a sequential identifier for the data
+ * chunk.
+ * type: opaque
+ * contains: up to STMF_PROVIDER_DATA_PROP_SIZE bytes
+ * of nvlist packed data.
+ * provider_data_count
+ * type: count
+ * contains: the number of provider data chunks
+ * provider_data_type
+ * type: integer
+ * contains: STMF_PORT_PROVIDER_TYPE or
+ * STMF_LU_PROVIDER_TYPE
+ *
+ * Description:
+ * Holds the nvlist packed provider data set via
+ * stmfSetProviderData and retrieved via stmfGetProviderData. Data
+ * is stored in STMF_PROVIDER_DATA_PROP_SIZE chunks. On retrieve,
+ * these chunks are reassembled and unpacked.
+ *
+ */
+
+static int iPsInit(scf_handle_t **, scf_service_t **);
+static int iPsCreateDeleteGroup(char *, char *, int);
+static int iPsAddRemoveGroupMember(char *, char *, char *, int);
+static int iPsGetGroupList(char *, stmfGroupList **);
+static int iPsGetGroupMemberList(char *, char *, stmfGroupProperties **);
+static int iPsAddViewEntry(char *, char *, stmfViewEntry *);
+static int iPsAddRemoveLuViewEntry(char *, char *, int);
+static int iPsGetViewEntry(char *, stmfViewEntry *);
+static int iPsGetActualGroupName(char *, char *, char *);
+static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *);
+static int iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *,
+ int);
+static int iPsGetSetStmfProp(int, char *, int);
+static int viewEntryCompare(const void *, const void *);
+static int holdSignal(sigset_t *);
+static int releaseSignal(sigset_t *);
+static void sigHandler();
+
+static pthread_mutex_t sigSetLock = PTHREAD_MUTEX_INITIALIZER;
+
+sigset_t sigSet;
+sigset_t signalsCaught;
+
+struct sigaction currentActionQuit;
+struct sigaction currentActionTerm;
+struct sigaction currentActionInt;
+
+boolean_t actionSet = B_FALSE;
+
+/*
+ * Version info for the SMF schema
+ */
+#define STMF_SMF_VERSION 1
+
+/*
+ * Note: Do not change these property names and size values.
+ * They represent fields in the persistent config and once modified
+ * will have a nasty side effect of invalidating the existing store.
+ * If you do need to change them, you'll need to use the versioning above
+ * to retain backward compatiblity with the previous configuration schema.
+ */
+
+/* BEGIN STORE PROPERTY DEFINITIONS */
+/*
+ * Property Group Names and prefixes
+ */
+#define STMF_HOST_GROUPS "host_groups"
+#define STMF_TARGET_GROUPS "target_groups"
+#define STMF_VE_PREFIX "view_entry"
+#define STMF_LU_PREFIX "lu"
+#define STMF_DATA_GROUP "stmf_data"
+
+/*
+ * Property names and prefix for logical unit property group
+ */
+#define STMF_VE_CNT "ve_cnt"
+#define STMF_GROUP_PREFIX "group_name"
+#define STMF_MEMBER_LIST_SUFFIX "member_list"
+#define STMF_VERSION_NAME "version_name"
+#define STMF_PERSIST_TYPE "persist_method"
+
+/* Property names for stmf properties */
+
+#define DEFAULT_LU_STATE "default_lu_state"
+#define DEFAULT_TARGET_PORT_STATE "default_target_state"
+
+/*
+ * Property names for view entry
+ */
+#define STMF_VE_ALLHOSTS "all_hosts"
+#define STMF_VE_HOSTGROUP "host_group"
+#define STMF_VE_ALLTARGETS "all_targets"
+#define STMF_VE_TARGETGROUP "target_group"
+#define STMF_VE_LUNBR "lu_nbr"
+
+/* Property group suffix for provider data */
+#define STMF_PROVIDER_DATA_PREFIX "provider_data_pg_"
+#define STMF_PROVIDER_DATA_PROP_PREFIX "provider_data_prop"
+#define STMF_PROVIDER_DATA_PROP_NAME_SIZE 256
+#define STMF_PROVIDER_DATA_PROP_TYPE "provider_type"
+#define STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt"
+#define STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt"
+
+
+#define STMF_SMF_READ_ATTR "solaris.smf.read.stmf"
+
+#define STMF_PS_PERSIST_NONE "none"
+#define STMF_PS_PERSIST_SMF "smf"
+#define STMF_PROVIDER_DATA_PROP_SIZE 4000
+
+#define STMF_PS_LU_ONLINE "default_lu_online"
+#define STMF_PS_LU_OFFLINE "default_lu_offline"
+#define STMF_PS_TARGET_PORT_ONLINE "default_target_online"
+#define STMF_PS_TARGET_PORT_OFFLINE "default_target_offline"
+
+/* END STORE PROPERTY DEFINITIONS */
+
+/* service name */
+#define STMF_SERVICE "system/stmf"
+
+/* limits and flag values */
+#define GROUP_MEMBER_ALLOC 100
+#define VIEW_ENTRY_STRUCT_CNT 6
+#define VIEW_ENTRY_PG_SIZE 256
+#define LOGICAL_UNIT_PG_SIZE 256
+#define VIEW_ENTRY_MAX UINT32_MAX
+#define GROUP_MAX UINT64_MAX
+#define ADD 0
+#define REMOVE 1
+#define GET 0
+#define SET 1
+
+/*
+ * sigHandler
+ *
+ * Catch the signal and set the global signalsCaught to the signal received
+ *
+ * signalsCaught will be used by releaseSignal to raise this signal when
+ * we're done processing our critical code.
+ *
+ */
+static void
+sigHandler(int sig)
+{
+ (void) sigaddset(&signalsCaught, sig);
+}
+
+/*
+ * iPsAddRemoveGroupMember
+ *
+ * Add or remove a member for a given group
+ *
+ * pgName - Property group name
+ * groupName - group name to which the member is added/removed
+ * memberName - member to be added/removed
+ * addRemoveFlag - ADD/REMOVE
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsAddRemoveGroupMember(char *pgName, char *groupName, char *memberName,
+int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_value_t **valueSet = NULL;
+ scf_iter_t *valueIter = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ int i = 0;
+ int lastAlloc;
+ int valueArraySize = 0;
+ int ret = STMF_PS_SUCCESS;
+ char buf[STMF_IDENT_LENGTH];
+ int commitRet;
+ boolean_t found = B_FALSE;
+
+ assert(pgName != NULL && groupName != NULL && memberName != NULL);
+
+ /*
+ * Init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the service property group handle
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+
+ goto out;
+ }
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * We're changing an existing property by adding a propval
+ * There are no add semantics in libscf for a property value. We'll
+ * need to read in the current properties and apply them all to the
+ * set and then add the one we were asked to add or omit the one
+ * we were asked to remove.
+ */
+ if (scf_transaction_property_change(tran, entry, groupName,
+ SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
+ } else {
+ ret = STMF_PS_ERROR;
+ syslog(LOG_ERR, "tran property change %s/%s "
+ "failed - %s", pgName, groupName,
+ scf_strerror(scf_error()));
+ }
+ goto out;
+ }
+
+ /*
+ * Get the property handle
+ */
+ if (scf_pg_get_property(pg, groupName, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Value lookup is used to lookup the existing values
+ */
+ valueLookup = scf_value_create(handle);
+ if (valueLookup == NULL) {
+ syslog(LOG_ERR, "scf value alloc for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * valueIter is the iterator handle, create the resource
+ */
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter values for %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Allocate value resource pointers.
+ * We need a value resource for each value as value pointers passed
+ * to libscf cannot be destroyed until the commit or destroy on the
+ * transaction is done.
+ *
+ * We're using GROUP_MEMBER_ALLOC initially. If it's not large
+ * enough, we'll realloc on the fly
+ */
+ valueSet = (scf_value_t **)calloc(1, sizeof (*valueSet)
+ * (lastAlloc = GROUP_MEMBER_ALLOC));
+ if (valueSet == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * Iterate through the existing values
+ */
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ bzero(buf, sizeof (buf));
+ if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter %s/%s value failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Check for existing
+ * If we're adding, it's an error
+ * If we're removing, we skip it and simply not
+ * add it to the set. Subtraction by omission.
+ */
+ if ((strlen(buf) == strlen(memberName)) &&
+ bcmp(buf, memberName, strlen(buf)) == 0) {
+ if (addRemoveFlag == ADD) {
+ ret = STMF_PS_ERROR_EXISTS;
+ break;
+ } else {
+ found = B_TRUE;
+ continue;
+ }
+ }
+
+ /*
+ * Create the value resource for this iteration
+ */
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Set the value
+ */
+ if (scf_value_set_ustring(valueSet[i], buf) == -1) {
+ syslog(LOG_ERR, "set value for %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Now add the value
+ */
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value for %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ i++;
+
+ /*
+ * realloc if we've hit the previous alloc size
+ */
+ if (i >= lastAlloc) {
+ lastAlloc += GROUP_MEMBER_ALLOC;
+ valueSet = realloc(valueSet,
+ sizeof (*valueSet) * lastAlloc);
+ if (valueSet == NULL) {
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ }
+ }
+
+ /*
+ * set valueArraySize to final allocated length
+ * so we can use it to destroy the resources correctly
+ */
+ valueArraySize = i;
+
+ if (!found && (addRemoveFlag == REMOVE)) {
+ ret = STMF_PS_ERROR_MEMBER_NOT_FOUND;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * If we're adding, we have one more step. Add the member to the
+ * propval list
+ */
+ if (addRemoveFlag == ADD) {
+ /*
+ * Now create the new entry
+ */
+ valueSet[i] = scf_value_create(handle);
+ if (valueSet[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc for %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ valueArraySize++;
+ }
+
+ /*
+ * Set the new member name
+ */
+ if (scf_value_set_ustring(valueSet[i], memberName) == -1) {
+ syslog(LOG_ERR, "set value for %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the new member
+ */
+ if (scf_entry_add_value(entry, valueSet[i]) == -1) {
+ syslog(LOG_ERR, "add value for %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * Yes, we're finally done. We actually added or removed one entry
+ * from the list.
+ * Woohoo!
+ */
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+
+ /*
+ * Free valueSet scf resources
+ */
+ if (valueArraySize > 0) {
+ for (i = 0; i < valueArraySize; i++) {
+ scf_value_destroy(valueSet[i]);
+ }
+ }
+ /*
+ * Now free the pointer array to the resources
+ */
+ if (valueSet != NULL) {
+ free(valueSet);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsAddRemoveLuViewEntry
+ *
+ * Adds or removes a view entry name property for a given logical unit
+ * property group. There is one logical unit property group for every logical
+ * unit that has one or more associated view entries.
+ *
+ * luPgName - Property group name of logical unit
+ * viewEntryPgName - Property group name of view entry
+ * addRemoveFlag - ADD_VE/REMOVE_VE
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsAddRemoveLuViewEntry(char *luPgName, char *viewEntryPgName,
+ int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_transaction_entry_t *entryVeName = NULL;
+ boolean_t createVeCnt = B_FALSE;
+ uint64_t veCnt = 0;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ assert(luPgName != NULL || viewEntryPgName != NULL);
+ assert(!(addRemoveFlag != ADD && addRemoveFlag != REMOVE));
+
+ /*
+ * Init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* get the LU property group */
+ if (scf_service_get_pg(svc, luPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND &&
+ addRemoveFlag == ADD) {
+ /* if it doesn't exist, create it */
+ if (scf_service_add_pg(svc, luPgName,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ } else {
+ /* we need to create the VE_CNT property */
+ createVeCnt = B_TRUE;
+ ret = STMF_PS_SUCCESS;
+ }
+ } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get lu pg %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+ }
+
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+ if (createVeCnt) {
+ /*
+ * Create the STMF_VE_CNT property. This will keep the current
+ * total view entries for this logical unit.
+ */
+ if (scf_transaction_property_new(tran, entry, STMF_VE_CNT,
+ SCF_TYPE_COUNT) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new %s/%s "
+ "failed - %s", luPgName, STMF_VE_CNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ } else {
+ /*
+ * The STMF_VE_CNT property already exists. Just update
+ * it.
+ */
+ if (scf_transaction_property_change(tran, entry,
+ STMF_VE_CNT, SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR, "transaction property %s/%s change "
+ "failed - %s", luPgName, STMF_VE_CNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_VE_CNT property
+ */
+ if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_VE_CNT value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property %s/%s value failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value, &veCnt) == -1) {
+ syslog(LOG_ERR, "get count value %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Reset the value resource as it is used below
+ */
+ scf_value_reset(value);
+ }
+
+ if (addRemoveFlag == ADD) {
+ veCnt++;
+ } else {
+ /* Check if this is the last one being removed */
+ if (veCnt == 1) {
+ /*
+ * Delete the pg and get out if this is the last
+ * view entry
+ */
+ if (scf_pg_delete(pg) == -1) {
+ syslog(LOG_ERR, "delete pg %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ } else {
+ veCnt--;
+ }
+ }
+
+
+ /*
+ * Set the view entry count
+ */
+ scf_value_set_count(value, veCnt);
+
+ /*
+ * Add the value to the transaction entry
+ */
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Create a transaction entry resource for the view entry name
+ */
+ entryVeName = scf_entry_create(handle);
+ if (entryVeName == NULL) {
+ syslog(LOG_ERR, "scf transaction entry alloc %s/%s failed - %s",
+ luPgName, viewEntryPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (addRemoveFlag == ADD) {
+ /*
+ * If adding, create a property with the view entry name
+ */
+ if (scf_transaction_property_new(tran, entryVeName,
+ viewEntryPgName, SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new %s/%s "
+ "failed - %s", luPgName, viewEntryPgName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ } else {
+ /*
+ * If removing, delete the existing property with the view
+ * entry name
+ */
+ if (scf_transaction_property_delete(tran, entryVeName,
+ viewEntryPgName) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR,
+ "transaction property delete %s/%s "
+ "failed - %s", luPgName, viewEntryPgName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ }
+
+ /*
+ * Commit property transaction
+ */
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (entryVeName != NULL) {
+ scf_entry_destroy(entryVeName);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsAddViewEntry
+ *
+ * Add a view entry property group and optionally, a logical unit property
+ * group if it does not exist.
+ *
+ * luName - ascii hexadecimal logical unit identifier
+ * viewEntryName - name of view entry (VIEW_ENTRY_nn)
+ * viewEntry - pointer to stmfViewEntry structure
+ */
+static int
+iPsAddViewEntry(char *luPgName, char *viewEntryPgName, stmfViewEntry *viewEntry)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_value_t *value[VIEW_ENTRY_STRUCT_CNT];
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry[VIEW_ENTRY_STRUCT_CNT];
+ int i = 0;
+ int j = 0;
+ int ret;
+ uint8_t scfBool;
+ boolean_t createdVePg = B_FALSE;
+ int backoutRet;
+ int commitRet;
+
+ assert(luPgName != NULL || viewEntryPgName != NULL ||
+ viewEntry == NULL);
+
+ bzero(value, sizeof (value));
+ bzero(entry, sizeof (entry));
+
+ /*
+ * Init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * allocate value and entry resources for scf
+ */
+ for (i = 0; i < VIEW_ENTRY_STRUCT_CNT; i++) {
+ if (((value[i] = scf_value_create(handle)) == NULL) ||
+ ((entry[i] = scf_entry_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ i = 0;
+
+ /*
+ * Create the View Entry property group
+ */
+ if (scf_service_add_pg(svc, viewEntryPgName, SCF_GROUP_APPLICATION,
+ 0, pg) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "add pg %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ createdVePg = B_TRUE;
+
+ /*
+ * Add the view entry as properties on the view entry group
+ */
+
+ /*
+ * Begin property update transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for add %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add allHosts property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_ALLHOSTS, SCF_TYPE_BOOLEAN) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_ALLHOSTS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /* Set the allHosts value */
+ scfBool = viewEntry->allHosts;
+ scf_value_set_boolean(value[i], scfBool);
+
+ /*
+ * Add the allHosts value to the transaction
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create hostGroup property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_HOSTGROUP, SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the value for hostGroup
+ */
+ if (scf_value_set_ustring(value[i], viewEntry->hostGroup) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the hostGroup value to the transaction entry
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create the allTargets property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_ALLTARGETS, SCF_TYPE_BOOLEAN) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_ALLTARGETS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the allTargets value
+ */
+ scfBool = viewEntry->allTargets;
+ scf_value_set_boolean(value[i], scfBool);
+
+ /*
+ * Add the allTargets value to the transaction
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create targetGroup property
+ */
+ if (scf_transaction_property_new(tran, entry[i],
+ STMF_VE_TARGETGROUP, SCF_TYPE_USTRING) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", viewEntryPgName,
+ STMF_VE_TARGETGROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the value for targetGroup
+ */
+ if (scf_value_set_ustring(value[i], viewEntry->targetGroup) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add targetGroup value to the transaction
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ i++;
+
+ /*
+ * Create the luNbr property
+ */
+ if (scf_transaction_property_new(tran, entry[i], STMF_VE_LUNBR,
+ SCF_TYPE_OPAQUE) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ ret = STMF_PS_ERROR_EXISTS;
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", viewEntryPgName, STMF_VE_LUNBR,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * Set the luNbr
+ */
+ if (scf_value_set_opaque(value[i], (char *)viewEntry->luNbr,
+ sizeof (viewEntry->luNbr)) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add luNbr to the transaction entry
+ */
+ if (scf_entry_add_value(entry[i], value[i]) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now that we've successfully added the view entry,
+ * update the logical unit property group or create
+ * it if it does not exist
+ */
+ ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName, ADD);
+
+ /*
+ * If we did not add the view entry name to the logical unit,
+ * make sure we do not commit the transaction
+ */
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Commit property transaction
+ */
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for add %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ /*
+ * If we did not commit, try to remove the view entry name
+ * from the logical unit.
+ * If that fails, we're now inconsistent.
+ */
+ backoutRet = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ REMOVE);
+
+ if (backoutRet != STMF_PS_SUCCESS) {
+ syslog(LOG_ERR, "remove lu view entry %s failed"
+ "possible inconsistency - %s", luPgName,
+ scf_strerror(scf_error()));
+ }
+ /*
+ * We are still in an error scenario even though the remove
+ * lu view entry succeeded.
+ */
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ /* if there was an error, delete the created pg if one was created */
+ if ((ret != STMF_PS_SUCCESS) && createdVePg) {
+ if (scf_pg_delete(pg) == -1) {
+ syslog(LOG_ERR, "delete VE pg %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ }
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ /*
+ * Free value and entry scf resources
+ */
+ if (i > 0) {
+ for (j = 0; j < VIEW_ENTRY_STRUCT_CNT; j++) {
+ if (value[j] != NULL)
+ scf_value_destroy(value[j]);
+ if (entry[j] != NULL)
+ scf_entry_destroy(entry[j]);
+ }
+ }
+
+ return (ret);
+}
+/*
+ * psClearProviderData
+ *
+ * providerName - name of provider data to clear
+ */
+int
+psClearProviderData(char *providerName, int providerType)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char pgName[MAXPATHLEN];
+ int ret = STMF_PS_SUCCESS;
+ boolean_t pgNotFound = B_FALSE;
+
+ if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE)) {
+ ret = STMF_PS_ERROR_INVALID_ARG;
+ goto out;
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if ((pg = scf_pg_create(handle)) == NULL) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * create the property group name
+ */
+ (void) snprintf(pgName, sizeof (pgName), "%s%s",
+ STMF_PROVIDER_DATA_PREFIX, providerName);
+
+ /*
+ * delete provider property group
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ pgNotFound = B_TRUE;
+ }
+ }
+
+ if (!pgNotFound && (scf_pg_delete(pg) == -1)) {
+ syslog(LOG_ERR, "delete pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (pgNotFound) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsCreateDeleteGroup
+ *
+ * Creates or deletes a group (target or host)
+ *
+ * When creating a group, two properties are created. One to hold the group
+ * name and the other to hold the group members.
+ *
+ * pgName - Property group name
+ * groupName - group name to create
+ * addRemoveFlag - ADD_GROUP/REMOVE_GROUP
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsCreateDeleteGroup(char *pgRefName, char *groupName, int addRemoveFlag)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_iter_t *propIter = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry1 = NULL;
+ scf_transaction_entry_t *entry2 = NULL;
+ scf_value_t *value = NULL;
+ uint64_t groupIdx;
+ char buf1[MAXNAMELEN];
+ char buf2[MAXNAMELEN];
+ char tmpbuf[MAXNAMELEN];
+ boolean_t found = B_FALSE;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ assert(groupName != NULL);
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((entry1 = scf_entry_create(handle)) == NULL) ||
+ ((entry2 = scf_entry_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the property group being modified
+ */
+ if (scf_service_get_pg(svc, pgRefName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND &&
+ addRemoveFlag == ADD) {
+ if (scf_service_add_pg(svc, pgRefName,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties for %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Iterate through the group names.
+ * If we find it in the list, it's an error when addRemoveFlag == ADD.
+ */
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ if (scf_property_get_name(prop, buf1, sizeof (buf1)) == -1) {
+ syslog(LOG_ERR, "get name from %s iter failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over member list properties
+ */
+ if (strstr(buf1, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, tmpbuf,
+ sizeof (tmpbuf)) == -1) {
+ syslog(LOG_ERR, "get ustring %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ if ((strlen(tmpbuf) == strlen(groupName)) &&
+ bcmp(tmpbuf, groupName, strlen(tmpbuf)) == 0) {
+ if (addRemoveFlag == ADD) {
+ ret = STMF_PS_ERROR_EXISTS;
+ }
+ found = B_TRUE;
+ /*
+ * buf1 contains the name for REMOVE
+ */
+ break;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ scf_value_reset(value);
+
+ if (!found && addRemoveFlag == REMOVE) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ goto out;
+ }
+
+ /*
+ * If we're adding, we need to create a new property name for the
+ * new group
+ */
+ if (addRemoveFlag == ADD) {
+ for (groupIdx = 0; groupIdx < GROUP_MAX; groupIdx++) {
+ if (snprintf(buf1, sizeof (buf1), "%s-%lld",
+ STMF_GROUP_PREFIX, groupIdx) > sizeof (buf1)) {
+ syslog(LOG_ERR,
+ "buffer overflow on property name %s",
+ buf1);
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_pg_get_property(pg, buf1, prop) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get property %s/%s "
+ "failed - %s", pgRefName, buf1,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * Now create the new member list property for the new group
+ */
+ if (snprintf(buf2, sizeof (buf2), "%s-%s", buf1,
+ STMF_MEMBER_LIST_SUFFIX) > sizeof (buf2)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ buf1);
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * buf1 now contains the name of the property if it was found in the
+ * list in the case of delete or the next available property name
+ * in the case of create
+ *
+ * buf2 now contains the member list property name
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (addRemoveFlag == ADD) {
+ /*
+ * Create the property 'group name'
+ * This is the container for the group name
+ */
+ if (scf_transaction_property_new(tran, entry1, buf1,
+ SCF_TYPE_USTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", pgRefName, buf1,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (scf_value_set_ustring(value, groupName) == -1) {
+ syslog(LOG_ERR, "set ustring %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (scf_entry_add_value(entry1, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /*
+ * Create the property 'group list'
+ * This is the container for the group members
+ */
+ if (scf_transaction_property_new(tran, entry2, buf2,
+ SCF_TYPE_USTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", pgRefName, buf2,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ /*
+ * Delete the property 'group name'
+ */
+ if (scf_transaction_property_delete(tran, entry1, buf1)
+ == -1) {
+ syslog(LOG_ERR,
+ "transaction property delete %s/%s failed - %s",
+ pgRefName, buf1, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /*
+ * Delete the property 'group list'
+ */
+ if (scf_transaction_property_delete(tran, entry2, buf2)
+ == -1) {
+ syslog(LOG_ERR, "transaction property delete %s/%s "
+ "failed - %s", pgRefName, buf2,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ pgRefName, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (entry1 != NULL) {
+ scf_entry_destroy(entry1);
+ }
+ if (entry2 != NULL) {
+ scf_entry_destroy(entry2);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsGetGroupList
+ *
+ * pgName - Property group name
+ * groupList - pointer to pointer to stmfGroupList structure. On success,
+ * contains the list of groups
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetGroupList(char *pgName, stmfGroupList **groupList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_iter_t *propIter = NULL;
+ scf_value_t *value = NULL;
+ char buf[MAXNAMELEN];
+ int memberCnt = 0;
+ int i = 0;
+ int ret = STMF_PS_SUCCESS;
+
+ assert(groupList != NULL);
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name from %s iter failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over member list properties
+ */
+ if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ memberCnt++;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) +
+ memberCnt * sizeof (stmfGroupName));
+
+ if (*groupList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * In order to get a list of groups, simply get all of the
+ * properties that are not member list properties, i.e. the group
+ * name properties.
+ * It's possible for this list to grow beyond what was originally
+ * read so just ensure we're not writing beyond our allocated buffer
+ * by ensuring i < memberCnt
+ */
+ while ((scf_iter_next_property(propIter, prop) == 1) &&
+ (i < memberCnt)) {
+ if (scf_property_get_name(prop, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name from %s iter failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over member list properties
+ */
+ if (strstr(buf, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, buf, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get ustring %s/%s failed - %s",
+ pgName, buf, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ bcopy(buf, (*groupList)->name[i++], strlen(buf));
+ (*groupList)->cnt++;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*groupList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsGetGroupMemberList
+ *
+ * pgName - Property group name
+ * groupName - group name (host group or target group)
+ * groupMemberList - pointer to pointer to stmfGroupProperties structure. On
+ * success, contains the list of group members
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetGroupMemberList(char *pgName, char *groupName,
+ stmfGroupProperties **groupMemberList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *valueLookup = NULL;
+ scf_iter_t *valueIter = NULL;
+ int i = 0;
+ int memberCnt;
+ int len;
+ int ret = STMF_PS_SUCCESS;
+ char buf[MAXNAMELEN];
+
+ assert(pgName != NULL && groupName != NULL);
+
+ /*
+ * init the service handle
+ */
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((valueIter = scf_iter_create(handle)) == NULL) ||
+ ((valueLookup = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * get the service property group handle
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ goto out;
+ }
+
+ /*
+ * Get the property handle
+ * based on the target or host group name
+ */
+ if (scf_pg_get_property(pg, groupName, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * valueIter is the iterator handle
+ */
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_value(valueIter, valueLookup) == 1) {
+ if (scf_value_get_ustring(valueLookup, buf, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "iter value %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ i++;
+ }
+
+ /*
+ * valueIter is the iterator handle
+ */
+ if (scf_iter_property_values(valueIter, prop) == -1) {
+ syslog(LOG_ERR, "iter value %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ memberCnt = i;
+
+ *groupMemberList = (stmfGroupProperties *)calloc(1,
+ sizeof (stmfGroupProperties) + memberCnt * sizeof (stmfDevid));
+ if (*groupMemberList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ i = 0;
+ while ((scf_iter_next_value(valueIter, valueLookup) == 1) &&
+ (i < memberCnt)) {
+ if ((len = scf_value_get_ustring(valueLookup, buf, MAXNAMELEN))
+ == -1) {
+ syslog(LOG_ERR, "iter value %s/%s failed - %s",
+ pgName, groupName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (len < sizeof (stmfDevid) - 1) {
+ (*groupMemberList)->name[i].identLength = len;
+ bcopy(buf,
+ (*groupMemberList)->name[i++].ident, len);
+ (*groupMemberList)->cnt++;
+ } else {
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*groupMemberList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (valueLookup != NULL) {
+ scf_value_destroy(valueLookup);
+ }
+ if (valueIter != NULL) {
+ scf_iter_destroy(valueIter);
+ }
+
+ return (ret);
+}
+
+int
+psGetServicePersist(uint8_t *persistType)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ int ret;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsGetSetPersistType(persistType, handle, svc, GET);
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ return (ret);
+}
+
+int
+psSetServicePersist(uint8_t persistType)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ int ret;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsGetSetPersistType(&persistType, handle, svc, SET);
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ return (ret);
+}
+
+static int
+iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle,
+scf_service_t *svc, int getSet)
+{
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ char iPersistTypeGet[MAXNAMELEN] = {0};
+ char *iPersistType;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (getSet == GET) {
+ /* set to default */
+ *persistType = STMF_PERSIST_SMF;
+ iPersistType = STMF_PS_PERSIST_SMF;
+ }
+
+ if (getSet == SET) {
+ if (*persistType == STMF_PERSIST_SMF) {
+ iPersistType = STMF_PS_PERSIST_SMF;
+ } else if (*persistType == STMF_PERSIST_NONE) {
+ iPersistType = STMF_PS_PERSIST_NONE;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * get stmf data property group
+ */
+ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+
+ goto out;
+ }
+
+ /* find persistence property */
+ /*
+ * Get the persistence property
+ */
+ if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* no persist property found */
+ if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
+ /*
+ * If we have no persistType property, go ahead
+ * and create it with the user specified value or
+ * the default value.
+ */
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* is this a SET or GET w/error? */
+ if (ret) {
+ if (scf_transaction_property_new(tran, entry,
+ STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new "
+ "%s/%s failed - %s", STMF_DATA_GROUP,
+ STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ if (scf_transaction_property_change(tran, entry,
+ STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property change "
+ "%s/%s failed - %s", STMF_DATA_GROUP,
+ STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * set the persist type
+ */
+ if (scf_value_set_astring(value, iPersistType) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * add the value to the transaction
+ */
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ /* reset return value */
+ ret = STMF_PS_SUCCESS;
+ } else if (getSet == GET) {
+ /* get the persist property */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the value of the persist property
+ */
+ if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN)
+ == -1) {
+ syslog(LOG_ERR, "get string value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_PERSIST_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (getSet == GET) {
+ if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) {
+ *persistType = STMF_PERSIST_NONE;
+ } else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) {
+ *persistType = STMF_PERSIST_SMF;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+out:
+ /*
+ * Free resources.
+ * handle and svc should not be free'd here. They're
+ * free'd elsewhere
+ */
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ return (ret);
+}
+
+int
+psSetStmfProp(int propType, char *propVal)
+{
+ return (iPsGetSetStmfProp(propType, propVal, SET));
+}
+
+int
+psGetStmfProp(int propType, char *propVal)
+{
+ return (iPsGetSetStmfProp(propType, propVal, GET));
+}
+
+static int
+iPsGetSetStmfProp(int propType, char *propVal, int getSet)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_property_t *prop = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ scf_value_t *value = NULL;
+ char *psStmfPropVal;
+ char *psStmfProp;
+ char stmfPropGet[MAXNAMELEN] = {0};
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (propVal == NULL || (getSet != GET && getSet != SET)) {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Init the service handle
+ */
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (getSet == GET) {
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE :
+ psStmfProp = DEFAULT_LU_STATE;
+ psStmfPropVal = STMF_PS_LU_ONLINE;
+ (void) strcpy(stmfPropGet, psStmfPropVal);
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE :
+ psStmfProp = DEFAULT_TARGET_PORT_STATE;
+ psStmfPropVal = STMF_PS_TARGET_PORT_ONLINE;
+ (void) strcpy(stmfPropGet, psStmfPropVal);
+ break;
+ default :
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ if (getSet == SET) {
+ switch (propType) {
+ case STMF_DEFAULT_LU_STATE :
+ psStmfProp = DEFAULT_LU_STATE;
+ if (strcasecmp(propVal, "online") == 0) {
+ psStmfPropVal = STMF_PS_LU_ONLINE;
+ } else if (strcasecmp(propVal,
+ "offline") == 0) {
+ psStmfPropVal = STMF_PS_LU_OFFLINE;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ break;
+ case STMF_DEFAULT_TARGET_PORT_STATE :
+ psStmfProp = DEFAULT_TARGET_PORT_STATE;
+ if (strcasecmp(propVal, "online") == 0) {
+ psStmfPropVal =
+ STMF_PS_TARGET_PORT_ONLINE;
+ } else if (strcasecmp(propVal,
+ "offline") == 0) {
+ psStmfPropVal =
+ STMF_PS_TARGET_PORT_OFFLINE;
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ break;
+ default :
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * get stmf data property group
+ */
+
+ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ goto out;
+ }
+
+ /*
+ * get the stmf props property, if exists
+ */
+
+ if (scf_pg_get_property(pg, psStmfProp, prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "start transaction for %s/%s "
+ "failed - %s", STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* if stmf prop is not found or while setting the prop */
+
+ if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if (ret) {
+ if (scf_transaction_property_new(tran, entry,
+ psStmfProp, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property new "
+ "%s/%s failed - %s", STMF_DATA_GROUP,
+ psStmfProp, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ if (scf_transaction_property_change(tran, entry,
+ psStmfProp, SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change "
+ "%s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * set stmf prop value
+ */
+
+ if (scf_value_set_astring(value, psStmfPropVal) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * add the value to the transaction
+ */
+
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s"
+ "failed - %s", STMF_DATA_GROUP,
+ scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ ret = STMF_PS_SUCCESS;
+ } else if (getSet == GET) {
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value "
+ "%s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* get stmfProp */
+
+ if (scf_value_get_astring(value, stmfPropGet, MAXNAMELEN)
+ == -1) {
+ syslog(LOG_ERR, "get string value %s/%s failed - %s",
+ STMF_DATA_GROUP, psStmfProp,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ if (getSet == GET) {
+ if (strcmp(stmfPropGet, STMF_PS_LU_ONLINE) == 0) {
+ (void) strcpy(propVal, "online");
+ } else if (strcmp(stmfPropGet, STMF_PS_LU_OFFLINE) == 0) {
+ (void) strcpy(propVal, "offline");
+ } else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_ONLINE)
+ == 0) {
+ (void) strcpy(propVal, "online");
+ } else if (strcmp(stmfPropGet, STMF_PS_TARGET_PORT_OFFLINE)
+ == 0) {
+ (void) strcpy(propVal, "offline");
+ } else {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+out:
+ /*
+ * Free resources.
+ */
+
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ return (ret);
+}
+
+/*
+ * Initialize scf stmf service access
+ * handle - returned handle
+ * service - returned service handle
+ *
+ * Both handle and service must be destroyed by the caller
+ */
+static int
+iPsInit(scf_handle_t **handle, scf_service_t **service)
+{
+ scf_scope_t *scope = NULL;
+ uint64_t version;
+ int ret;
+
+ assert(handle != NULL && service != NULL);
+
+ if ((*handle = scf_handle_create(SCF_VERSION)) == NULL) {
+ syslog(LOG_ERR, "scf_handle_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_bind(*handle) == -1) {
+ syslog(LOG_ERR, "scf_handle_bind failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if ((*service = scf_service_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_service_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if ((scope = scf_scope_create(*handle)) == NULL) {
+ syslog(LOG_ERR, "scf_scope_create failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if (scf_handle_get_scope(*handle, SCF_SCOPE_LOCAL, scope) == -1) {
+ syslog(LOG_ERR, "scf_handle_get_scope failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto err;
+ }
+
+ if (scf_scope_get_service(scope, STMF_SERVICE, *service) == -1) {
+ syslog(LOG_ERR, "scf_scope_get_service failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR_SERVICE_NOT_FOUND;
+ goto err;
+ }
+
+
+ /*
+ * Get and check the version number
+ */
+ ret = iPsGetServiceVersion(&version, *handle, *service);
+ if (ret != STMF_PS_SUCCESS) {
+ goto err;
+ }
+
+ if (version != STMF_SMF_VERSION) {
+ ret = STMF_PS_ERROR_VERSION_MISMATCH;
+ goto err;
+ }
+
+ /* we only need destroy the scope here */
+ scf_scope_destroy(scope);
+
+ return (STMF_PS_SUCCESS);
+
+err:
+ if (*handle != NULL) {
+ scf_handle_destroy(*handle);
+ }
+ if (*service != NULL) {
+ scf_service_destroy(*service);
+ *service = NULL;
+ }
+ if (scope != NULL) {
+ scf_scope_destroy(scope);
+ }
+ return (ret);
+}
+
+
+/*
+ * called by iPsInit only
+ * iPsGetServiceVersion
+ */
+static int
+iPsGetServiceVersion(uint64_t *version, scf_handle_t *handle,
+scf_service_t *svc)
+{
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_transaction_t *tran = NULL;
+ scf_transaction_entry_t *entry = NULL;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((entry = scf_entry_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *version = STMF_SMF_VERSION;
+
+ /*
+ * get stmf data property group
+ */
+ if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* create the group */
+ if (ret == STMF_PS_ERROR_NOT_FOUND) {
+ /*
+ * create the property group.
+ */
+ if (scf_service_add_pg(svc, STMF_DATA_GROUP,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* reset return value */
+ ret = STMF_PS_SUCCESS;
+ }
+
+ /* find version property */
+ /*
+ * Get the version property
+ */
+ if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* no version property found */
+ if (ret == STMF_PS_ERROR_NOT_FOUND) {
+ /*
+ * If we have no version property, go ahead
+ * and create it. We're obviously making an assumption
+ * here that someone did not delete the existing property
+ * and that this is the initial set and the initial call
+ * to iPsInit.
+ * If they did delete it, this will simply plant this
+ * library's version on this service. That may or may not be
+ * correct and we have no way of determining that.
+ */
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_transaction_property_new(tran, entry,
+ STMF_VERSION_NAME, SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR,
+ "transaction property new %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * set the version number
+ */
+ scf_value_set_count(value, *version);
+
+ /*
+ * add the value to the transaction
+ */
+ if (scf_entry_add_value(entry, value) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ STMF_DATA_GROUP, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+ /* reset return value */
+ ret = STMF_PS_SUCCESS;
+ } else {
+ /* get the version property */
+ if (scf_pg_get_property(pg, STMF_VERSION_NAME, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the actual value of the view entry count property
+ */
+ if (scf_value_get_count(value, version) == -1) {
+ syslog(LOG_ERR, "get count value %s/%s failed - %s",
+ STMF_DATA_GROUP, STMF_VERSION_NAME,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+out:
+ /*
+ * Free resources.
+ * handle and svc should not be free'd here. They're
+ * free'd elsewhere
+ */
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (entry != NULL) {
+ scf_entry_destroy(entry);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ return (ret);
+}
+
+
+
+/*
+ * iPsGetActualGroupName
+ *
+ * pgName - Property group name
+ * groupName - requested group name
+ * actualName - actual group name to reference (len must be >= MAXNAMELEN)
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetActualGroupName(char *pgName, char *groupName, char *actualName)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_iter_t *propIter = NULL;
+ scf_value_t *value = NULL;
+ char buf[MAXNAMELEN];
+ int ret;
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * get group list property group
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Iterate through group properties searching for the requested
+ * group name. When we find it, we need to get the property name
+ * since it refers to the actual group name.
+ */
+
+ /* initialize to not found */
+ ret = STMF_PS_ERROR_GROUP_NOT_FOUND;
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ if (scf_property_get_name(prop, actualName, MAXNAMELEN) == -1) {
+ syslog(LOG_ERR, "get name from %s iter failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Skip over non-member list properties
+ */
+ if (strstr(actualName, STMF_MEMBER_LIST_SUFFIX)) {
+ continue;
+ }
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, actualName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ if (scf_value_get_ustring(value, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get ustring %s/%s failed - %s",
+ pgName, actualName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * When we find a match, set success and break
+ */
+ if ((strlen(buf) == strlen(groupName)) &&
+ bcmp(buf, groupName, strlen(buf)) == 0) {
+ ret = STMF_PS_SUCCESS;
+ break;
+ }
+ }
+
+ /*
+ * if we didn't find it, ret is set to STMF_PS_ERROR_GROUP_NOT_FOUND
+ */
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+
+ return (ret);
+}
+
+/*
+ * psAddHostGroupMember
+ *
+ * Add a host group member to a host group,
+ *
+ * Input: groupName - name of group to which the member is added
+ * memberName - name of group member to add
+ */
+int
+psAddHostGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
+ memberName, ADD));
+}
+
+/*
+ * psAddTargetGroupMember
+ *
+ * Add a target port group member to a target group
+ *
+ * Input: groupName - name of group to which the member is added
+ * memberName - name of group member to add. Must be nul terminated.
+ */
+int
+psAddTargetGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
+ memberName, ADD));
+}
+
+
+/*
+ * psAddViewEntry
+ *
+ * luGuid - logical unit identifier
+ * viewEntry - pointer to viewEntry allocated by the caller that contains
+ * the values to set for this view entry
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char scfLuPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+ sigset_t sigmaskRestore;
+
+ /* grab the signal hold lock */
+ (void) pthread_mutex_lock(&sigSetLock);
+
+ /*
+ * hold signals until we're done
+ */
+ if (holdSignal(&sigmaskRestore) != 0) {
+ (void) pthread_mutex_unlock(&sigSetLock);
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ pg = scf_pg_create(handle);
+ if (pg == NULL) {
+ syslog(LOG_ERR, "scf pg alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ (void) snprintf(scfLuPgName, sizeof (scfLuPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ bzero(viewEntryPgName, sizeof (viewEntryPgName));
+ /*
+ * Format of view entry property group name:
+ * VE-<view_entry_name>-<lu_name>
+ */
+ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
+ "%s-%d-%s", STMF_VE_PREFIX, viewEntry->veIndex, guidAsciiBuf);
+
+ ret = iPsAddViewEntry(scfLuPgName, viewEntryPgName, viewEntry);
+
+out:
+ /*
+ * Okay, we're done. Release the signals
+ */
+ if (releaseSignal(&sigmaskRestore) != 0) {
+ /*
+ * Don't set this as an STMF_PS_ERROR_*. We succeeded
+ * the requested operation. But we do need to log it.
+ */
+ syslog(LOG_ERR, "Unable to release one or more signals - %s",
+ strerror(errno));
+ }
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ /* release the signal hold lock */
+ (void) pthread_mutex_unlock(&sigSetLock);
+
+ return (ret);
+}
+
+/*
+ * psCheckService
+ *
+ * Purpose: Checks whether service exists
+ *
+ */
+int
+psCheckService()
+{
+ int ret;
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+
+ ret = iPsInit(&handle, &svc);
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+
+ return (ret);
+}
+
+/*
+ * psCreateHostGroup
+ *
+ * groupName - name of group to create
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psCreateHostGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, ADD));
+}
+
+/*
+ * psCreateTargetGroup
+ *
+ * groupName - name of group to create
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psCreateTargetGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName, ADD));
+}
+
+/*
+ * psDeleteHostGroup
+ *
+ * groupName - name of group to delete
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psDeleteHostGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_HOST_GROUPS, groupName, REMOVE));
+}
+
+/*
+ * psDeleteTargetGroup
+ *
+ * groupName - name of group to delete
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psDeleteTargetGroup(char *groupName)
+{
+ return (iPsCreateDeleteGroup(STMF_TARGET_GROUPS, groupName,
+ REMOVE));
+}
+
+/*
+ * psGetHostGroupList
+ *
+ * groupList - pointer to pointer to stmfGroupList. Contains the list
+ * of host groups on successful return.
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetHostGroupList(stmfGroupList **groupList)
+{
+ return (iPsGetGroupList(STMF_HOST_GROUPS, groupList));
+}
+
+/*
+ * psGetLogicalUnitList
+ *
+ *
+ */
+int
+psGetLogicalUnitList(stmfGuidList **guidList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_iter_t *pgIter = NULL;
+ char buf[MAXNAMELEN];
+ int guidCnt = 0;
+ int i = 0, j;
+ int ret = STMF_PS_SUCCESS;
+ unsigned int guid[sizeof (stmfGuid)];
+ stmfGuid outGuid;
+
+ assert(guidList != NULL);
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((pgIter = scf_iter_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_pg(pgIter, pg) == 1) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get pg name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only count LU property groups
+ */
+ if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) == 0) {
+ guidCnt++;
+ }
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *guidList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
+ guidCnt * sizeof (stmfGuid));
+ if (*guidList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * it's possible for entries to be added/removed while we're retrieving
+ * the property groups. Just make sure we don't write beyond our
+ * allocated buffer by checking to ensure i < guidCnt.
+ */
+ while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < guidCnt)) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get pg name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only use LU property groups
+ */
+ if (strncmp(buf, STMF_LU_PREFIX, strlen(STMF_LU_PREFIX)) != 0) {
+ continue;
+ }
+
+ j = strlen(STMF_LU_PREFIX) + strlen("-");
+
+ (void) sscanf(buf + j,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
+ &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
+ &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
+
+ for (j = 0; j < sizeof (stmfGuid); j++) {
+ outGuid.guid[j] = guid[j];
+ }
+
+ bcopy(&outGuid, (*guidList)->guid[i++].guid, sizeof (stmfGuid));
+ (*guidList)->cnt++;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*guidList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (pgIter != NULL) {
+ scf_iter_destroy(pgIter);
+ }
+
+ return (ret);
+}
+
+/*
+ * psGetTargetGroupList
+ *
+ * groupList - pointer to pointer to stmfGroupList. Contains the list
+ * of target groups on successful return.
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetTargetGroupList(stmfGroupList **groupList)
+{
+ return (iPsGetGroupList(STMF_TARGET_GROUPS, groupList));
+}
+
+/*
+ * psGetHostGroupMemberList
+ *
+ * groupName - group name for which to retrieve a member list
+ * groupMemberList - pointer to pointer to stmfGroupProperties list
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupMemberList)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsGetGroupMemberList(STMF_HOST_GROUPS, groupPropListName,
+ groupMemberList));
+}
+
+/*
+ * psGetTargetGroupMemberList
+ *
+ * groupName - group name for which to retrieve a member list
+ * groupMemberList - pointer to pointer to stmfGroupProperties list
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetTargetGroupMemberList(char *groupName,
+ stmfGroupProperties **groupMemberList)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsGetGroupMemberList(STMF_TARGET_GROUPS,
+ groupPropListName, groupMemberList));
+}
+
+/*
+ * qsort function
+ * sort on veIndex
+ */
+static int
+viewEntryCompare(const void *p1, const void *p2)
+{
+
+ stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
+ if (v1->veIndex > v2->veIndex)
+ return (1);
+ if (v1->veIndex < v2->veIndex)
+ return (-1);
+ return (0);
+}
+
+/*
+ * psGetViewEntryList
+ *
+ * luGuid - identifier of logical unit for which to retrieve a view entry list
+ * viewEntryList - pointer to pointer to stmfViewEntryList. It will be allocated
+ * on successful return.
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_iter_t *propIter = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char luPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+ uint64_t i = 0;
+ uint64_t veCnt;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((propIter = scf_iter_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ /* form the LU property group name (LU-<guid>) */
+ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ /* get the property group associated with this LU */
+ if (scf_service_get_pg(svc, luPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /* get the view entry count property */
+ if (scf_pg_get_property(pg, STMF_VE_CNT, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the actual value of the view entry count property
+ */
+ if (scf_value_get_count(value, &veCnt) == -1) {
+ syslog(LOG_ERR, "get integer value %s/%s failed - %s",
+ luPgName, STMF_VE_CNT, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * propIter is the iterator handle
+ */
+ if (scf_iter_pg_properties(propIter, pg) == -1) {
+ syslog(LOG_ERR, "iter properties for %s failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * alloc the list based on the view entry count
+ */
+ *viewEntryList = (stmfViewEntryList *)calloc(1,
+ sizeof (stmfViewEntryList) + veCnt * sizeof (stmfViewEntry));
+ if (*viewEntryList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ i = 0;
+ /*
+ * iterate through the view entry properties to find the
+ * view entries
+ */
+ while (scf_iter_next_property(propIter, prop) == 1) {
+ /* find match for view entry property */
+ if (scf_property_get_name(prop, viewEntryPgName,
+ sizeof (viewEntryPgName)) != -1) {
+ if (strncmp(viewEntryPgName, STMF_VE_PREFIX,
+ strlen(STMF_VE_PREFIX)) != 0) {
+ continue;
+ }
+ /*
+ * We've exceeded our alloc limit
+ * break with error
+ */
+ if (i == veCnt) {
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ if ((ret = iPsGetViewEntry(viewEntryPgName,
+ &((*viewEntryList)->ve[i]))) != STMF_PS_SUCCESS) {
+ break;
+ }
+
+ i++;
+
+ /* set the list count */
+ (*viewEntryList)->cnt++;
+ } else {
+ syslog(LOG_ERR, "scf iter %s properties failed - %s",
+ luPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*viewEntryList);
+ goto out;
+ }
+
+ /*
+ * We're sorting the final list here based on the veIndex
+ * If we don't, the caller is going to have to do it to reap
+ * some intelligent output.
+ */
+ qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
+ sizeof (stmfViewEntry), viewEntryCompare);
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (propIter != NULL) {
+ scf_iter_destroy(propIter);
+ }
+
+ return (ret);
+}
+
+/*
+ * iPsGetViewEntry
+ *
+ * viewEntryPgName - view entry property group name to retrieve
+ * viewEntry - pointer to stmfViewEntry structure allocated by the caller
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+static int
+iPsGetViewEntry(char *viewEntryPgName, stmfViewEntry *viewEntry)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ uint8_t scfBool;
+ char *indexPtr;
+ char groupName[sizeof (stmfGroupName)];
+ int ret = STMF_PS_SUCCESS;
+
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ bzero(viewEntry, sizeof (stmfViewEntry));
+
+ /*
+ * get the service property group view entry handle
+ */
+ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+
+ /*
+ * get index
+ * format is: VE-<veIndex>-GUID
+ */
+ indexPtr = strchr(viewEntryPgName, '-');
+ if (!indexPtr) {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Set the index */
+ viewEntry->veIndex = atoi(strtok(++indexPtr, "-"));
+
+ viewEntry->veIndexValid = B_TRUE;
+
+ /* get allHosts property */
+ if (scf_pg_get_property(pg, STMF_VE_ALLHOSTS,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* set allHosts */
+ if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLHOSTS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ viewEntry->allHosts = scfBool;
+
+ /* get hostGroup property */
+ if (scf_pg_get_property(pg, STMF_VE_HOSTGROUP,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_get_ustring(value, groupName,
+ sizeof (groupName)) == -1) {
+ syslog(LOG_ERR, "get value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_HOSTGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* set hostGroup */
+ bcopy(groupName, viewEntry->hostGroup, strlen(groupName));
+
+ /* get allTargets property */
+ if (scf_pg_get_property(pg, STMF_VE_ALLTARGETS,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* set allTargets */
+ if (scf_value_get_boolean(value, (uint8_t *)&scfBool) == -1) {
+ syslog(LOG_ERR, "get value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_ALLTARGETS,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ viewEntry->allTargets = scfBool;
+
+ /* get targetGroup property */
+ if (scf_pg_get_property(pg, STMF_VE_TARGETGROUP, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_get_ustring(value, groupName,
+ sizeof (groupName)) == -1) {
+ syslog(LOG_ERR, "get value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_TARGETGROUP,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* set targetGroup */
+ bcopy(groupName, viewEntry->targetGroup, strlen(groupName));
+
+ /* get luNbr property */
+ if (scf_pg_get_property(pg, STMF_VE_LUNBR,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* set luNbr */
+ if (scf_value_get_opaque(value, (char *)viewEntry->luNbr,
+ sizeof (viewEntry->luNbr)) == -1) {
+ syslog(LOG_ERR, "get opaque value %s/%s failed - %s",
+ viewEntryPgName, STMF_VE_LUNBR,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ /* set luNbrValid to true since we just got it */
+ viewEntry->luNbrValid = B_TRUE;
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+
+ return (ret);
+}
+
+
+/*
+ * psRemoveHostGroupMember
+ *
+ * Remove a host group member from a host group,
+ *
+ * groupName - name of group from which the member is removed
+ * memberName - name of group member to remove
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psRemoveHostGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_HOST_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_HOST_GROUPS, groupPropListName,
+ memberName, REMOVE));
+}
+
+/*
+ * psRemoveTargetGroupMember
+ *
+ * Remove a target port group member from an target port group,
+ *
+ * groupName - name of group from which the member is removed
+ * memberName - name of group member to remove
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psRemoveTargetGroupMember(char *groupName, char *memberName)
+{
+ int ret;
+ char groupPropListName[MAXNAMELEN];
+ char groupPropName[MAXNAMELEN];
+
+ ret = iPsGetActualGroupName(STMF_TARGET_GROUPS, groupName,
+ groupPropName);
+ if (ret != STMF_PS_SUCCESS) {
+ return (ret);
+ }
+
+ if (snprintf(groupPropListName, sizeof (groupPropListName),
+ "%s-%s", groupPropName, STMF_MEMBER_LIST_SUFFIX) >
+ sizeof (groupPropListName)) {
+ syslog(LOG_ERR, "buffer overflow on property name %s",
+ groupPropName);
+ return (STMF_PS_ERROR);
+ }
+
+ return (iPsAddRemoveGroupMember(STMF_TARGET_GROUPS, groupPropListName,
+ memberName, REMOVE));
+}
+
+/*
+ * psGetProviderData
+ *
+ * Retrieves an nvlist on a per provider basis
+ *
+ * providerName - property group name to use
+ * nvl - nvlist to retrieve
+ *
+ */
+int
+psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setToken)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ uint64_t blockCnt = 0;
+ ssize_t blockOffset = 0;
+ ssize_t actualBlockSize = 0;
+ char pgName[MAXPATHLEN];
+ char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
+ char *nvlistEncoded = NULL;
+ ssize_t nvlistEncodedSize = 0;
+ boolean_t foundSetCnt = B_TRUE;
+ int i;
+ int ret = STMF_PS_SUCCESS;
+
+ if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE)) {
+ ret = STMF_PS_ERROR_INVALID_ARG;
+ goto out;
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * create the property group name
+ */
+ (void) snprintf(pgName, sizeof (pgName), "%s%s",
+ STMF_PROVIDER_DATA_PREFIX, providerName);
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Retrieve the existing property group.
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg %s failed - %s", pgName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ goto out;
+ }
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT property
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value, &blockCnt) == -1) {
+ syslog(LOG_ERR, "get integer value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Has the caller requested the token to be set? */
+ if (setToken) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
+ * If it doesn't exist, we assume it to be zero.
+ */
+ *setToken = 0;
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ foundSetCnt = B_FALSE;
+ } else {
+ syslog(LOG_ERR, "get property %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (foundSetCnt) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR,
+ "get property value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ * and set the caller's token
+ */
+ if (scf_value_get_count(value, setToken) == -1) {
+ syslog(LOG_ERR,
+ "get integer value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ }
+
+ nvlistEncoded = (char *)calloc(1,
+ blockCnt * STMF_PROVIDER_DATA_PROP_SIZE);
+ if (nvlistEncoded == NULL) {
+ syslog(LOG_ERR, "nvlistEncoded alloc failed");
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < blockCnt; i++) {
+ bzero(dataPropertyName, sizeof (dataPropertyName));
+ /*
+ * create the name to use for the property
+ */
+ (void) snprintf(dataPropertyName, sizeof (dataPropertyName),
+ "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
+
+ if (scf_pg_get_property(pg, dataPropertyName, prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Set the data block offset
+ */
+ blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
+ actualBlockSize = scf_value_get_opaque(value,
+ &nvlistEncoded[blockOffset], STMF_PROVIDER_DATA_PROP_SIZE);
+ if (actualBlockSize == -1) {
+ syslog(LOG_ERR, "get opaque property value %s/%s "
+ "failed - %s", pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ nvlistEncodedSize += actualBlockSize;
+ }
+
+ if (nvlist_unpack(nvlistEncoded, nvlistEncodedSize, nvl, 0) != 0) {
+ syslog(LOG_ERR, "unable to unpack nvlist");
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (nvlistEncoded != NULL) {
+ free(nvlistEncoded);
+ }
+
+ return (ret);
+
+}
+/*
+ * psGetProviderDataList
+ *
+ * Retrieves the list of providers that currently store persistent data
+ *
+ * providerList - pointer to a pointer to an stmfProviderList structure
+ * On success, this will contain the list of providers
+ * currently storing persistent data.
+ */
+int
+psGetProviderDataList(stmfProviderList **providerList)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_value_t *value = NULL;
+ scf_iter_t *pgIter = NULL;
+ char buf[MAXNAMELEN];
+ int providerCnt = 0;
+ int64_t providerType;
+ int i = 0, j;
+ int ret = STMF_PS_SUCCESS;
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ *providerList = NULL;
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((value = scf_value_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((pgIter = scf_iter_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ while (scf_iter_next_pg(pgIter, pg) == 1) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only count LU property groups
+ */
+ if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
+ strlen(STMF_PROVIDER_DATA_PREFIX)) == 0) {
+ providerCnt++;
+ }
+ }
+
+ /*
+ * pgIter is the iterator handle
+ */
+ if (scf_iter_service_pgs(pgIter, svc) == -1) {
+ syslog(LOG_ERR, "iter property groups failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ *providerList = (stmfProviderList *)calloc(1,
+ sizeof (stmfProviderList) + providerCnt * sizeof (stmfProvider));
+ if (*providerList == NULL) {
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * it's possible for entries to be added/removed while we're retrieving
+ * the property groups. Just make sure we don't write beyond our
+ * allocated buffer by checking to ensure i < providerCnt.
+ */
+ while ((scf_iter_next_pg(pgIter, pg) == 1) && (i < providerCnt)) {
+ if (scf_pg_get_name(pg, buf, sizeof (buf)) == -1) {
+ syslog(LOG_ERR, "get name failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+ /*
+ * Only use provider data property groups
+ */
+ if (strncmp(buf, STMF_PROVIDER_DATA_PREFIX,
+ strlen(STMF_PROVIDER_DATA_PREFIX)) != 0) {
+ continue;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_TYPE property
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_TYPE,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ buf, STMF_PROVIDER_DATA_PROP_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_TYPE value
+ */
+ if (scf_property_get_value(prop, value) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ buf, STMF_PROVIDER_DATA_PROP_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_integer(value, &providerType) == -1) {
+ syslog(LOG_ERR, "get integer value %s/%s failed - %s",
+ buf, STMF_PROVIDER_DATA_PROP_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ break;
+ }
+
+ (*providerList)->provider[i].providerType = providerType;
+
+ /* determine offset for copy of provider name */
+ j = strlen(STMF_PROVIDER_DATA_PREFIX);
+
+ /* copy provider name to caller's list */
+ (void) strncpy((*providerList)->provider[i].name, buf + j,
+ sizeof ((*providerList)->provider[i].name));
+ i++;
+ (*providerList)->cnt++;
+ }
+
+ if (ret != STMF_PS_SUCCESS) {
+ free(*providerList);
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (value != NULL) {
+ scf_value_destroy(value);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (pgIter != NULL) {
+ scf_iter_destroy(pgIter);
+ }
+
+ return (ret);
+}
+
+
+/*
+ * psSetProviderData
+ *
+ * Stores a packed nvlist on a per provider basis
+ *
+ * providerName - property group name to use
+ * nvl - nvlist to store
+ * providerType - type of provider (logical unit or port)
+ *
+ */
+int
+psSetProviderData(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setToken)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ scf_property_t *prop = NULL;
+ scf_transaction_t *tran = NULL;
+ /* represents arrays of entry and value pointers for scf */
+ scf_transaction_entry_t **addEntry = NULL;
+ scf_transaction_entry_t **deleteEntry = NULL;
+ scf_value_t **addValue = NULL;
+
+ /*
+ * These declarations are for known entry and value set/get
+ * operations
+ */
+ scf_transaction_entry_t *entry1 = NULL;
+ scf_transaction_entry_t *entry2 = NULL;
+ scf_transaction_entry_t *entry3 = NULL;
+ scf_transaction_entry_t *entry5 = NULL;
+ scf_value_t *value1 = NULL;
+ scf_value_t *value2 = NULL;
+ scf_value_t *value3 = NULL;
+ scf_value_t *value4 = NULL;
+ scf_value_t *value5 = NULL;
+
+ boolean_t newPg = B_FALSE;
+ char pgName[MAXPATHLEN];
+ char dataPropertyName[STMF_PROVIDER_DATA_PROP_NAME_SIZE];
+ char *nvlistEncoded = NULL;
+ size_t nvlistEncodedSize;
+ size_t blockSize;
+ int i, j = 0;
+ int addEntryAlloc = 0, deleteEntryAlloc = 0, addValueAlloc = 0;
+ int blockOffset;
+ uint64_t oldBlockCnt = 0;
+ uint64_t blockCnt = 0;
+ uint64_t setCnt = 0;
+ boolean_t foundSetCnt = B_TRUE;
+ int ret = STMF_PS_SUCCESS;
+ int commitRet;
+
+ if (providerName == NULL || (providerType != STMF_LU_PROVIDER_TYPE &&
+ providerType != STMF_PORT_PROVIDER_TYPE)) {
+ ret = STMF_PS_ERROR_INVALID_ARG;
+ goto out;
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ bzero(pgName, sizeof (pgName));
+ /*
+ * create the property group name
+ */
+ (void) snprintf(pgName, sizeof (pgName), "%s%s",
+ STMF_PROVIDER_DATA_PREFIX, providerName);
+
+ /*
+ * Allocate scf resources
+ */
+ if (((pg = scf_pg_create(handle)) == NULL) ||
+ ((entry1 = scf_entry_create(handle)) == NULL) ||
+ ((entry2 = scf_entry_create(handle)) == NULL) ||
+ ((entry3 = scf_entry_create(handle)) == NULL) ||
+ ((entry5 = scf_entry_create(handle)) == NULL) ||
+ ((value1 = scf_value_create(handle)) == NULL) ||
+ ((value2 = scf_value_create(handle)) == NULL) ||
+ ((value3 = scf_value_create(handle)) == NULL) ||
+ ((value4 = scf_value_create(handle)) == NULL) ||
+ ((value5 = scf_value_create(handle)) == NULL) ||
+ ((prop = scf_property_create(handle)) == NULL) ||
+ ((tran = scf_transaction_create(handle)) == NULL)) {
+ syslog(LOG_ERR, "scf alloc resource failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the existing property group
+ */
+ if (scf_service_get_pg(svc, pgName, pg) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ } else {
+ /*
+ * create the property group.
+ */
+ if (scf_service_add_pg(svc, pgName,
+ SCF_GROUP_APPLICATION, 0, pg) == -1) {
+ syslog(LOG_ERR, "add pg %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ newPg = B_TRUE;
+ }
+ }
+
+ /*
+ * Begin the transaction
+ */
+ if (scf_transaction_start(tran, pg) == -1) {
+ syslog(LOG_ERR, "start transaction for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (!newPg) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT property
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_COUNT,
+ prop) == -1) {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_COUNT value
+ */
+ if (scf_property_get_value(prop, value4) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value4, &oldBlockCnt) == -1) {
+ syslog(LOG_ERR, "get integer value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT property
+ * If it doesn't exist, we'll create it later after successfully
+ * setting the data.
+ */
+ if (scf_pg_get_property(pg, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ prop) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ foundSetCnt = B_FALSE;
+ } else {
+ syslog(LOG_ERR, "get property %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (foundSetCnt) {
+ /*
+ * Get the STMF_PROVIDER_DATA_PROP_SET_COUNT value
+ */
+ if (scf_property_get_value(prop, value5) == -1) {
+ syslog(LOG_ERR, "get property value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Now get the actual value from the value handle
+ */
+ if (scf_value_get_count(value5, &setCnt) == -1) {
+ syslog(LOG_ERR, "get integer value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Compare the setCnt prop to the caller's.
+ */
+ if (setToken && (*setToken != setCnt)) {
+ ret = STMF_PS_ERROR_PROV_DATA_STALE;
+ goto out;
+ }
+ }
+
+ setCnt++;
+
+ /*
+ * prepare the list for writing
+ */
+ if (nvlist_pack(nvl, &nvlistEncoded, &nvlistEncodedSize,
+ NV_ENCODE_XDR, 0) != 0) {
+ syslog(LOG_ERR, "nvlist_pack for %s failed",
+ pgName);
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /* Determine how many chunks we need to write */
+ blockCnt = nvlistEncodedSize/STMF_PROVIDER_DATA_PROP_SIZE;
+ if (nvlistEncodedSize % STMF_PROVIDER_DATA_PROP_SIZE)
+ blockCnt++;
+
+ /* allocate entry and value resources for writing those chunks */
+ addEntry = (scf_transaction_entry_t **)calloc(1, sizeof (*addEntry)
+ * blockCnt);
+ if (addEntry == NULL) {
+ syslog(LOG_ERR, "addEntry alloc for %s failed", pgName);
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ addValue = (scf_value_t **)calloc(1, sizeof (*addValue)
+ * blockCnt);
+ if (addValue == NULL) {
+ syslog(LOG_ERR, "value alloc for %s failed", pgName);
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+
+ /*
+ * allocate entry delete resources for deleting anything existing
+ * that is more than the new block count. We could leave them around
+ * without suffering any ill effects but it will be cleaner to look at
+ * in smf tools if they are deleted.
+ */
+ if (oldBlockCnt > blockCnt) {
+ deleteEntry = (scf_transaction_entry_t **)calloc(1,
+ sizeof (*deleteEntry) * (oldBlockCnt - blockCnt));
+ if (deleteEntry == NULL) {
+ syslog(LOG_ERR, "deleteEntry alloc for %s failed",
+ pgName);
+ ret = STMF_PS_ERROR_NOMEM;
+ goto out;
+ }
+ deleteEntryAlloc = oldBlockCnt - blockCnt;
+ }
+
+
+ for (i = 0; i < blockCnt; i++) {
+ /*
+ * Create the entry resource for the prop
+ */
+ addEntry[i] = scf_entry_create(handle);
+ if (addEntry[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* bump alloc count for addEntry allocation */
+ addEntryAlloc++;
+
+ /*
+ * create the name to use for the property
+ */
+ (void) snprintf(dataPropertyName, sizeof (dataPropertyName),
+ "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
+
+ /*
+ * Create the new property
+ */
+ if (scf_transaction_property_new(tran, addEntry[i],
+ dataPropertyName, SCF_TYPE_OPAQUE) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran,
+ addEntry[i], dataPropertyName,
+ SCF_TYPE_OPAQUE) == -1) {
+ syslog(LOG_ERR, "transaction property "
+ "change %s/%s failed - %s",
+ pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR,
+ "transaction property new %s/%s "
+ "failed - %s", pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+ /*
+ * Create the value resource for the prop
+ */
+ addValue[i] = scf_value_create(handle);
+ if (addValue[i] == NULL) {
+ syslog(LOG_ERR, "scf value alloc for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* bump alloc count for addValue allocation */
+ addValueAlloc++;
+
+ /*
+ * Set the data block offset and size
+ */
+ if ((STMF_PROVIDER_DATA_PROP_SIZE * (i + 1))
+ > nvlistEncodedSize) {
+ blockSize = nvlistEncodedSize
+ - STMF_PROVIDER_DATA_PROP_SIZE * i;
+ } else {
+ blockSize = STMF_PROVIDER_DATA_PROP_SIZE;
+ }
+
+ blockOffset = STMF_PROVIDER_DATA_PROP_SIZE * i;
+ if (scf_value_set_opaque(addValue[i],
+ &nvlistEncoded[blockOffset], blockSize) == -1) {
+ syslog(LOG_ERR, "set value for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * Add the data block to the transaction entry
+ */
+ if (scf_entry_add_value(addEntry[i], addValue[i]) == -1) {
+ syslog(LOG_ERR, "add value for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /*
+ * Now we need to delete any chunks (properties) that are no longer
+ * needed. Iterate through the rest of the chunks deleting each.
+ */
+ for (i = blockCnt; i < oldBlockCnt; i++) {
+ /*
+ * Create the entry resource for the prop
+ */
+ deleteEntry[j] = scf_entry_create(handle);
+ if (deleteEntry[j] == NULL) {
+ syslog(LOG_ERR, "scf value alloc for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /*
+ * create the name to use for the property
+ */
+ (void) snprintf(dataPropertyName, sizeof (dataPropertyName),
+ "%s-%d", STMF_PROVIDER_DATA_PROP_PREFIX, i);
+
+ /*
+ * Delete the existing property
+ */
+ if (scf_transaction_property_delete(tran, deleteEntry[j++],
+ dataPropertyName) == -1) {
+ syslog(LOG_ERR, "delete property %s/%s failed - %s",
+ pgName, dataPropertyName,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ if (newPg) {
+ /*
+ * Ensure the read_authorization property is set
+ * for the group
+ */
+ if (scf_transaction_property_new(tran, entry1,
+ "read_authorization", SCF_TYPE_ASTRING) == -1) {
+ syslog(LOG_ERR, "transaction property %s/%s new "
+ "failed - %s", pgName, "read_authorization",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_value_set_astring(value1, STMF_SMF_READ_ATTR) == -1) {
+ syslog(LOG_ERR, "set value %s/%s failed - %s",
+ pgName, "read_authorization",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_entry_add_value(entry1, value1) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ pgName, "read_authorization",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ /* create or change the count property */
+ if (scf_transaction_property_new(tran, entry2,
+ STMF_PROVIDER_DATA_PROP_COUNT, SCF_TYPE_COUNT) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran, entry2,
+ STMF_PROVIDER_DATA_PROP_COUNT,
+ SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR, "transaction property change "
+ "%s/%s failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property %s/%s new "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ scf_value_set_count(value2, blockCnt);
+
+ if (scf_entry_add_value(entry2, value2) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* create or change the set count property */
+ if (scf_transaction_property_new(tran, entry5,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT, SCF_TYPE_COUNT) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran, entry5,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ SCF_TYPE_COUNT) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+
+
+ scf_value_set_count(value5, setCnt);
+
+ if (scf_entry_add_value(entry5, value5) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s",
+ pgName, STMF_PROVIDER_DATA_PROP_SET_COUNT,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* create or change the provider type property */
+ if (scf_transaction_property_new(tran, entry3,
+ STMF_PROVIDER_DATA_PROP_TYPE, SCF_TYPE_INTEGER) == -1) {
+ if (scf_error() == SCF_ERROR_EXISTS) {
+ if (scf_transaction_property_change(tran, entry3,
+ STMF_PROVIDER_DATA_PROP_TYPE,
+ SCF_TYPE_INTEGER) == -1) {
+ syslog(LOG_ERR,
+ "transaction property change %s/%s "
+ "failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ } else {
+ syslog(LOG_ERR, "transaction property new %s/%s "
+ "failed - %s", pgName, STMF_PROVIDER_DATA_PROP_TYPE,
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+ }
+
+ switch (providerType) {
+ case STMF_PORT_PROVIDER_TYPE:
+ case STMF_LU_PROVIDER_TYPE:
+ scf_value_set_integer(value3, providerType);
+ break;
+ default:
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ if (scf_entry_add_value(entry3, value3) == -1) {
+ syslog(LOG_ERR, "add value %s/%s failed - %s", pgName,
+ STMF_PROVIDER_DATA_PROP_TYPE, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+
+ if ((commitRet = scf_transaction_commit(tran)) != 1) {
+ syslog(LOG_ERR, "transaction commit for %s failed - %s",
+ pgName, scf_strerror(scf_error()));
+ if (commitRet == 0) {
+ ret = STMF_PS_ERROR_BUSY;
+ } else {
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /* pass the new token back to the caller if requested */
+ if (ret == STMF_PS_SUCCESS && setToken) {
+ *setToken = setCnt;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+ if (prop != NULL) {
+ scf_property_destroy(prop);
+ }
+ if (tran != NULL) {
+ scf_transaction_destroy(tran);
+ }
+ for (i = 0; i < addEntryAlloc; i++) {
+ scf_entry_destroy(addEntry[i]);
+ }
+ for (i = 0; i < addValueAlloc; i++) {
+ scf_value_destroy(addValue[i]);
+ }
+ free(addValue);
+ free(addEntry);
+ for (i = 0; i < deleteEntryAlloc; i++) {
+ scf_entry_destroy(deleteEntry[i]);
+ }
+ free(deleteEntry);
+ if (entry1 != NULL) {
+ scf_entry_destroy(entry1);
+ }
+ if (entry2 != NULL) {
+ scf_entry_destroy(entry2);
+ }
+ if (entry3 != NULL) {
+ scf_entry_destroy(entry3);
+ }
+ if (entry5 != NULL) {
+ scf_entry_destroy(entry5);
+ }
+ if (value1 != NULL) {
+ scf_value_destroy(value1);
+ }
+ if (value2 != NULL) {
+ scf_value_destroy(value2);
+ }
+ if (value3 != NULL) {
+ scf_value_destroy(value3);
+ }
+ if (value4 != NULL) {
+ scf_value_destroy(value4);
+ }
+ if (value5 != NULL) {
+ scf_value_destroy(value5);
+ }
+ if (nvlistEncoded != NULL) {
+ free(nvlistEncoded);
+ }
+
+ return (ret);
+}
+
+/*
+ * psGetViewEntry
+ *
+ * Purpose: Get a single view entry based on the logical unit identifier and
+ * view entry index
+ *
+ * lu - logical unit identifier
+ * viewEntryIndex - index of view entry
+ * ve - caller allocated stmfViewEntry structure. On success, this will
+ * contain the retrieved view entry
+ */
+int
+psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char luPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ pg = scf_pg_create(handle);
+ if (pg == NULL) {
+ syslog(LOG_ERR, "scf pg alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ /*
+ * Format of view entry property group name:
+ * VE-<view_entry_index>-<lu_name>
+ */
+ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
+ "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
+
+ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+
+ if ((ret = iPsGetViewEntry(viewEntryPgName, ve)) != STMF_PS_SUCCESS) {
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+out:
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ return (ret);
+}
+
+/*
+ * psRemoveViewEntry
+ *
+ * Remove a view entry
+ *
+ * luGuid - identifier of logical unit from which to remove view entry
+ * viewEntryIndex - view entry name to remove
+ *
+ * returns:
+ * STMF_PS_SUCCESS on success
+ * STMF_PS_ERROR_* on failure
+ */
+int
+psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
+{
+ scf_handle_t *handle = NULL;
+ scf_service_t *svc = NULL;
+ scf_propertygroup_t *pg = NULL;
+ char guidAsciiBuf[33]; /* size of ascii hex 16 byte guid with NULL */
+ char viewEntryPgName[VIEW_ENTRY_PG_SIZE];
+ char luPgName[LOGICAL_UNIT_PG_SIZE];
+ int ret = STMF_PS_SUCCESS;
+ sigset_t sigmaskRestore;
+
+ /* grab the signal hold lock */
+ (void) pthread_mutex_lock(&sigSetLock);
+
+ /*
+ * hold signals until we're done
+ */
+ if (holdSignal(&sigmaskRestore) != 0) {
+ (void) pthread_mutex_unlock(&sigSetLock);
+ return (STMF_PS_ERROR);
+ }
+
+ ret = iPsInit(&handle, &svc);
+ if (ret != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ pg = scf_pg_create(handle);
+ if (pg == NULL) {
+ syslog(LOG_ERR, "scf pg alloc failed - %s",
+ scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+ /* Convert to ASCII uppercase hexadecimal string */
+ (void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+ lu->guid[0], lu->guid[1], lu->guid[2], lu->guid[3], lu->guid[4],
+ lu->guid[5], lu->guid[6], lu->guid[7], lu->guid[8], lu->guid[9],
+ lu->guid[10], lu->guid[11], lu->guid[12], lu->guid[13],
+ lu->guid[14], lu->guid[15]);
+
+ (void) snprintf(luPgName, sizeof (luPgName), "%s-%s",
+ STMF_LU_PREFIX, guidAsciiBuf);
+
+ /*
+ * Format of view entry property group name:
+ * VE-<view_entry_index>-<lu_name>
+ */
+ (void) snprintf(viewEntryPgName, sizeof (viewEntryPgName),
+ "%s-%d-%s", STMF_VE_PREFIX, viewEntryIndex, guidAsciiBuf);
+
+ if (scf_service_get_pg(svc, viewEntryPgName, pg) == -1) {
+ if (scf_error() == SCF_ERROR_NOT_FOUND) {
+ ret = STMF_PS_ERROR_NOT_FOUND;
+ } else {
+ syslog(LOG_ERR, "get pg %s failed - %s",
+ viewEntryPgName, scf_strerror(scf_error()));
+ ret = STMF_PS_ERROR;
+ }
+ goto out;
+ }
+
+ /*
+ * update the logical unit property group to remove
+ * the view entry and update the view entry count
+ * If it fails, we won't delete the property group so that
+ * we maintain consistency.
+ */
+ if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ REMOVE)) != STMF_PS_SUCCESS) {
+ goto out;
+ }
+
+ /*
+ * Delete the view entry. If this fails, we should try to add
+ * the logical unit view entry property group back otherwise
+ * we're inconsistent.
+ */
+ if (scf_pg_delete(pg) == -1) {
+ syslog(LOG_ERR, "delete pg %s failed - %s", viewEntryPgName,
+ scf_strerror(scf_error()));
+ if ((ret = iPsAddRemoveLuViewEntry(luPgName, viewEntryPgName,
+ ADD)) != STMF_PS_SUCCESS) {
+ syslog(LOG_ERR, "add of view entry %s failed, possible"
+ "inconsistency - %s", viewEntryPgName,
+ scf_strerror(scf_error()));
+ }
+ ret = STMF_PS_ERROR;
+ goto out;
+ }
+
+out:
+ /*
+ * Okay, we're done. Release the signals
+ */
+ if (releaseSignal(&sigmaskRestore) != 0) {
+ /*
+ * Don't set this as an STMF_PS_ERROR_*. We succeeded
+ * the requested operation. But we do need to log it.
+ */
+ syslog(LOG_ERR, "Unable to release one or more signals - %s",
+ strerror(errno));
+ }
+
+ /*
+ * Free resources
+ */
+ if (handle != NULL) {
+ scf_handle_destroy(handle);
+ }
+ if (svc != NULL) {
+ scf_service_destroy(svc);
+ }
+ if (pg != NULL) {
+ scf_pg_destroy(pg);
+ }
+
+ /* release the signal hold lock */
+ (void) pthread_mutex_unlock(&sigSetLock);
+
+ return (ret);
+}
+
+
+
+/*
+ * holdSignal
+ *
+ * Hold SIGINT, SIGTERM, SIGQUIT until further notice.
+ *
+ * Saves old signal mask on a per thread basis
+ * and saves action for the process.
+ *
+ * Installs action for above signals.
+ *
+ * locks held: sigSetLock
+ *
+ * returns:
+ * 0 on success
+ * non-zero otherwise
+ */
+static int
+holdSignal(sigset_t *sigmaskRestore)
+{
+ struct sigaction act;
+ sigset_t sigmask;
+
+ /*
+ * Return existing signal mask for this thread
+ */
+ if (pthread_sigmask(0, NULL, sigmaskRestore) != 0) {
+ return (1);
+ }
+
+ (void) sigemptyset(&act.sa_mask);
+ act.sa_handler = sigHandler;
+ act.sa_flags = 0;
+
+ /*
+ * Have we set the actions for the signals we want to catch?
+ */
+ if (!actionSet) {
+ if (sigaction(SIGQUIT, &act, &currentActionQuit) != 0) {
+ return (1);
+ }
+
+ if (sigaction(SIGINT, &act, &currentActionInt) != 0) {
+ return (1);
+ }
+
+ if (sigaction(SIGTERM, &act, &currentActionTerm) != 0) {
+ return (1);
+ }
+
+ actionSet = B_TRUE;
+ }
+
+ /*
+ * We still need to change the mask for the current thread
+ */
+ if (sigfillset(&sigmask) != 0) {
+ return (1);
+ }
+
+ (void) sigdelset(&sigmask, SIGQUIT);
+
+ (void) sigdelset(&sigmask, SIGINT);
+
+ (void) sigdelset(&sigmask, SIGTERM);
+
+ if (pthread_sigmask(SIG_SETMASK, &sigmask, NULL) != 0) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * releaseSignal
+ *
+ * Re-install the original signal mask and signal actions
+ *
+ * Also, raise any signals that were caught during the hold period and clear
+ * the signal from the caught set (signalsCaught).
+ *
+ * locks held: sigSetLock
+ *
+ * Returns
+ * 0 on success
+ * non-zero otherwise
+ */
+static int
+releaseSignal(sigset_t *sigmaskRestore)
+{
+ int ret = 0;
+
+ if (sigaction(SIGQUIT, &currentActionQuit, NULL) != 0) {
+ ret = 1;
+ }
+
+ if (sigaction(SIGINT, &currentActionInt, NULL) != 0) {
+ ret = 1;
+ }
+
+ if (sigaction(SIGTERM, &currentActionTerm, NULL) != 0) {
+ ret = 1;
+ }
+
+ actionSet = B_FALSE;
+
+ /*
+ * Restore previous signal mask for this thread
+ */
+ if (pthread_sigmask(SIG_SETMASK, sigmaskRestore, NULL) != 0) {
+ syslog(LOG_ERR, "Unable to restore sigmask");
+ }
+
+ /*
+ * Now raise signals that were raised while we were held
+ */
+ if (sigismember(&signalsCaught, SIGTERM)) {
+ (void) sigdelset(&signalsCaught, SIGTERM);
+ (void) raise(SIGTERM);
+ }
+
+ if (sigismember(&signalsCaught, SIGINT)) {
+ (void) sigdelset(&signalsCaught, SIGINT);
+ (void) raise(SIGINT);
+ }
+
+ if (sigismember(&signalsCaught, SIGQUIT)) {
+ (void) sigdelset(&signalsCaught, SIGQUIT);
+ (void) raise(SIGQUIT);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/lib/libstmf/common/store.h b/usr/src/lib/libstmf/common/store.h
new file mode 100644
index 0000000..48eb547
--- /dev/null
+++ b/usr/src/lib/libstmf/common/store.h
@@ -0,0 +1,84 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+#ifndef _STORE_H
+#define _STORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libnvpair.h>
+
+/*
+ * Error defines
+ */
+#define STMF_PS_SUCCESS 0
+#define STMF_PS_ERROR 1
+#define STMF_PS_ERROR_MEMBER_NOT_FOUND 2
+#define STMF_PS_ERROR_GROUP_NOT_FOUND 3
+#define STMF_PS_ERROR_NOT_FOUND 4
+#define STMF_PS_ERROR_EXISTS 5
+#define STMF_PS_ERROR_NOMEM 6
+#define STMF_PS_ERROR_RETRY 7
+#define STMF_PS_ERROR_BUSY 8
+#define STMF_PS_ERROR_SERVICE_NOT_FOUND 9
+#define STMF_PS_ERROR_INVALID_ARG 10
+#define STMF_PS_ERROR_VERSION_MISMATCH 11
+#define STMF_PS_ERROR_PROV_DATA_STALE 12
+
+int psAddHostGroupMember(char *groupName, char *memberName);
+int psAddTargetGroupMember(char *groupName, char *memberName);
+int psAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry);
+int psCreateHostGroup(char *groupName);
+int psDeleteHostGroup(char *groupName);
+int psCreateTargetGroup(char *groupName);
+int psDeleteTargetGroup(char *groupName);
+int psGetViewEntry(stmfGuid *lu, uint32_t viewEntryIndex, stmfViewEntry *ve);
+int psGetLogicalUnitList(stmfGuidList **guidList);
+int psRemoveHostGroupMember(char *groupName, char *memberName);
+int psRemoveTargetGroupMember(char *groupName, char *memberName);
+int psRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex);
+int psGetHostGroupList(stmfGroupList **groupList);
+int psGetTargetGroupList(stmfGroupList **groupList);
+int psGetHostGroupMemberList(char *groupName, stmfGroupProperties **groupList);
+int psGetTargetGroupMemberList(char *groupName,
+ stmfGroupProperties **groupList);
+int psGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList);
+int psCheckService();
+int psSetProviderData(char *providerName, nvlist_t *nvl, int providerType,
+ uint64_t *setHandle);
+int psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
+ uint64_t *setHandle);
+int psGetProviderDataList(stmfProviderList **providerList);
+int psClearProviderData(char *providerName, int providerType);
+int psSetServicePersist(uint8_t persistType);
+int psGetServicePersist(uint8_t *persistType);
+int psSetStmfProp(int propType, char *propVal);
+int psGetStmfProp(int propType, char *propVal);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STORE_H */
diff --git a/usr/src/man/man1m/stmfadm.1m b/usr/src/man/man1m/stmfadm.1m
new file mode 100644
index 0000000..3fe7cd3
--- /dev/null
+++ b/usr/src/man/man1m/stmfadm.1m
@@ -0,0 +1,1136 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved
+.\" 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]
+.TH STMFADM 1M "Jul 30, 2009"
+.SH NAME
+stmfadm \- SCSI target mode framework command line interface
+.SH SYNOPSIS
+.LP
+.nf
+\fBstmfadm\fR \fBadd-hg-member\fR \fB-g\fR, \fB--group-name\fR \fIgroup-name\fR \fIgroup-member\fR...
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBadd-tg-member\fR \fB-g\fR, \fB--group-name\fR \fIgroup-name\fR \fIgroup-member\fR...
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBadd-view\fR [\fB-n\fR, \fB--lun\fR \fIlogical-unit-number\fR
+ \fB-t\fR, \fB--target-group\fR \fIgroup-name\fR \fB-h\fR, \fB--host-group\fR \fIgroup-name\fR] \fIlu-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBcreate-hg\fR \fIgroup-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBcreate-lu\fR [\fB-p\fR, \fB--lu-prop\fR \fIlogical-unit-property\fR=\fIval\fR
+ \fB-s\fR, \fB--size\fR \fIsize\fR] \fIlu-file\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBcreate-tg\fR \fIgroup-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBdelete-hg\fR \fIgroup-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBdelete-lu\fR \fIlu-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBdelete-tg\fR \fIgroup-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBimport-lu\fR \fIlu-file\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBlist-hg\fR [\fB-v\fR] [\fIhost-group-name\fR...]
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBlist-tg\fR [\fB-v\fR] [\fItarget-group-name\fR...]
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBlist-lu\fR [\fB-v\fR] [\fIlu-name\fR...]
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBlist-target\fR [\fB-v\fR] [\fItarget-name\fR...]
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBlist-view\fR \fB-l\fR, \fB--lu-name\fR \fIlu-name\fR [\fIentry-name\fR...]
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBlist-state\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBmodify-lu\fR [\fB-p\fR, \fB--lu-prop\fR \fIlogical-unit-property\fR=\fIval\fR
+ \fB-s\fR, \fB--size\fR \fIsize\fR, \fB-f\fR, \fB--file\fR] \fIlu-name\fR|\fIlu-file\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBonline-lu\fR \fIlu-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBoffline-lu\fR \fIlu-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBonline-lu\fR \fItarget-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBoffline-lu\fR \fItarget-name\fR
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBremove-hg-member\fR \fB-g\fR, \fB--group-name\fR \fIgroup-name\fR \fIgroup-member\fR...
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBremove-tg-member\fR \fB-g\fR, \fB--group-name\fR \fIgroup-name\fR \fIgroup-member\fR...
+.fi
+
+.LP
+.nf
+\fBstmfadm\fR \fBremove-view\fR \fB-l\fR, \fB--lu-name\fR \fIlu-name\fR \fIentry-name\fR
+.fi
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfadm\fR command configures logical units within the SCSI Target Mode
+Framework (STMF) framework. The framework and this man page use the following
+terminology:
+.sp
+.ne 2
+.na
+\fB\fBinitiator\fR\fR
+.ad
+.sp .6
+.RS 4n
+A device responsible for issuing SCSI I/O commands to a SCSI target and logical
+unit.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBtarget\fR\fR
+.ad
+.sp .6
+.RS 4n
+A device responsible for receiving SCSI I/O commands for a logical unit.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlogical unit\fR\fR
+.ad
+.sp .6
+.RS 4n
+A device within a target responsible for executing SCSI I/O commands.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlogical unit number\fR\fR
+.ad
+.sp .6
+.RS 4n
+The identifier of a logical unit within a target.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBinitiator group\fR\fR
+.ad
+.sp .6
+.RS 4n
+An initiator group is a set of one or more initiators that are combined for the
+purposes of being applied to a \fBview\fR (see below). An initiator cannot be a
+member of more than one initiator group.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBtarget group\fR\fR
+.ad
+.sp .6
+.RS 4n
+A target group is a set of one or more SCSI target ports that are treated the
+same when creating a \fBview\fR (see below). The set of logical units that a
+particular SCSI initiator can see is determined by the combined set of views.
+.sp
+Each logical unit has a set of view entries, and each view entry specifies a
+target group, host group, and a LUN. An initiator from that host group, when
+connecting through that target group, is able to identify and connect to that
+logical unit using the specified LUN. You can use views to restrict the set of
+logical units that a specific initiator can see, and assign the set of LUNs
+that will be used.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBview\fR\fR
+.ad
+.sp .6
+.RS 4n
+A view defines the association of an initiator group, a target group, and a
+logical unit number with a specified logical unit. Any view entry added to a
+logical unit must not be in conflict with existing view entries for that
+logical unit. A view entry is considered to be in conflict when an attempt is
+made to duplicate the association of any given initiator, target and logical
+unit number. As an example, logical unit \fBLU_0\fR has the following view
+entry associated with it:
+.sp
+.in +2
+.nf
+Logical Unit: LU_0
+ View Entry: 0
+ initiator group: HostA
+ target group: All targets
+ logical unit number: 32
+.fi
+.in -2
+.sp
+
+If you attempted the following:
+.sp
+.in +2
+.nf
+# \fBstmf add-view -n 31 -h HostA LU_0\fR
+.fi
+.in -2
+.sp
+
+\&...the operation would return an error with a message indicating that the
+view entry is in conflict with one or more existing view entries. This conflict
+arises because the existing view entry, \fB0\fR, already has mapped \fBLU_0\fR
+to logical unit number 32 for the initiator group \fBHostA\fR.
+.RE
+
+.SH SUB-COMMANDS
+.sp
+.LP
+The \fBstmfadm\fR command supports the subcommands listed below.
+.sp
+.ne 2
+.na
+\fB\fBadd-view\fR [\fB-n\fR, \fB--lun\fR \fIlogical-unit-number\fR \fB-t\fR,
+\fB--target-group\fR \fIgroup-name\fR \fB-h\fR, \fB--host-group\fR
+\fIgroup-name\fR] \fIlu-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Adds a logical unit view entry to a logical unit \fIlu-name\fR, where
+\fIlu-name\fR is the STMF name for the logical unit as displayed by the
+\fBlist-lu\fR subcommand. The \fBadd-view\fR subcommand provides the user with
+a mechanism to implement access control for a logical unit and also provides a
+means of assigning a logical unit number to a logical unit for a given set of
+initiators and targets. A logical unit will not be available to any initiators
+until at least one view is applied. Each view entry gets assigned an entry
+name, which can be used to reference the entry in the \fBremove-view\fR and
+\fBlist-view\fR subcommands.
+.sp
+\fBadd-view\fR supports the following options:
+.sp
+.ne 2
+.na
+\fB\fB-n\fR, \fB--lun\fR \fIlogical-unit-number\fR\fR
+.ad
+.sp .6
+.RS 4n
+\fIlogical-unit-number\fR is an integer in the range 0-16383 to be assigned to
+the logical unit for this view entry. If this option is not specified, a
+logical unit number will be assigned by the STMF framework.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-t\fR, \fB--target-group\fR \fIgroup-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+\fIgroup-name\fR is the name of a target group previously created using the
+STMF \fBcreate-tg\fR subcommand. If this option is not specified, the logical
+unit will be available through all targets.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-h\fR, \fB-host-group\fR \fIgroup-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+\fIgroup-name\fR is the name of an host group previously created using the STMF
+\fBcreate-hg\fR subcommand. If this option is not specified, the logical unit
+will be available to all initiators that log in to the STMF framework.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBadd-hg-member\fR \fB-g\fR \fIgroup-name\fR \fIgroup member\fR...\fR
+.ad
+.sp .6
+.RS 4n
+Add a host group member to a host group. \fIgroup-name\fR must be an existing
+group created using the \fBcreate-hg\fR subcommand. \fIgroup member\fR can be
+specified as \fIname_type\fR.\fIname_value\fR, where \fIname_type\fR can be one
+of the following:
+.sp
+.in +2
+.nf
+wwn
+iqn
+eui
+.fi
+.in -2
+.sp
+
+\&...and \fIname_value\fR is the value of the initiator name. As an example, to
+add a fibre channel initiator port world-wide name \fB200000e08b909221\fR to
+the host group \fBHostA\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm add-hg-member -g HostA wwn.200000e08b909221\fR
+.fi
+.in -2
+.sp
+
+To add an ISCSI initiator node member with the name
+\fBiqn.1986-03.com.sun:01.46f7e262\fR to \fBHostA\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm add-hg-member -g HostA iqn.1986-03.com.sun:01.46f7e262\fR
+.fi
+.in -2
+.sp
+
+Alternatively, members can be specified using their SCSI name string
+identifiers. To add the two initiators above using their SCSI name string
+identifiers, the commands would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm add-hg-member -g HostA eui.200000e08b909221\fR
+# \fBstmfadm add-hg-member -g HostA iqn.1986-03.com.sun:01.46f7e262\fR
+.fi
+.in -2
+.sp
+
+A host group member cannot be a member of more than one host group.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBadd-tg-member\fR \fB-g\fR \fIgroup-name\fR \fIgroup member\fR...\fR
+.ad
+.sp .6
+.RS 4n
+Add a target group member to a target group. \fIgroup-name\fR must be an
+existing group created using the \fBcreate-tg\fR subcommand. \fIgroup member\fR
+can be specified as \fIname_type\fR.\fIname_value\fR, where \fIname_type\fR can
+be one of the following:
+.sp
+.in +2
+.nf
+wwn
+iqn
+eui
+.fi
+.in -2
+.sp
+
+\&...and \fIname_value\fR is the value of the target name. As an example, to
+add a fibre channel target port world-wide name \fB501000e092376af7\fR to the
+target group \fBTG0\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm add-tg-member -g TG0 wwn.501000e092376af7\fR
+.fi
+.in -2
+.sp
+
+To add an ISCSI target member with the name
+\fBiqn.1986-03.com.sun:target.01.01110\fR to \fBTG0\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm add-tg-member -g TG0 iqn.1986-03.com.sun:target.01.01110\fR
+.fi
+.in -2
+.sp
+
+Alternatively, members can be specified using their SCSI name string
+identifiers. To add the two targets above using their SCSI name string
+identifiers, the commands would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm add-tg-member -g TG0 eui.501000e092376af7\fR
+# \fBstmfadm add-tg-member -g TG0 iqn.1986-03.com.sun:target.01.01110\fR
+.fi
+.in -2
+.sp
+
+A target group member cannot be a member of more than one target group.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcreate-hg\fR \fIgroup-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Create an initiator group with the name \fIgroup-name\fR. \fIgroup-name\fR is a
+string of Unicode characters with a maximum length of 255. The group name must
+be unique within the STMF system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcreate-lu\fR [\fB-p\fR, \fB--lu-prop\fR
+\fIlogical-unit-property\fR=\fIval\fR \fB--s\fR, \fB--size\fR \fIsize\fR]
+\fIlu-file\fR\fR
+.ad
+.sp .6
+.RS 4n
+Create a logical unit that can be registered with STMF. For the \fB-p\fR
+option, \fIlogical-unit-property\fR can be one of the following properties:
+.sp
+.ne 2
+.na
+\fB\fBalias\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 255 characters, representing a user-defined name for the device. The
+default is the name of the backing store.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBblk\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies the block size for the device. The default is 512.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBguid\fR\fR
+.ad
+.sp .6
+.RS 4n
+Thirty-two hexadecimal ASCII characters representing a valid NAA Registered
+Extended Identifier. The default is set by the STMF to a generated value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmeta\fR\fR
+.ad
+.sp .6
+.RS 4n
+Metadata file name. When specified, will be used to hold the SCSI metadata for
+the logical unit. There is no default.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmgmt-url\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 1024 characters representing a Management Network Address URL. More than
+one URL can be passed as a single parameter by using space-delimited URLs
+enclosed inside a single pair of quotation marks (\fB"\fR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBoui\fR\fR
+.ad
+.sp .6
+.RS 4n
+Organizational Unique Identifier. Six hexadecimal ASCII characters representing
+the IEEE OUI company ID assignment. This will be used to generate the device
+identifier (GUID). The default is \fB00144F\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBpid\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sixteen characters of product identification SCSI SPC-3. This value will be
+reflected in the Standard \fBINQUIRY\fR data returned for the device. The
+default is \fBCOMSTAR\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBserial\fR\fR
+.ad
+.sp .6
+.RS 4n
+Serial Number. Specifies the SCSI Vital Product Data Serial Number (page
+\fB80h\fR). It is a character value up to 252 bytes in length. There is no
+default value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBvid\fR\fR
+.ad
+.sp .6
+.RS 4n
+Eight characters of vendor identification per SCSI SPC-3. This value will be
+reflected in the Standard \fBINQUIRY\fR data returned for the device. The
+default is \fBSUN\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwcd\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write-back cache disable. Specify \fBtrue\fR or \fBfalse\fRto determine
+write-back cache disable behavior. The default is the write-back cache setting
+of the backing store device specified by the \fIlu-file\fR argument.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwp\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write-protect bit. Specify \fBtrue\fR or \fBfalse\fR to determine whether the
+device reports as write-protected. The default is \fBfalse\fR.
+.RE
+
+For the \fB-s\fR option, \fIsize\fR is an integer followed by one of the
+following letters, to indicate a unit of size:
+.sp
+.ne 2
+.na
+\fB\fBk\fR\fR
+.ad
+.RS 5n
+kilobyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBm\fR\fR
+.ad
+.RS 5n
+megabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBg\fR\fR
+.ad
+.RS 5n
+gigabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBt\fR\fR
+.ad
+.RS 5n
+terabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBp\fR\fR
+.ad
+.RS 5n
+petabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBe\fR\fR
+.ad
+.RS 5n
+exabyte
+.RE
+
+\fIlu-file\fR is the file to be used as the backing store for the logical unit.
+If the \fB-s\fR option is not specified, the size of the specified
+\fIlu-file\fR will be used as the size of the logical unit. Logical units
+registered with the STMF require space for the metadata to be stored. When a
+\fBzvol\fR is specified as the backing store device, the default will be to use
+a special property of the \fBzvol\fR to contain the metadata. For all other
+devices, the default behavior will be to use the first 64k of the device. An
+alternative approach would be to use the \fBmeta\fR property in a
+\fBcreate-lu\fR command to specify an alternate file to contain the metadata.
+It is advisable to use a file that can provide sufficient storage of the
+logical unit metadata, preferably 64k.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcreate-tg\fR \fIgroup-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Create a target group with the name \fIgroup-name\fR. \fIgroup-name\fR is a
+string of Unicode characters with a maximum length of 255. The group name must
+be unique within the STMF system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdelete-hg\fR \fIgroup-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Delete the host group that identified by \fIgroup-name\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdelete-lu\fR \fIlu-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Deletes an existing logical unit that was created using \fBstmfadm
+create-lu\fR. This effectively unloads the logical unit from the STMF
+framework. Any existing data on the logical unit remains intact.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdelete-tg\fR \fIgroup-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Delete the target group that identified by \fIgroup-name\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBimport-lu\fR \fIlu-file\fR\fR
+.ad
+.sp .6
+.RS 4n
+Imports and loads a logical unit into the STMF that was previously created
+using \fBstmfadm create-lu\fR and was then deleted from the STMF using
+\fBstmfadm delete-lu\fR. On success, the logical unit is again made available
+to the STMF. \fIlu-file\fR is the filename used in the \fBstmfadm create-lu\fR
+command. If this logical unit is using a separate metadata file, the filename
+in the \fBmeta\fR property value that was used in the \fBstmfadm create-lu\fR
+command must be used here.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlist-hg\fR [\fB-v\fR,\fB--verbose\fR] [\fIhost-group-name\fR...]\fR
+.ad
+.sp .6
+.RS 4n
+Lists information for the host group in the system referenced by
+\fIhost-group-name\fR. If \fIhost-group-name\fR is not specified, all host
+groups in the system will be listed. If the \fB--v\fR or \fB--verbose\fR option
+is specified, all members within a host group are displayed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlist-lu\fR [\fB-v\fR,\fB--verbose\fR] [\fIlu-name\fR...]\fR
+.ad
+.sp .6
+.RS 4n
+Lists information for the logical unit in the system referenced by
+\fIlu-name\fR. If \fIlu-name\fR is not specified, all logical units in the
+system will be listed. If the \fB-v\fR or \fB--verbose\fR option is specified,
+additional information about the logical unit will be displayed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlist-target\fR [\fB-v\fR,\fB--verbose\fR] [\fItarget-name\fR...]\fR
+.ad
+.sp .6
+.RS 4n
+Lists information for the target port in the system referenced by
+\fItarget-name\fR. If target name is not specified, all target ports in the
+system will be listed. If the \fB-v\fR or \fB--verbose\fR option is specified,
+additional information about the target along with SCSI session information for
+logged-in initiators is displayed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlist-tg\fR [\fB-v\fR,\fB--verbose\fR] [\fItarget-group-name\fR...]\fR
+.ad
+.sp .6
+.RS 4n
+Lists information for the target group in the system referenced by
+\fItarget-group-name\fR. If \fItarget-group-name\fR is not specified, all
+target groups in the system will be listed. If the \fB--v\fR or \fB--verbose\fR
+option is specified, all members within a target group are displayed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlist-view\fR \fB--l\fR, \fB--lu-name\fR \fIlu-name\fR
+[\fIentry-name\fR...]\fR
+.ad
+.sp .6
+.RS 4n
+Lists the view entry for the logical unit referenced by \fIlu-name\fR. If
+\fIentry-name\fR is not specified, all view entries for the specified logical
+unit will be listed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmodify-lu\fR [\fB-p\fR, \fB--lu-prop\fR
+\fIlogical-unit-property\fR=\fIval\fR \fB--s\fR, \fB--size\fR \fIsize\fR,
+\fB-f\fR, \fB--file\fR] \fIlu-name\fR|\fIlu-file\fR\fR
+.ad
+.sp .6
+.RS 4n
+Modifies attributes of a logical unit created using the \fBstmfadm create-lu\fR
+command. For the \fB-p\fR option, \fIlogical-unit-property\fR can be one of the
+following properties:
+.sp
+.ne 2
+.na
+\fB\fBalias\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 255 characters, representing a user-defined name for the device. The
+default is the name of the backing store.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmgmt-url\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 1024 characters representing a Management Network Address URL. More than
+one URL can be passed as a single parameter by using space-delimited URLs
+enclosed inside a single pair of quotation marks (\fB"\fR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwcd\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write-back cache disable. Specify \fBtrue\fR or \fBfalse\fRto determine
+write-back cache disable behavior. The default is the write-back cache setting
+of the backing store device specified by the \fIlu-file\fR argument.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwp\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write-protect bit. Specify \fBtrue\fR or \fBfalse\fR to determine whether the
+device reports as write-protected. The default is \fBfalse\fR.
+.RE
+
+For the \fB-s\fR option, \fIsize\fR is an integer followed by one of the
+following letters, to indicate a unit of size:
+.sp
+.ne 2
+.na
+\fB\fBk\fR\fR
+.ad
+.RS 5n
+kilobyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBm\fR\fR
+.ad
+.RS 5n
+megabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBg\fR\fR
+.ad
+.RS 5n
+gigabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBt\fR\fR
+.ad
+.RS 5n
+terabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBp\fR\fR
+.ad
+.RS 5n
+petabyte
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBe\fR\fR
+.ad
+.RS 5n
+exabyte
+.RE
+
+\fIlu-name\fR is the \fBguid\fR of the logical unit to be modified. If the
+\fB-f\fR option is specified, the operand is interpreted as a file name. This
+provides the ability to modify a logical unit that is not currently imported
+into the STMF.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBonline-lu\fR \fIlu-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Online a logical unit currently registered with the STMF.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBonline-target\fR \fItarget-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Online the specified target.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBoffline-lu\fR \fIlu-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Offline a logical unit currently registered with the STMF.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBoffline-target\fR \fItarget-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Online the specified target.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlist-state\fR\fR
+.ad
+.sp .6
+.RS 4n
+Lists the operational and configuration state of the STMF.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBremove-hg-member\fR \fB-g\fR \fIgroup-name\fR \fIgroup member\fR\fR
+.ad
+.sp .6
+.RS 4n
+Removes a host group member from a host group. \fIgroup-name\fR must be an
+existing group created using the \fBcreate-hg\fR subcommand. \fIgroup member\fR
+can be specified as \fIname_type\fR.\fIname_value\fR, where \fIname_type\fR can
+be one of the following:
+.sp
+.in +2
+.nf
+wwn
+iqn
+eui
+.fi
+.in -2
+.sp
+
+\&...and \fIname_value\fR is the value of the initiator name. As an example, to
+remove the fibre channel initiator port world-wide name \fB200000e08b909221\fR
+from the host group \fBHostA\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm remove-hg-member -g HostA wwn.200000e08b909221\fR
+.fi
+.in -2
+.sp
+
+To remove the ISCSI initiator node member with the name
+\fBiqn.1986-03.com.sun:01.46f7e262\fR from \fBHostA\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm remove-hg-member -g HostA iqn.1986-03.com.sun:01.46f7e262\fR
+.fi
+.in -2
+.sp
+
+Alternatively, members can be specified using their SCSI name string
+identifiers. To remove the two initiators above using their SCSI name string
+identifiers, the commands would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm remove-hg-member -g HostA eui.200000e08b909221\fR
+# \fBstmfadm remove-hg-member -g HostA iqn.1986-03.com.sun:01.46f7e262\fR
+.fi
+.in -2
+.sp
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBremove-tg-member\fR \fB-g\fR \fIgroup-name\fR \fIgroup member\fR\fR
+.ad
+.sp .6
+.RS 4n
+Removes a target group member from a target group. \fIgroup-name\fR must be an
+existing group created using the \fBcreate-tg\fR subcommand. \fIgroup member\fR
+can be specified as \fIname_type\fR.\fIname_value\fR, where \fIname_type\fR can
+be one of the following:
+.sp
+.in +2
+.nf
+wwn
+iqn
+eui
+.fi
+.in -2
+.sp
+
+\&...and \fIname_value\fR is the value of the target name. As an example, to
+remove the fibre channel target port world-wide name \fB501000e092376af7\fR
+from the target group \fBTG0\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm remove-tg-member -g TG0 wwn.501000e092376af7\fR
+.fi
+.in -2
+.sp
+
+To remove the ISCSI target member with the name
+\fBiqn.1986-03.com.sun:target.01.01110\fR from \fBTG0\fR, the command would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm remove-tg-member -g TG0 iqn.1986-03.com.sun:target.01.01110\fR
+.fi
+.in -2
+.sp
+
+Alternatively, members can be specified using their SCSI name string
+identifiers. To remove the two targets above using their SCSI name string
+identifiers, the commands would be:
+.sp
+.in +2
+.nf
+# \fBstmfadm remove-tg-member -g TG0 eui.501000e092376af7\fR
+# \fBstmfadm remove-tg-member -g TG0 iqn.1986-03.com.sun:target.01.01110\fR
+.fi
+.in -2
+.sp
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBremove-view\fR \fB--l\fR, \fB--lu-name\fR \fIlu-name\fR
+\fIentry-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Removes one or more logical unit view entries from a logical unit.
+.RE
+
+.SH EXAMPLES
+.LP
+\fBExample 1 \fRCreating a Host group with Two Initiator Ports
+.sp
+.LP
+The following commands use the \fBcreate-hg\fR and \fBadd-hg-member\fR
+subcommands to create a host group and add two initiator ports to that host
+group.
+
+.sp
+.in +2
+.nf
+# \fBstmfadm create-hg host-group-a\fR
+# \fBstmfadm add-hg-member -g host-group-a wwn.210105b0000d92d0\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 2 \fRAdding a View Entry to a Logical Unit
+.sp
+.LP
+The following command uses the \fBadd-view\fR subcommand to allow access from
+\fBhost-group-a\fR to a logical unit.
+
+.sp
+.in +2
+.nf
+# \fBstmfadm add-view -h host-group-a 6000AE40C5000000000046FC4FEA001C\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 3 \fRListing a View Entry
+.sp
+.LP
+The following command uses the \fBlist-view\fR subcommand to list all view
+entries for the specified logical unit.
+
+.sp
+.in +2
+.nf
+# \fBstmfadm list-view -l 6000AE40C5000000000046FC4FEA001C\fR
+View Entry: 0
+ Host group : host-group-a
+ Target group : All
+ LUN : 0
+.fi
+.in -2
+.sp
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBsbdadm\fR(1M), \fBattributes\fR(5)
diff --git a/usr/src/man/man3lib/libstmf.3lib b/usr/src/man/man3lib/libstmf.3lib
new file mode 100644
index 0000000..049446b
--- /dev/null
+++ b/usr/src/man/man3lib/libstmf.3lib
@@ -0,0 +1,201 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems, Inc. All rights reserved.
+.\" 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]
+.TH LIBSTMF 3LIB "May 8, 2009"
+.SH NAME
+libstmf \- SCSI Target Mode Framework library
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+.fi
+
+.SH DESCRIPTION
+.sp
+.LP
+Functions in this library provide configuration management of the SCSI Target
+Mode Framework (STMF), allowing clients to manage the provisioning of logical
+units and targets to the initiator clients of the framework.
+.SS "Definitions"
+.sp
+.ne 2
+.na
+\fBHost Group\fR
+.ad
+.sp .6
+.RS 4n
+A Host Group is a set of one or more initiator ports that are combined together
+for the purposes of applying access controls to a Logical Unit object and
+assigning a logical unit number to the Logical Unit. The assigned logical unit
+number will be reported to the members of that Host Group via the SCSI REPORT
+LUN command. Host Groups can contain initiator ports that are not visible to
+the SCSI Target Mode Framework. Initiator ports might not be a member in more
+than one group. A Host Group is associated with a given Logical Unit via a view
+entry. Host Group names are unique within the framework.
+.RE
+
+.sp
+.ne 2
+.na
+\fBLogical Unit\fR
+.ad
+.sp .6
+.RS 4n
+A Logical Unit object is provided to the SCSI Target Mode Framework for the
+purposes of executing SCSI commands. Library clients can manage a Logical Unit
+object's accessibility to one or more SCSI initiator clients. \fBlibstmf\fR
+library clients cannot add or remove Logical Unit objects from the system.
+Every Logical Unit object within the SCSI Target Mode Framework is owned by a
+logical unit provider whose identity is available via the properties on the
+Logical Unit object.
+.RE
+
+.sp
+.ne 2
+.na
+\fBLogical Unit Number\fR
+.ad
+.sp .6
+.RS 4n
+A Logical Unit Number is the SCSI identifier of a logical unit within a target.
+.RE
+
+.sp
+.ne 2
+.na
+\fBTarget Port\fR
+.ad
+.sp .6
+.RS 4n
+A Target port object is provided to the SCSI Target Mode Framework for the
+purposes of receiving SCSI commands on a particular logical unit. Library
+clients can manage a Logical Unit object's availability to one or more Target
+port objects. Library clients cannot add or remove Target objects from the
+system. Every Target port object within the SCSI Target Mode Framework is owned
+by a Local Port provider whose identity is available via the properties on the
+Target port object.
+.RE
+
+.sp
+.ne 2
+.na
+\fBTarget Port Group\fR
+.ad
+.sp .6
+.RS 4n
+A Target Port Group is a set of one or more Target ports that are combined
+together for the purposes of applying availability to a Logical Unit object. A
+Target Port Group may be applied to any given Logical Unit via a view entry.
+Target ports may not be a member in more than one Target Port Group. Target
+Port Group names are unique within the framework.
+.RE
+
+.sp
+.ne 2
+.na
+\fBView\fR
+.ad
+.sp .6
+.RS 4n
+A View is a list of logical units exposed to a list of initiator ports through
+a list of targets.
+.RE
+
+.sp
+.ne 2
+.na
+\fBView Entry\fR
+.ad
+.sp .6
+.RS 4n
+A View Entry object defines the association of an host group, a target group
+and a logical unit number with a specified logical unit. When a view entry is
+created for a logical unit, a caller can assign all targets and/or all
+initiator ports to the logical unit thus making the logical unit accessible to
+all target ports and/or all initiator ports. A logical unit may have one or
+more view entries associated with it. Any two view entries are considered to be
+in conflict when an attempt is made to duplicate the association of any given
+initiator port, target port and logical unit. Attempting this will result in an
+error returned from the call to \fBstmfAddViewEntry\fR(3STMF).
+.RE
+
+.SH INTERFACES
+.sp
+.LP
+The shared object \fBlibstmf.so.1\fR provides the public interfaces defined
+below. See \fBIntro\fR(3) for additional information on shared object
+interfaces.
+.sp
+
+.sp
+.TS
+l l
+l l .
+\fBstmfAddToHostGroup\fR \fBstmfAddToTargetGroup\fR
+\fBstmfAddViewEntry\fR \fBstmfClearProviderData\fR
+\fBstmfCreateHostGroup\fR \fBstmfCreateLu\fR
+\fBstmfCreateLuResource\fR \fBstmfCreateTargetGroup\fR
+\fBstmfDeleteHostGroup\fR \fBstmfDeleteLu\fR
+\fBstmfDeleteTargetGroup\fR \fBstmfDevidFromIscsiName\fR
+\fBstmfDevidFromWwn\fR \fBstmfFreeLuResource\fR
+\fBstmfFreeMemory\fR \fBstmfGetHostGroupList\fR
+\fBstmfGetHostGroupMembers\fR \fBstmfGetLogicalUnitList\fR
+\fBstmfGetLogicalUnitProperties\fR \fBstmfGetLuProp\fR
+\fBstmfGetLuResource\fR \fBstmfGetPersistMethod\fR
+\fBstmfGetProviderData\fR \fBstmfGetProviderDataProt\fR
+\fBstmfGetState\fR \fBstmfGetTargetGroupList\fR
+\fBstmfGetTargetGroupMembers\fR \fBstmfGetTargetList\fR
+\fBstmfGetTargetProperties\fR \fBstmfGetViewEntryList\fR
+\fBstmfModifyLu\fR \fBstmfModifyLuByFname\fR
+\fBstmfOfflineLogicalUnit\fR \fBstmfOfflineTarget\fR
+\fBstmfOnlineLogicalUnit\fR \fBstmfOnlineTarget\fR
+\fBstmfRemoveFromHostGroup\fR \fBstmfRemoveFromTargetGroup\fR
+\fBstmfRemoveViewEntry\fR \fBstmfSetLuProp\fR
+\fBstmfSetPersistMethod\fR \fBstmfSetProviderData\fR
+\fBstmfSetProviderDataProt\fR
+.TE
+
+.SH FILES
+.sp
+.ne 2
+.na
+\fB\fB/lib/libstmf.so.1\fR\fR
+.ad
+.RS 24n
+shared object
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB/lib/64/libstmf.so.1\fR\fR
+.ad
+.RS 24n
+64-bit shared object
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBIntro\fR(3), \fBstmfAddViewEntry\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfAddToHostGroup.3stmf b/usr/src/man/man3stmf/stmfAddToHostGroup.3stmf
new file mode 100644
index 0000000..fbaabb2
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfAddToHostGroup.3stmf
@@ -0,0 +1,96 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFADDTOHOSTGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfAddToHostGroup \- add an initiator port to an existing host group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfAddToHostGroup\fR(\fBstmfGroupName *\fR\fIhostGroupName\fR,
+ \fBstmfDevid\fR \fIinitiatorName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhostGroupName\fR\fR
+.ad
+.RS 17n
+The name of the host group to which the specified initiatorName is added.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIinitiatorName\fR\fR
+.ad
+.RS 17n
+The device identifier of the initiator port to add to the specified host group.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfAddToHostGroup()\fR function adds an initiator port to an existing
+host group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_EXISTS\fR\fR
+.ad
+.RS 30n
+The specified \fIinitiatorName\fR already exists in this \fIhostGroupName\fR or
+in another host group in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_GROUP_NOT_FOUND\fR\fR
+.ad
+.RS 30n
+The specified \fIhostGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 30n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfAddToTargetGroup.3stmf b/usr/src/man/man3stmf/stmfAddToTargetGroup.3stmf
new file mode 100644
index 0000000..ab01e17
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfAddToTargetGroup.3stmf
@@ -0,0 +1,97 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFADDTOTARGETGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfAddToTargetGroup \- add a target to an existing target group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfAddToTargetGroup\fR(\fBstmfGroupName *\fR\fItargetGroupName\fR,
+ \fBstmfDevid\fR \fItargetName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetGroupName\fR\fR
+.ad
+.RS 19n
+The name of the target port group to which the specified \fItargetName\fR is
+added.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fItargetName\fR\fR
+.ad
+.RS 19n
+The device identifier of the target port to add to the specified target group.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfAddToTargetGroup()\fR function adds a target to an existing target
+group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_EXISTS\fR\fR
+.ad
+.RS 30n
+The specified \fItargetName\fR already exists in this \fItagettGroupName\fR or
+in another target group in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_GROUP_NOT_FOUND\fR\fR
+.ad
+.RS 30n
+The specified \fItargetGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 30n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfAddViewEntry.3stmf b/usr/src/man/man3stmf/stmfAddViewEntry.3stmf
new file mode 100644
index 0000000..cf79775
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfAddViewEntry.3stmf
@@ -0,0 +1,113 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFADDVIEWENTRY 3STMF "Jun 9, 2008"
+.SH NAME
+stmfAddViewEntry \- add a view entry for a given logical unit
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfAddViewEntry\fR(\fBstmfGuid *\fR\fIlogicalUnit\fR,
+ \fBstmfViewEntry *\fR\fIviewEntry\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnit\fR\fR
+.ad
+.RS 15n
+The identifier of the logical unit to which this view entry is being added.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIviewEntry\fR\fR
+.ad
+.RS 15n
+The view entry to add to the specified logical unit identifier.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfAddViewEntry()\fR function adds a view entry for a given logical
+unit.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_LUN_IN_USE\fR\fR
+.ad
+.RS 26n
+The specified logical unit number is already in use for this logical unit.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 26n
+The ID specified for \fIlogicalUnit\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_VE_CONFLICT\fR\fR
+.ad
+.RS 26n
+Adding this view entry is in conflict with one or more existing view entries.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 26n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
+.SH NOTES
+.sp
+.LP
+If \fIluNbrValid\fR in the \fBstmfViewEntry\fR structure is set to
+\fBB_FALSE\fR, the framework will assign a logical unit number for this view
+entry. \fIveIndexValid\fR must be set to \fBB_FALSE\fR when adding a view
+entry. On successful return, \fIveIndexValid\fR will be set to \fBB_TRUE\fR and
+\fIveIndex\fR will contain the view entry index assigned to this view entry by
+the framework.
diff --git a/usr/src/man/man3stmf/stmfClearProviderData.3stmf b/usr/src/man/man3stmf/stmfClearProviderData.3stmf
new file mode 100644
index 0000000..8de3bd5
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfClearProviderData.3stmf
@@ -0,0 +1,86 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFCLEARPROVIDERDATA 3STMF "Jun 9, 2008"
+.SH NAME
+stmfClearProviderData \- delete all data for the specified provider
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfClearProviderData\fR(\fBchar *\fR\fIproviderName\fR, \fBint\fR \fIproviderType\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIproviderName\fR\fR
+.ad
+.RS 16n
+The name of the provider whose data is being deleted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIproviderType\fR\fR
+.ad
+.RS 16n
+The value must be either \fBSTMF_LU_PROVIDER_TYPE\fR or
+\fBSTMF_PORT_PROVIDER_TYPE\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfClearProviderData()\fR function deletes all data for the specified
+provider.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The value specified for \fIproviderName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfCreateHostGroup.3stmf b/usr/src/man/man3stmf/stmfCreateHostGroup.3stmf
new file mode 100644
index 0000000..58aa881
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfCreateHostGroup.3stmf
@@ -0,0 +1,84 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFCREATEHOSTGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfCreateHostGroup \- create a new host group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfCreateHostGroup\fR(\fBstmfGroupName *\fR\fIhostGroupName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhostGroupName\fR\fR
+.ad
+.RS 17n
+The name of the host group to be created.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfCreateHostGroup()\fR function creates a new host group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_EXISTS\fR\fR
+.ad
+.RS 25n
+The value specified for \fIhostGroupName\fR already exists in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_INVALID_ARGUMENT\fR\fR
+.ad
+.RS 25n
+The value specified for \fIhostGroupName\fR was not valid.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 25n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfCreateLu.3stmf b/usr/src/man/man3stmf/stmfCreateLu.3stmf
new file mode 100644
index 0000000..ecaf33c
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfCreateLu.3stmf
@@ -0,0 +1,155 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFCREATELU 3STMF "May 8, 2009"
+.SH NAME
+stmfCreateLu \- create a logical unit
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfCreateLu\fR(\fBluResource\fR \fIhdl\fR, \fBstmfGuid *\fR\fIluGuid\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhdl\fR\fR
+.ad
+.RS 10n
+The logical unit resource returned from a previous call to
+\fBstmfCreateLuResource\fR(3STMF).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIluGuid\fR\fR
+.ad
+.RS 10n
+If non-null, it must contain a pointer to an \fBstmfGuid\fR structure allocated
+by the caller. On successful return from this API, it will contain the guid of
+the newly created logical unit. If \fIluGuid\fR is \fINULL\fR, this argument is
+ignored.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The stmfCreateLu function creates a logical unit in stmf using the properties
+of \fIhdl\fR. See \fBstmfSetLuProp\fR(3STMF) for a complete description of
+properties and their possible values.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_FILE_IN_USE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The filename specified by the \fBSTMF_LU_PROP_DATA_FILENAME\fR or
+\fBSTMF_LU_PROP_META_FILENAME\fR was in use.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_GUID_IN_USE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The guid specified by the \fBSTMF_LU_PROP_GUID\fR property is already being
+used.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_BLKSIZE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The blocksize specified by \fBSTMF_LU_PROP_BLOCK_SIZE\fR is invalid.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_WRITE_CACHE_SET\fR\fR
+.ad
+.sp .6
+.RS 4n
+The requested write cache setting could not be provided.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_SIZE_OUT_OF_RANGE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified logical unit size is not supported.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_META_FILE_NAME\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified meta file could not be accessed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_DATA_FILE_NAME\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified data file could not be accessed.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfCreateLuResource\fR(3STMF),
+\fBstmfSetLuProp\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfCreateLuResource.3stmf b/usr/src/man/man3stmf/stmfCreateLuResource.3stmf
new file mode 100644
index 0000000..b396a72
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfCreateLuResource.3stmf
@@ -0,0 +1,86 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFCREATELURESOURCE 3STMF "May 8, 2009"
+.SH NAME
+stmfCreateLuResource \- create new logical unit resource
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfCreateLuResource\fR(\fBuint16_t\fR \fIdType\fR, \fBluResource *\fR\fIhdl\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIdType\fR\fR
+.ad
+.RS 9n
+The device type of the logical unit resource. Only \fBSTMF_DISK\fR is currently
+supported.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIhdl\fR\fR
+.ad
+.RS 9n
+The logical unit resource to be created.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfCreateLuResource()\fR function creates a resource for setting
+properties of a logical unit for purposes of creating a logical unit in STMF.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_ARG\fR\fR
+.ad
+.RS 26n
+Either type is unrecognized or \fIhdl\fR was \fINULL\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 26n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfCreateTargetGroup.3stmf b/usr/src/man/man3stmf/stmfCreateTargetGroup.3stmf
new file mode 100644
index 0000000..b946491
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfCreateTargetGroup.3stmf
@@ -0,0 +1,84 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFCREATETARGETGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfCreateTargetGroup \- create a new target port group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfCreateTargetGroup\fR(\fBstmfGroupName *\fR\fItargetGroupName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetGroupName\fR\fR
+.ad
+.RS 19n
+The name of the target port group to be created.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfCreateTargetGroup()\fR function creates a new target port group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_EXISTS\fR\fR
+.ad
+.RS 25n
+The value specified for \fItargetGroupName\fR already exists in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_INVALID_ARGUMENT\fR\fR
+.ad
+.RS 25n
+The value specified for \fItargetGroupName\fR was not valid.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 25n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfDeleteHostGroup.3stmf b/usr/src/man/man3stmf/stmfDeleteHostGroup.3stmf
new file mode 100644
index 0000000..cbc8d9a
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfDeleteHostGroup.3stmf
@@ -0,0 +1,75 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFDELETEHOSTGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfDeleteHostGroup \- delete an existing host group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfDeleteHostGroup\fR(\fBstmfGroupName *\fR\fIhostGroupName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhostGroupName\fR\fR
+.ad
+.RS 17n
+The name of the host group being deleted.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfDeleteHostGroup()\fR function deletes an existing host group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The specified \fIhostGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfDeleteLu.3stmf b/usr/src/man/man3stmf/stmfDeleteLu.3stmf
new file mode 100644
index 0000000..a54633f
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfDeleteLu.3stmf
@@ -0,0 +1,79 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFDELETELU 3STMF "May 8, 2009"
+.SH NAME
+stmfDeleteLu \- delete a logical unit
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfDeleteLu\fR(\fBstmfGuid *\fR\fIluGuid\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIluGuid\fR\fR
+.ad
+.RS 10n
+a pointer to an \fBstmfGuid\fR structure containing the guid of the logical
+unit to delete
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfDeleteLu()\fR function deletes the logical unit from the system. Any
+view entries that may exist for this logical unit will be retained in the
+system and must be removed using \fBstmfRemoveViewEntry\fR(3STMF) if so
+desired.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The guid does not exist.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfRemoveViewEntry\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfDeleteTargetGroup.3stmf b/usr/src/man/man3stmf/stmfDeleteTargetGroup.3stmf
new file mode 100644
index 0000000..583fa69
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfDeleteTargetGroup.3stmf
@@ -0,0 +1,76 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFDELETETARGETGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfDeleteTargetGroup \- delete an existing target port group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfDeleteTargetGroup\fR(\fBstmfGroupName *\fR\fItargetGroupName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetGroupName\fR\fR
+.ad
+.RS 19n
+The name of the target port group being deleted.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfDeleteTargetGroup()\fR function deletes an existing target port
+group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The specified \fItargetGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfDevidFromIscsiName.3stmf b/usr/src/man/man3stmf/stmfDevidFromIscsiName.3stmf
new file mode 100644
index 0000000..d848b22
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfDevidFromIscsiName.3stmf
@@ -0,0 +1,91 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFDEVIDFROMISCSINAME 3STMF "Jun 9, 2008"
+.SH NAME
+stmfDevidFromIscsiName \- convert an iSCSI name to a stmfDevid structure
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfDevidFromIscsiName\fR(\fBchar *\fR\fIiscsiName\fR, \fBstmfDevid *\fR\fIdevid\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIiscsiName\fR\fR
+.ad
+.RS 13n
+A character string of UTF-8 encoded Unicode characters representing the iSCSI
+name terminated with the Unicode nul character.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIdevid\fR\fR
+.ad
+.RS 13n
+A pointer to a \fBstmfDevid\fR structure allocated by the caller. On successful
+return, this will contain the converted device identifier. On error, the value
+of this parameter is undefined.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfDevidFromIscsiName()\fR function converts an iSCSI name to a
+\fBstmfDevid\fR structure. It returns the \fIdevid\fR as a SCSI name string
+identifier.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_ARGUMENT\fR\fR
+.ad
+.sp .6
+.RS 4n
+The value of \fIiscsiName\fR was not valid iSCSI name.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfDevidFromWwn.3stmf b/usr/src/man/man3stmf/stmfDevidFromWwn.3stmf
new file mode 100644
index 0000000..2bbc243
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfDevidFromWwn.3stmf
@@ -0,0 +1,89 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFDEVIDFROMWWN 3STMF "Jun 9, 2008"
+.SH NAME
+stmfDevidFromWwn \- convert a WWN to a stmfDevid structure
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfDevidFromWWN\fR(\fBuchar_t\fR \fIwwn\fR[8], \fBstmfDevid *\fR\fIdevid\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIwwn\fR\fR
+.ad
+.RS 9n
+The 8-byte WWN identifier.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIdevid\fR\fR
+.ad
+.RS 9n
+A pointer to a \fBstmfDevid\fR structure allocated by the caller. On successful
+return, this will contain the converted device identifier. On error, the value
+of this parameter is undefined.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The stmfDevidFromWwn function convert a WWN to a stmfDevid structure. It
+returns the \fIdevid\fR as a SCSI name string.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_ARGUMENT\fR\fR
+.ad
+.sp .6
+.RS 4n
+The value of \fIwwn\fR was not valid WWN identifier.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfFreeLuResource.3stmf b/usr/src/man/man3stmf/stmfFreeLuResource.3stmf
new file mode 100644
index 0000000..619aaa1
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfFreeLuResource.3stmf
@@ -0,0 +1,79 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFFREELURESOURCE 3STMF "May 8, 2009"
+.SH NAME
+stmfFreeLuResource \- free an allocated logical unit resource
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfFreeLuResource\fR(\fBluResource\fR \fIhdl\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhdl\fR\fR
+.ad
+.RS 7n
+A logical unit resource previously allocated in a call to
+\fBstmfCreateLuResource\fR(3STMF) or \fBstmfGetLuResource\fR(3STMF).
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfFreeLuResource()\fR function frees a logical unit resource that was
+previously allocated in a call to \fBstmfCreateLuResource\fR(3STMF) or
+\fBstmfGetLuResource\fR(3STMF).
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 26n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_ARG\fR\fR
+.ad
+.RS 26n
+The \fIhdl\fR argument is not a valid logical unit resource.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfCreateLuResource\fR(3STMF),
+\fBstmfGetLuResource\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfFreeMemory.3stmf b/usr/src/man/man3stmf/stmfFreeMemory.3stmf
new file mode 100644
index 0000000..21a8411
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfFreeMemory.3stmf
@@ -0,0 +1,58 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFFREEMEMORY 3STMF "Jun 9, 2008"
+.SH NAME
+stmfFreeMemory \- free memory allocated by this library
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBvoid\fR \fBstmfFreeMemory\fR(\fBvoid *\fR\fIstmfMemory\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fImemory\fR\fR
+.ad
+.RS 10n
+A pointer to memory that was previously allocated by this library. If
+\fBstmfMemory()\fR is equal to \fINULL\fR, the call will return successfully.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfFreeMemory()\fR function frees memory allocated by this library.
+.SH RETURN VALUES
+.sp
+.LP
+No values are returned.
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetHostGroupList.3stmf b/usr/src/man/man3stmf/stmfGetHostGroupList.3stmf
new file mode 100644
index 0000000..d5e61af
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetHostGroupList.3stmf
@@ -0,0 +1,78 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETHOSTGROUPLIST 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetHostGroupList \- retrieve the list of host groups
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetInitiatorGroupList\fR(\fBstmfGroupList **\fR\fIhostGroupList\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhostGroupList\fR\fR
+.ad
+.RS 17n
+A pointer to a pointer to an \fBstmfGroupList\fR structure. On successful
+return, this will contain a list of host groups.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetInitiatorGroupList()\fR function retrieves the list of host
+groups. The caller should call \fBstmfFreeMemory\fR(3STMF) when this list is no
+longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory for \fIhostGroupList\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBstmfFreeMemory\fR(3STMF), \fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetHostGroupMembers.3stmf b/usr/src/man/man3stmf/stmfGetHostGroupMembers.3stmf
new file mode 100644
index 0000000..d9769e3
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetHostGroupMembers.3stmf
@@ -0,0 +1,88 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETHOSTGROUPMEMBERS 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetHostGroupMembers \- retrieve the properties of the specified host group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetHostGroupMembers\fR(\fBstmfGroupName *\fR\fIhostGroupName\fR,
+ \fBstmfGroupProperties **\fR\fIgroupProperties\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhostGroupName\fR\fR
+.ad
+.RS 19n
+The name of the host group whose member list is being retrieved.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIgroupProperties\fR\fR
+.ad
+.RS 19n
+A pointer to a pointer to an \fBstmfGroupProperties\fR structure. On successful
+return, this will contain the properties for the specified \fIhostGroupName\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetHostGroupMembers()\fR function retrieves the properties of the
+specified host group. The caller should call \fBstmfFreeMemory\fR(3STMF) when
+this list is no longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The specified \fIhostGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBstmfFreeMemory\fR(3STMF), \fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetLogicalUnitList.3stmf b/usr/src/man/man3stmf/stmfGetLogicalUnitList.3stmf
new file mode 100644
index 0000000..c0adf4f
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetLogicalUnitList.3stmf
@@ -0,0 +1,78 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETLOGICALUNITLIST 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetLogicalUnitList \- retrieve the list of logical units
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetLogicalUnitList\fR(\fBstmfGuidList **\fR\fIlogicalUnitList\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnitList\fR\fR
+.ad
+.RS 19n
+A pointer to a pointer to an \fBstmfGuidList\fR structure. On successful
+return, this will contain a list of logical units in the system.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetLogicalUnitList()\fR function retrieves the list of logical
+units. The caller should call \fBstmfFreeMemory\fR(3STMF) when this list is no
+longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory for \fIlogicalUnitList\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBstmfFreeMemory\fR(3STMF), \fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetLogicalUnitProperties.3stmf b/usr/src/man/man3stmf/stmfGetLogicalUnitProperties.3stmf
new file mode 100644
index 0000000..c859836
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetLogicalUnitProperties.3stmf
@@ -0,0 +1,91 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETLOGICALUNITPROPERTIES 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetLogicalUnitProperties \- retrieve the properties of the specified
+logical unit
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetLogicalUnitProperties\fR(\fBstmfGuid *\fR\fIlogicalUnit\fR,
+ \fBstmfLogicalUnitProperties *\fR\fIlogicalUnitProps\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnit\fR\fR
+.ad
+.RS 20n
+The identifier of the logical unit whose properties are being retrieved.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnitProps\fR\fR
+.ad
+.RS 20n
+A pointer to an \fBstmfLogicalUnitProperties\fR structure. On successful
+return, this will contain the properties for the specified
+\fIlogicalUnitOid\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetLogicalUnitProperties()\fR function retrieves the properties of
+the specified logical unit.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_LOGICAL_UNIT_NOT_REGISTERED\fR\fR
+.ad
+.sp .6
+.RS 4n
+The \fIlogicalUnit\fR is not a valid registered logical unit in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetLuResource.3stmf b/usr/src/man/man3stmf/stmfGetLuResource.3stmf
new file mode 100644
index 0000000..04ddd94
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetLuResource.3stmf
@@ -0,0 +1,91 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETLURESOURCE 3STMF "May 8, 2009"
+.SH NAME
+stmfGetLuResource \- get a logical unit resource for a currently registered
+logical unit
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetLuResource\fR(\fBstmfGuid *\fR\fIluGuid\fR, \fBluResource *\fR\fIhdl\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIluGuid\fR\fR
+.ad
+.RS 10n
+The guid of logical unit to retrieve.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIhdl\fR\fR
+.ad
+.RS 10n
+The logical unit resource to create.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetLuResource()\fR function retrieves a logical unit resource
+\fIhdl\fR for a given logical unit. The \fIluGuid\fR argument must represent a
+currently registered stmf logical unit. This retrieved resource is a set of
+device-specific properties for a logical unit device. This allocates an
+\fBluResource\fR \fIhdl\fR of device type matching \fIluGuid\fR. The
+\fBstmfFreeLuResource\fR(3STMF) function should be used when \fIhdl\fR is no
+longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The guid does not exist.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfFreeLuResource\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetPersistMethod.3stmf b/usr/src/man/man3stmf/stmfGetPersistMethod.3stmf
new file mode 100644
index 0000000..8bc727e
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetPersistMethod.3stmf
@@ -0,0 +1,89 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETPERSISTMETHOD 3STMF "May 8, 2009"
+.SH NAME
+stmfGetPersistMethod \- get the current persistence method for stmf
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetPersistMethod\fR(\fBuint8_t *\fR\fIpersistType\fR, \fBboolean_t\fR \fIserviceState\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIpersistType\fR\fR
+.ad
+.RS 16n
+On success, contains the current persistence setting based on
+\fIserviceState\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIserviceState\fR\fR
+.ad
+.RS 16n
+When set to \fBB_TRUE\fR, \fIpersistType\fR will contain the persist method
+currently set for the service. When set to \fBB_FALSE\fR, \fIpersistType\fR
+will contain the persist method for the current library open.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetPersistMethod()\fR function retrieves the current persistent
+method setting for the service or for a given library open. When set to
+\fBB_TRUE\fR, retrieves the setting from the service.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 27n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_PERSIST_TYPE\fR\fR
+.ad
+.RS 27n
+Unable to retrieve persist type from service.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetProviderData.3stmf b/usr/src/man/man3stmf/stmfGetProviderData.3stmf
new file mode 100644
index 0000000..d3d69c4
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetProviderData.3stmf
@@ -0,0 +1,105 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETPROVIDERDATA 3STMF "Oct 7, 2008"
+.SH NAME
+stmfGetProviderData \- retrieve the data for the specified provider
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetProviderData\fR(\fBchar *\fR\fIproviderName\fR, \fBnvlist_t **\fR\fInvl\fR,
+ \fBint\fR \fIproviderType\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIproviderNane\fR\fR
+.ad
+.RS 16n
+The name of the provider for which data is being retrieved.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fInvl\fR\fR
+.ad
+.RS 16n
+A pointer to a pointer to an \fBnvlist_t\fR. On success, this will contain the
+nvlist retrieved. Caller is responsible for freeing the returned nvlist by
+calling \fBnvlist_free\fR(3NVPAIR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIproviderType\fR\fR
+.ad
+.RS 16n
+The value for this parameter must be either \fBSTMF_LU_PROVIDER_TYPE\fR or
+\fBSTMF_PORT_PROVIDER_TYPE\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetProviderData()\fR function retrieves the data for the specified
+provider.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory to return the data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed (Obsolete)
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBnvlist_free\fR(3NVPAIR),
+\fBstmfGetProviderDataProt\fR(3STMF), \fBattributes\fR(5)
+.SH NOTES
+.sp
+.LP
+The \fBstmfGetProviderData()\fR function is deprecated in favor of
+\fBstmfGetProviderDataProt\fR(3STMF) and may be removed in a future revision of
+\fBlibstmf\fR(3LIB).
diff --git a/usr/src/man/man3stmf/stmfGetProviderDataProt.3stmf b/usr/src/man/man3stmf/stmfGetProviderDataProt.3stmf
new file mode 100644
index 0000000..665fe80
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetProviderDataProt.3stmf
@@ -0,0 +1,111 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETPROVIDERDATAPROT 3STMF "Oct 7, 2008"
+.SH NAME
+stmfGetProviderDataProt \- retrieve data for the specified provider
+.SH SYNOPSIS
+.LP
+.nf
+\fBcc\fR [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+ #include <libstmf.h>
+
+\fBint\fR \fBstmfGetProviderDataProt\fR(\fBchar *\fR\fIproviderName\fR, \fBnvlist_t **\fR\fInvl\fR,
+ \fBint\fR \fIproviderType\fR, \fBuint64_t *\fR\fItoken\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIproviderName\fR\fR
+.ad
+.RS 16n
+The name of the provider for which data is being retrieved.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fInvl\fR\fR
+.ad
+.RS 16n
+A pointer to a pointer to an \fBnvlist_t\fR. On success, this will contain the
+nvlist retrieved. The caller is responsible for freeing the returned nvlist by
+calling \fBnvlist_free\fR(3NVPAIR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIproviderType\fR\fR
+.ad
+.RS 16n
+The value for this parameter must be either \fBSTMF_LU_PROVIDER_TYPE\fR or
+\fBSTMF_PORT_PROVIDER_TYPE\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fItoken\fR\fR
+.ad
+.RS 16n
+A pointer to a \fBuint64_t\fR allocated by the caller. On success, this will
+contain a token for the returned data that can be used in a call to
+\fBstmfSetProviderDataProt\fR(3STMF) to ensure that the data returned in this
+call is not stale. If this value is \fINULL\fR, the token will be ignored.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetProviderDataProt()\fR function retrieves the data for the
+specified provider.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory to return the data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBnvlist_free\fR(3NVPAIR),
+\fBstmfSetProviderDataProt\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetState.3stmf b/usr/src/man/man3stmf/stmfGetState.3stmf
new file mode 100644
index 0000000..d886a97
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetState.3stmf
@@ -0,0 +1,66 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETSTATE 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetState \- retrieve the list of sessions on a target
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetState\fR(\fBstmfState *\fR\fIstate\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIstate\fR\fR
+.ad
+.RS 9n
+A pointer to an \fBstmfState\fR structure allocated by the caller.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetState()\fR function retrieves the list of target port groups.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetTargetGroupList.3stmf b/usr/src/man/man3stmf/stmfGetTargetGroupList.3stmf
new file mode 100644
index 0000000..fed57ac
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetTargetGroupList.3stmf
@@ -0,0 +1,78 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETTARGETGROUPLIST 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetTargetGroupList \- retrieve the list of target port groups
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetTargetGroupList\fR(\fBstmfGroupList **\fR\fItargetGroupList\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetGroupList\fR\fR
+.ad
+.RS 19n
+A pointer to a pointer to an \fBstmfGroupList\fR structure. On successful
+return, this will contain a list of target port group object identifiers.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetTargetGroupList()\fR function retrieves the list of target port
+groups. The caller should call \fBstmfFreeMemory\fR(3STMF) when this list is no
+longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory for \fItargetGroupList\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfFreeMemory\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetTargetGroupMembers.3stmf b/usr/src/man/man3stmf/stmfGetTargetGroupMembers.3stmf
new file mode 100644
index 0000000..6df7972
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetTargetGroupMembers.3stmf
@@ -0,0 +1,90 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETTARGETGROUPMEMBERS 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetTargetGroupMembers \- retrieve the properties of the specified target
+port group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetTargetGroupMembers\fR(\fBstmfGroupName *\fR\fItargetGroupName\fR,
+ \fBstmfGroupProperties **\fR\fIgroupProperties\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetGroupName\fR\fR
+.ad
+.RS 19n
+The name of the target port group whose member list is being retrieved.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIgroupProperties\fR\fR
+.ad
+.RS 19n
+A pointer to a pointer to an \fBstmfGroupProperties\fR structure. On successful
+return, this will contain the properties for the specified
+\fItargetGroupName\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetTargetGroupMembers()\fR function retrieves the properties of the
+specified target port group. The caller should call \fBstmfFreeMemory\fR(3STMF)
+when this list is no longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The specified \fItargetGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfFreeMemory\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetTargetList.3stmf b/usr/src/man/man3stmf/stmfGetTargetList.3stmf
new file mode 100644
index 0000000..cfd8d1b
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetTargetList.3stmf
@@ -0,0 +1,78 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETTARGETLIST 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetTargetList \- retrieve the list of target ports
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetTargetList\fR(\fBstmfDevidList **\fR\fItargetList\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetList\fR\fR
+.ad
+.RS 14n
+A pointer to a pointer to an \fBstmfDevidList\fR structure. On successful
+return, this will contain a list of target ports in the system.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetTargetList()\fR function retrieves the list of target ports. The
+caller should call \fBstmfFreeMemory\fR(3STMF) when this list is no longer
+needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory for \fItargetList\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfFreeMemory\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetTargetProperties.3stmf b/usr/src/man/man3stmf/stmfGetTargetProperties.3stmf
new file mode 100644
index 0000000..3fbe1eb
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetTargetProperties.3stmf
@@ -0,0 +1,88 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETTARGETPROPERTIES 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetTargetProperties \- retrieve the properties of the specified target port
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetTargetProperties\fR(\fBstmfDevid *\fR\fItarget\fR,
+ \fBstmfTargetProperties *\fR\fItargetProperties\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItarget\fR\fR
+.ad
+.RS 20n
+The identifier of the target port whose properties are being retrieved.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fItargetProperties\fR\fR
+.ad
+.RS 20n
+A pointer to an \fBstmfTargetProperties\fR structure allocated by the caller.
+On successful return, the structure will contain the properties for the
+specified.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetTargetProperties()\fR function retrieves the properties of the
+specified target port.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The specified target was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfGetViewEntryList.3stmf b/usr/src/man/man3stmf/stmfGetViewEntryList.3stmf
new file mode 100644
index 0000000..6f07e84
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfGetViewEntryList.3stmf
@@ -0,0 +1,90 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFGETVIEWENTRYLIST 3STMF "Jun 9, 2008"
+.SH NAME
+stmfGetViewEntryList \- retrieve the list of view entries for a specified
+logical unit
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfGetViewEntryList\fR(\fBstmfGuid *\fR\fIlogicalUnit\fR,
+ \fBstmfViewEntryList **\fR\fIviewEntryList\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnit\fR\fR
+.ad
+.RS 17n
+The identifier of the logical unit for which to retrieve the list of view
+entries.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIviewEntryList\fR\fR
+.ad
+.RS 17n
+A pointer to a pointer to an \fBstmfViewEntryList\fR structure. On successful
+return, this will contain a list of view entries for \fIlogicalUnit\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfGetViewEntryList()\fR function retrieves the list of view entries
+for a specified logical unit. The caller should call
+\fBstmfFreeMemory\fR(3STMF) when this list is no longer needed.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory for \fIviewEntryList\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfFreeMemory\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfModifyLu.3stmf b/usr/src/man/man3stmf/stmfModifyLu.3stmf
new file mode 100644
index 0000000..52b9bb2
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfModifyLu.3stmf
@@ -0,0 +1,196 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFMODIFYLU 3STMF "May 8, 2009"
+.SH NAME
+stmfModifyLu, stmfModifyLuByFname \- modify a logical uni
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfModifyLu\fR(\fBstmfGuid *\fR\fIluGuid\fR, \fBuint32_t\fR \fIprop\fR, \fBconst char *\fR\fIpropVal\fR)
+.fi
+
+.LP
+.nf
+\fBint\fR \fBstmfModifyLu\fR(\fBuint16_t\fR \fIdType\fR, \fBconst char *\fR\fIfname\fR, \fBuint32_t\fR \fIprop\fR,
+ \fBconst char *\fR\fIpropVal\fR)
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIluGuid\fR\fR
+.ad
+.RS 11n
+The guid of logical unit to modify.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIfname\fR\fR
+.ad
+.RS 11n
+The filename of logical unit to modify.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIdType\fR\fR
+.ad
+.RS 11n
+Type of logical unit. See \fBstmfCreateLuResource\fR(3STMF).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIprop\fR\fR
+.ad
+.RS 11n
+A property type value. See DESCRIPTION for valid values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIpropVal\fR\fR
+.ad
+.RS 11n
+A property value.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfModifyLu()\fR and \fBstmfModifyLuByFname()\fR functions modify the
+properties of a logical unit device.
+.sp
+.LP
+Valid properties for modify \fBSTMF_DISK\fR:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_ALIAS\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 255 characters representing a user defined name for the device.
+.sp
+Default: Set to file name of backing store.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_SIZE\fR\fR
+.ad
+.sp .6
+.RS 4n
+Numeric value with optional suffix (for example, 100G, 1T) to specify unit of
+size.
+.sp
+Default: Size of device specified in the \fBSTMF_LU_PROP_DATA_FILENAME\fR
+property value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_WRITE_CACHE_DISABLE\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write back cache disable. When specified as "true" or "false", specifies write
+back cache disable behavior.
+.sp
+Default: Writeback cache setting of the backing store device specified by
+\fBSTMF_LU_PROP_DATA_FILENAME\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_WRITE_PROTECT\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write protect bit. When specified as "true" or "false", specifies whether the
+device behaves as a write protected device.
+.sp
+Default: "false"
+.RE
+
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_ARG\fR\fR
+.ad
+.sp .6
+.RS 4n
+Either \fIprop\fR or \fIpropVal\fR is unrecognized.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_PROPSIZE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The size of \fIpropVal\fR is invalid.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NO_PROP\fR\fR
+.ad
+.sp .6
+.RS 4n
+The value of \fIprop\fR is unknown for this resource type.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfCreateLuResource\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfOfflineLogicalUnit.3stmf b/usr/src/man/man3stmf/stmfOfflineLogicalUnit.3stmf
new file mode 100644
index 0000000..d7ee7ec
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfOfflineLogicalUnit.3stmf
@@ -0,0 +1,86 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFOFFLINELOGICALUNIT 3STMF "Jun 9, 2008"
+.SH NAME
+stmfOfflineLogicalUnit \- take offline a logical unit that is currently in the
+online state
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfOfflineLogicalUnit\fR(\fBstmfGuid *\fR\fIlogicalUnit\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnit\fR\fR
+.ad
+.RS 15n
+The identifier of the logical unit to offline.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfOfflineLogicalUnit()\fR function takes offline a logical unit that
+is currently in the online state. Once in the offline state, the logical unit
+will no longer be capable of servicing requests in the system.
+.sp
+.LP
+This API call can be used to take offline a logical unit for servicing. Once
+the logical unit is offline, an initiator port that attempts to issue any SCSI
+commands to the offlined logical unit will receive a check condition. For
+purposes of the REPORT LUNS command, the logical unit will no longer appear in
+the logical unit inventory for any initiator ports to which it is currently
+mapped by one or more view entries.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_BUSY\fR\fR
+.ad
+.RS 23n
+The device is currently busy.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfOfflineTarget.3stmf b/usr/src/man/man3stmf/stmfOfflineTarget.3stmf
new file mode 100644
index 0000000..021286b
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfOfflineTarget.3stmf
@@ -0,0 +1,84 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFOFFLINETARGET 3STMF "Jun 9, 2008"
+.SH NAME
+stmfOfflineTarget \- take offline a target port that is currently in the online
+state
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfOfflineTarget\fR(\fBstmfDevid *\fR\fItarget\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItarget\fR\fR
+.ad
+.RS 10n
+The identifier of the target port to offline.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfOfflineTarget()\fR function takes offline a target port that is
+currently in the online state. Once in the offline state, the target port will
+no longer be capable of servicing requests in the system.
+.sp
+.LP
+This API call can be used to take offline a target port device for servicing.
+Once the target port is offline, it will no longer be available to any entities
+outside of the SCSI Target Mode Framework. Any initiator ports that currently
+have sessions established by the offlined target port will be logged out.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_BUSY\fR\fR
+.ad
+.RS 23n
+The device is currently busy.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfOnlineLogicalUnit.3stmf b/usr/src/man/man3stmf/stmfOnlineLogicalUnit.3stmf
new file mode 100644
index 0000000..de88aaf
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfOnlineLogicalUnit.3stmf
@@ -0,0 +1,68 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFONLINELOGICALUNIT 3STMF "Jun 9, 2008"
+.SH NAME
+stmfOnlineLogicalUnit \- take online of a logical unit that is currently in the
+offline state
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfOnlineLogicalUnit\fR(\fBstmfGuid *\fR\fIlogicalUnit\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnit\fR\fR
+.ad
+.RS 15n
+The identifier of the logical unit to take online.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfOnlineLogicalUnit()\fR function takes online of a logical unit that
+is currently in the offline state.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfOnlineTarget.3stmf b/usr/src/man/man3stmf/stmfOnlineTarget.3stmf
new file mode 100644
index 0000000..f93e158
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfOnlineTarget.3stmf
@@ -0,0 +1,68 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFONLINETARGET 3STMF "Jun 9, 2008"
+.SH NAME
+stmfOnlineTarget \- take online a target port that is currently in the offline
+state
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag \&.\|.\|.\fR ] \fIfile\fR\&.\|.\|. \fB-lstmf\fR [ \fIlibrary \&.\|.\|.\fR ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfOnlineTarget\fR(\fBstmfDevid *\fR\fItarget\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItarget\fR\fR
+.ad
+.RS 10n
+The identifier of the target port to online.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfOnlineTarget()\fR function takes online a target port that is
+currently in the offline state.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfRemoveFromHostGroup.3stmf b/usr/src/man/man3stmf/stmfRemoveFromHostGroup.3stmf
new file mode 100644
index 0000000..dfd26c6
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfRemoveFromHostGroup.3stmf
@@ -0,0 +1,100 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFREMOVEFROMHOSTGROUP 3STMF "Jun 9, 2008"
+.SH NAME
+stmfRemoveFromHostGroup \- remove an initiator port from an host group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfRemoveFromHostGroup\fR(\fBstmfGroupName *\fR\fIhostGroupName\fR
+ \fBstmfDevid *\fR\fIinitiatorPortName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhostGroupName\fR\fR
+.ad
+.RS 21n
+The name of the host group from which the specified \fIhostGroupName\fR is
+being removed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIinitiatorPortName\fR\fR
+.ad
+.RS 21n
+The device identifier of the initiator port to remove from the specified host
+group.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfRemoveFromHostGroup()\fR function removes an initiator port from an
+host group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_GROUP_NOT_FOUND\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified \fIhostGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_MEMBER_NOT_FOUND\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified \fIinitiatorPortName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfRemoveFromTargetGroup.3stmf b/usr/src/man/man3stmf/stmfRemoveFromTargetGroup.3stmf
new file mode 100644
index 0000000..7270e7b
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfRemoveFromTargetGroup.3stmf
@@ -0,0 +1,110 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFREMOVEFROMTARGETGROUP 3STMF "Jun 15, 2009"
+.SH NAME
+stmfRemoveFromTargetGroup \- remove a target port from an target port group
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfRemoveFromTargetGroup\fR(\fBstmfGroupName *\fR\fItargetGroupName\fR
+ \fBstmfDevid *\fR\fItargetName\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fItargetGroupName\fR\fR
+.ad
+.RS 19n
+The name of the target port group from which the specified
+\fItargetGroupName\fR is being removed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fItargetName\fR\fR
+.ad
+.RS 19n
+The device identifier of the target port to remove from the specified target
+port group.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfRemoveFromTargetGroup()\fR function removes a target port from an
+target port group.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_GROUP_NOT_FOUND\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified \fItargetGroupName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_MEMBER_NOT_FOUND\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified \fItargetName\fR was not found in the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_TG_ONLINE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The specified \fItargetName\fR must be offline.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfRemoveViewEntry.3stmf b/usr/src/man/man3stmf/stmfRemoveViewEntry.3stmf
new file mode 100644
index 0000000..f7dbc01
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfRemoveViewEntry.3stmf
@@ -0,0 +1,86 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFREMOVEVIEWENTRY 3STMF "Jun 9, 2008"
+.SH NAME
+stmfRemoveViewEntry \- remove a view entry from the system
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfRemoveViewEntry\fR(\fBstmfGuid *\fR\fIlogicalUnit\fR,
+ \fBuint32_t\fR \fIviewEntry\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIlogicalUnit\fR\fR
+.ad
+.RS 15n
+The identifier of the logical unit for the view entry being removed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIviewEntry\fR\fR
+.ad
+.RS 15n
+The numeric value of the view entry to be removed.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfRemoveViewEntry()\fR function removes a view entry from the system.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOT_FOUND\fR\fR
+.ad
+.RS 24n
+The specified \fIlogicalUnit\fR or \fIviewEntryName\fR was not found in the
+system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 24n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfSetLuProp.3stmf b/usr/src/man/man3stmf/stmfSetLuProp.3stmf
new file mode 100644
index 0000000..3f0fc41
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfSetLuProp.3stmf
@@ -0,0 +1,321 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFSETLUPROP 3STMF "Jul 17, 2009"
+.SH NAME
+stmfSetLuProp, stmfGetLuProp \- set or get a logical unit property
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfSetLuProp\fR(\fBluResource\fR \fIhdl\fR, \fBuint32_t\fR \fIprop\fR, \fBconst char *\fR\fIpropVal\fR);
+.fi
+
+.LP
+.nf
+\fBint\fR \fBstmfGetLuProp\fR(\fBluResource\fR \fIhdl\fR, \fBuint32_t\fR \fIprop\fR, \fBchar *\fR\fIpropVal\fR,
+ \fBsize_t *\fR\fIpropLen\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIhdl\fR\fR
+.ad
+.RS 11n
+A logical unit resource previously allocated by
+\fBstmfCreateLuResource\fR(3STMF) or \fBstmfGetLuResource\fR(3STMF).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIprop\fR\fR
+.ad
+.RS 11n
+A property type value. See DESCRIPTION for valid values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIpropVal\fR\fR
+.ad
+.RS 11n
+A property value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIpropLen\fR\fR
+.ad
+.RS 11n
+The length of the specified property value. If \fIpropLen\fR was of an
+insufficient size to hold the returned property value, \fIpropLen\fR will
+contain the required size of the buffer and \fBSTMF_ERROR_INVALID_ARG\fR will
+be returned.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+These functions set or get property values. All property values are expressed
+in human-readable form. Boolean properties are expressed in case insensitive
+form of "true" or "false". Properties that are represented by ASCII hexadecimal
+contain no leading characters to indicate a base hexadecimal representation
+(that is, no leading "0x"). The \fIprop\fR argument can be one of the following
+values:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_ALIAS\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 255 characters representing a user defined name for the device.
+.sp
+Default: Set to file name of backing store.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_BLOCK_SIZE\fR\fR
+.ad
+.sp .6
+.RS 4n
+Numeric value for block size in bytes in 2^n.
+.sp
+Default: 512
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_COMPANY_ID\fR\fR
+.ad
+.sp .6
+.RS 4n
+Organizational Unique Identifier. 6 hexadecimal ASCII characters representing
+the IEEE OUI company id assignment. This will be used to generate the device
+identifier (GUID).
+.sp
+Default: 00144F
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_DATA_FILENAME\fR\fR
+.ad
+.sp .6
+.RS 4n
+Character value representing the file name of the backing store device.
+.sp
+Default: None
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_GUID\fR\fR
+.ad
+.sp .6
+.RS 4n
+ASCII hexadecimal string of 32 characters representing the unique identifier
+for the device. This must be of valid 32 hexadecimal ASCII characters
+representing a valid NAA Registered Extended Identifier.
+.sp
+Default: Set by framework to a generated value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_META_FILENAME\fR\fR
+.ad
+.sp .6
+.RS 4n
+Metadata file name. When specified, will be used to hold the SCSI metadata for
+the logical unit.
+.sp
+Default: None. If this value is not specified, the value specified in
+\fBSTMF_LU_PROP_DATA_FILENAME\fR will be used.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_MGMT_URL\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 1024 characters representing Management Network Address URLs. More than
+one URL can be passed using space delimited URLs.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_PID\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 16 characters of product identification that will be reflected in the
+Standard INQUIRY data returned for the device.
+.sp
+Default: sSet to COMSTAR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_PRODUCT_REV\fR\fR
+.ad
+.sp .6
+.RS 4n
+Up to 4 characters of revision information that will be reflected in the
+Standard INQUIRY data returned for the device.
+.sp
+Default: Set to 1.0.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_SERIAL_NUM\fR\fR
+.ad
+.sp .6
+.RS 4n
+Serial Number. Specifies the SCSI Vital Product Data Serial Number (page 80h).
+It is a character value up to 252 bytes in length.
+.sp
+Default: None
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_SIZE\fR\fR
+.ad
+.sp .6
+.RS 4n
+Numeric value w/optional suffix, e.g. 100G, 1T, to specify unit of size.
+.sp
+Default: Size of the device specified in the \fBSTMF_LU_PROP_DATA_FILENAME\fR
+property value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_VID\fR\fR
+.ad
+.sp .6
+.RS 4n
+8 characters of vendor identification per SCSI SPC-3 and will be reflected in
+the Standard INQUIRY data returned for the device.
+.sp
+Default: Set to SUN.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_WRITE_CACHE_DISABLE\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write back cache disable. When specified as "true" or "false", specifies write
+back cache disable behavior.
+.sp
+Default: Writeback cache setting of the backing store device specified by
+\fBSTMF_LU_PROP_DATA_FILENAME\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_LU_PROP_WRITE_PROTECT\fR\fR
+.ad
+.sp .6
+.RS 4n
+Write protect bit. When specified as "true" or "false", specifies whether the
+device behaves as a write protected device.
+.sp
+Default: "false"
+.RE
+
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.sp .6
+.RS 4n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_ARG\fR\fR
+.ad
+.sp .6
+.RS 4n
+Either \fIprop\fR or \fIpropVal\fR is unrecognized.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_INVALID_PROPSIZE\fR\fR
+.ad
+.sp .6
+.RS 4n
+The size of \fIpropVal\fR is invalid.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NO_PROP\fR\fR
+.ad
+.sp .6
+.RS 4n
+The value of \fIprop\fR is unknown for this resource type.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfCreateLuResource\fR(3STMF),
+\fBstmfGetLuResource\fR(3STMF), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfSetPersistMethod.3stmf b/usr/src/man/man3stmf/stmfSetPersistMethod.3stmf
new file mode 100644
index 0000000..acdc949
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfSetPersistMethod.3stmf
@@ -0,0 +1,87 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFSETPERSISTMETHOD 3STMF "May 8, 2009"
+.SH NAME
+stmfSetPersistMethod \- set persistence method for the stmf service
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... -lstmf [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfSetPersistMethod\fR(\fBuint8_t\fR \fIpersistType\fR, \fBboolean_t\fR \fIserviceSet\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIpersistType\fR\fR
+.ad
+.RS 15n
+The requested persistence setting. Can be either \fBSTMF_PERSIST_SMF\fR or
+\fBSTMF_PERSIST_NONE\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIserviceSet\fR\fR
+.ad
+.RS 15n
+Set to indicate whether the setting should persist on the stmf service. When
+set to \fBB_FALSE\fR, this setting is only applicable for the duration of the
+current library open or until a subsequent call is made to change the setting.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfSetPersistMethod()\fR function sets the persistence method for stmf.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 27n
+The API call was successful.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_PERSIST_TYPE\fR\fR
+.ad
+.RS 27n
+The \fIpersistType\fR argument is invalid.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBattributes\fR(5)
diff --git a/usr/src/man/man3stmf/stmfSetProviderData.3stmf b/usr/src/man/man3stmf/stmfSetProviderData.3stmf
new file mode 100644
index 0000000..1e492a5
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfSetProviderData.3stmf
@@ -0,0 +1,102 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFSETPROVIDERDATA 3STMF "Oct 7, 2008"
+.SH NAME
+stmfSetProviderData \- set the data for the specified provider
+.SH SYNOPSIS
+.LP
+.nf
+cc [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+#include <libstmf.h>
+
+\fBint\fR \fBstmfSetProviderData\fR(\fBchar *\fR\fIproviderName\fR, \fBnvlist_t *\fR\fInvl\fR,
+ \fBint\fR \fIproviderType\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIproviderName\fR\fR
+.ad
+.RS 16n
+The name of the provider for which data is being set.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fInvl\fR\fR
+.ad
+.RS 16n
+A pointer to an \fBnvlist_t\fR containing the nvlist to be set.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIproviderType\fR\fR
+.ad
+.RS 16n
+The value must be either \fBSTMF_LU_PROVIDER_TYPE\fR or
+\fBSTMF_PORT_PROVIDER_TYPE\fR.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfSetProviderData()\fR function sets the data for the specified
+provider.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_NOMEM\fR\fR
+.ad
+.RS 23n
+The library was unable to allocate sufficient memory to return the data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 23n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed (Obsolete)
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBstmfSetProviderDataProt\fR(3STMF), \fBattributes\fR(5)
+.SH NOTES
+.sp
+.LP
+The \fBstmfSetProviderData()\fR function is deprecated in favor of
+\fBstmfSetProviderDataProt\fR(3STMF) and may be removed in a future revision of
+\fBlibstmf\fR(3LIB).
diff --git a/usr/src/man/man3stmf/stmfSetProviderDataProt.3stmf b/usr/src/man/man3stmf/stmfSetProviderDataProt.3stmf
new file mode 100644
index 0000000..71ae13a
--- /dev/null
+++ b/usr/src/man/man3stmf/stmfSetProviderDataProt.3stmf
@@ -0,0 +1,114 @@
+'\" te
+.\" Copyright (c) 2008, Sun Microsystems Inc. All Rights Reserved.
+.\" 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]
+.TH STMFSETPROVIDERDATAPROT 3STMF "Oct 7, 2008"
+.SH NAME
+stmfSetProviderDataProt \- retrieve data for the specified provider
+.SH SYNOPSIS
+.LP
+.nf
+\fBcc\fR [ \fIflag\fR... ] \fIfile\fR... \fB-lstmf\fR [ \fIlibrary\fR... ]
+ #include <libstmf.h>
+
+\fBint\fR \fBstmfSetProviderDataProt\fR(\fBchar *\fR\fIproviderName\fR, \fBnvlist_t **\fR\fInvl\fR,
+ \fBint\fR \fIproviderType\fR, \fBuint64_t *\fR\fItoken\fR);
+.fi
+
+.SH PARAMETERS
+.sp
+.ne 2
+.na
+\fB\fIproviderName\fR\fR
+.ad
+.RS 16n
+The name of the provider for which data is being set.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fInvl\fR\fR
+.ad
+.RS 16n
+A pointer to a pointer to an \fBnvlist_t\fR containing the nvlist to be set.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIproviderType\fR\fR
+.ad
+.RS 16n
+The value for this parameter must be either \fBSTMF_LU_PROVIDER_TYPE\fR or
+\fBSTMF_PORT_PROVIDER_TYPE\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fItoken\fR\fR
+.ad
+.RS 16n
+A pointer to a \fBuint64_t\fR that contains the value returned from a
+successful call to \fBstmfGetProviderDataProt\fR(3STMF). If this argument is
+\fINULL\fR, the token is ignored. Otherwise, the token will be verified against
+the current data. If the token represents stale data, the call fails.
+.sp
+On success, \fItoken\fR will contain the new token for the data being set and
+can be used in subsequent calls to \fBstmfSetProviderData\fR(3STMF). On failure
+the contents are undefined.
+.RE
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBstmfSetProviderDataProt()\fR function sets the data for the specified
+provider.
+.SH RETURN VALUES
+.sp
+.LP
+The following values are returned:
+.sp
+.ne 2
+.na
+\fB\fBSTMF_ERROR_PROV_DATA_STALE\fR\fR
+.ad
+.RS 30n
+The token value represents stale data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBSTMF_STATUS_SUCCESS\fR\fR
+.ad
+.RS 30n
+The API call was successful.
+.RE
+
+.SH ATTRIBUTES
+.sp
+.LP
+See \fBattributes\fR(5) for descriptions of the following attributes:
+.sp
+
+.sp
+.TS
+box;
+c | c
+l | l .
+ATTRIBUTE TYPE ATTRIBUTE VALUE
+_
+Interface Stability Committed
+_
+MT-Level Safe
+.TE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBlibstmf\fR(3LIB), \fBnvlist_free\fR(3NVPAIR),
+\fBstmfGetProviderDataProt\fR(3STMF), \fBstmfSetProviderData\fR(3STMF),
+\fBattributes\fR(5)