diff options
Diffstat (limited to 'usr/src')
110 files changed, 102 insertions, 45211 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index 8c535e5fc5..90b76afe47 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -172,7 +172,6 @@ COMMON_SUBDIRS = \ cmd/ipcs \ cmd/isaexec \ cmd/isalist \ - cmd/iscsi \ cmd/iscsiadm \ cmd/iscsid \ cmd/iscsitsvc \ @@ -382,7 +381,6 @@ COMMON_SUBDIRS = \ lib/libipp \ lib/libipsecutil \ lib/libiscsit \ - lib/libiscsitgt \ lib/libkmf \ lib/libkstat \ lib/liblgrp \ diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs index e03c47e54e..61f6e0c00c 100644 --- a/usr/src/Targetdirs +++ b/usr/src/Targetdirs @@ -843,8 +843,6 @@ $(ROOT)/usr/lib/libinetutil.so.1:= REALPATH=../../lib/libinetutil.so.1 $(ROOT)/usr/lib/libinetutil.so:= REALPATH=../../lib/libinetutil.so.1 $(ROOT)/usr/lib/libintl.so.1:= REALPATH=../../lib/libintl.so.1 $(ROOT)/usr/lib/libintl.so:= REALPATH=../../lib/libintl.so.1 -$(ROOT)/usr/lib/libiscsitgt.so.1:= REALPATH=../../lib/libiscsitgt.so.1 -$(ROOT)/usr/lib/libiscsitgt.so:= REALPATH=../../lib/libiscsitgt.so.1 $(ROOT)/usr/lib/libkmf.so.1:= REALPATH=../../lib/libkmf.so.1 $(ROOT)/usr/lib/libkmf.so:= REALPATH=../../lib/libkmf.so.1 $(ROOT)/usr/lib/libkmfberder.so.1:= REALPATH=../../lib/libkmfberder.so.1 @@ -1127,10 +1125,6 @@ $(ROOT)/usr/lib/$(MACH64)/libintl.so.1:= \ REALPATH=../../../lib/$(MACH64)/libintl.so.1 $(ROOT)/usr/lib/$(MACH64)/libintl.so:= \ REALPATH=../../../lib/$(MACH64)/libintl.so.1 -$(ROOT)/usr/lib/$(MACH64)/libiscsitgt.so.1:= \ - REALPATH=../../../lib/$(MACH64)/libiscsitgt.so.1 -$(ROOT)/usr/lib/$(MACH64)/libiscsitgt.so:= \ - REALPATH=../../../lib/$(MACH64)/libiscsitgt.so.1 $(ROOT)/usr/lib/$(MACH64)/libkstat.so.1:= \ REALPATH=../../../lib/$(MACH64)/libkstat.so.1 $(ROOT)/usr/lib/$(MACH64)/libkstat.so:= \ @@ -1449,8 +1443,6 @@ SYM.USRLIB= \ /usr/lib/libinetutil.so.1 \ /usr/lib/libintl.so \ /usr/lib/libintl.so.1 \ - /usr/lib/libiscsitgt.so \ - /usr/lib/libiscsitgt.so.1 \ /usr/lib/libkstat.so \ /usr/lib/libkstat.so.1 \ /usr/lib/liblddbg.so.4 \ @@ -1689,8 +1681,6 @@ SYM.USRLIB64= \ /usr/lib/$(MACH64)/libinetutil.so.1 \ /usr/lib/$(MACH64)/libintl.so \ /usr/lib/$(MACH64)/libintl.so.1 \ - /usr/lib/$(MACH64)/libiscsitgt.so \ - /usr/lib/$(MACH64)/libiscsitgt.so.1 \ /usr/lib/$(MACH64)/libkstat.so \ /usr/lib/$(MACH64)/libkstat.so.1 \ /usr/lib/$(MACH64)/liblddbg.so.4 \ diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index f4afcc0390..36b830bfbf 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -207,7 +207,6 @@ COMMON_SUBDIRS= \ ipf \ isainfo \ isalist \ - iscsi \ itutools \ iscsiadm \ iscsid \ @@ -599,7 +598,6 @@ MSGSUBDIRS= \ id \ idmap \ isaexec \ - iscsi \ iscsiadm \ iscsid \ isns \ diff --git a/usr/src/cmd/Makefile.check b/usr/src/cmd/Makefile.check index 964719eb6c..bc13f620b7 100644 --- a/usr/src/cmd/Makefile.check +++ b/usr/src/cmd/Makefile.check @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -117,7 +117,6 @@ MANIFEST_SUBDIRS= \ hostid/smf \ idmap/idmapd \ ipf/svc \ - iscsi/iscsitgtd \ isns/isnsd \ krb5/kadmin/server \ krb5/krb5kdc \ diff --git a/usr/src/cmd/iscsi/Makefile b/usr/src/cmd/iscsi/Makefile deleted file mode 100644 index 79aac24e7c..0000000000 --- a/usr/src/cmd/iscsi/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# -# Makefile definitions for volume management -# -# -# cmd/iscsi/Makefile -# - -include ../Makefile.cmd - -SUBDIRS = iscsitgtd iscsitadm -POSUBDIRS = iscsitgtd iscsitadm -POFILE = SUNW_ISCSI.po -POFILES = $(POSUBDIRS:%=%/%.po) - -CAT= cat - -all := TARGET= all -install := TARGET= install -clean := TARGET= clean -clobber := TARGET= clobber -lint := TARGET= lint -cstyle := TARGET= cstyle -_msg := TARGET= catalog - -.KEEP_STATE: - -all install cstyle lint _msg: $(SUBDIRS) - -clean: $(SUBDIRS) - $(RM) $(POFILES) - -clobber: $(SUBDIRS) - $(RM) $(POFILE) - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -$(POFILE): $(POFILES) - $(BUILDPO.pofiles) - -_msg: $(POSUBDIRS) .WAIT $(MSGDOMAINPOFILE) - -FRC: - -include $(SRC)/Makefile.msg.targ diff --git a/usr/src/cmd/iscsi/Makefile.iscsi b/usr/src/cmd/iscsi/Makefile.iscsi deleted file mode 100644 index d24117eb4d..0000000000 --- a/usr/src/cmd/iscsi/Makefile.iscsi +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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. -# - -CPPFLAGS += -D_FILE_OFFSET_BITS=64 -I/usr/include/libxml2 - -ISCSISRC = $(SRC)/cmd/iscsi -ISCSICOMMONDIR = $(ISCSISRC)/common -HDCRCCOMMONDIR = $(SRC)/common/hdcrc diff --git a/usr/src/cmd/iscsi/iscsitadm/Makefile b/usr/src/cmd/iscsi/iscsitadm/Makefile deleted file mode 100644 index f8d91cd936..0000000000 --- a/usr/src/cmd/iscsi/iscsitadm/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# 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. -# - -PROG = iscsitadm -OBJS = main.o helper.o cmdparse.o -SRCS =$(OBJS:%.o=%.c) -POFILES= $(OBJS:%.o=%.po) - -include $(SRC)/cmd/Makefile.cmd -include $(SRC)/cmd/iscsi/Makefile.iscsi - -LDLIBS += -liscsitgt -XMLLIB = -lxml2 -CFLAGS += $(CCVERBOSE) -I${ISCSICOMMONDIR} -FILEMODE= 0555 - -.KEEP_STATE: - -all: $(PROG) - -install: all $(ROOTUSRSBINPROG) - -$(PROG): $(OBJS) $(COMMON_OBJS) - $(LINK.c) -o $(PROG) $(OBJS) $(COMMON_OBJS) $(LDLIBS) $(XMLLIB) - $(POST_PROCESS) - -catalog: $(POFILE) - -lint := LINTFLAGS += -u -lint := LINTFLAGS64 += -u - -lint: $$(SRCS) - $(LINT.c) $(SRCS) $(LDLIBS) - -$(POFILE): $(POFILES) - $(RM) $@ - cat $(POFILES) > $@ - -%.o : $(ISCSICOMMONDIR)/%.c - $(COMPILE.c) -o $@ $< - $(POST_PROCESS_O) - -clean: - -$(RM) $(OBJS) $(COMMON_OBJS) - -include $(SRC)/cmd/Makefile.targ diff --git a/usr/src/cmd/iscsi/iscsitadm/cmdparse.c b/usr/src/cmd/iscsi/iscsitadm/cmdparse.c deleted file mode 100644 index d94e54538c..0000000000 --- a/usr/src/cmd/iscsi/iscsitadm/cmdparse.c +++ /dev/null @@ -1,934 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <strings.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" - -#pragma ident "%Z%%M% %I% %E% SMI" - - -/* Usage types */ -#define GENERAL_USAGE 1 -#define HELP_USAGE 2 -#define DETAIL_USAGE 3 - -/* 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 getSubcommand(char *, subcommand_t **); -static char *getExecBasename(char *); -static void usage(uint_t); -static void subUsage(uint_t, subcommand_t *); -static void subUsageObject(uint_t, subcommand_t *, object_t *); -static int getObject(char *, object_t **); -static int getObjectRules(uint_t, objectRules_t **); -static char *getLongOption(int); -static optionProp_t *getOptions(uint_t, uint_t); -static char *getOptionArgDesc(int); - -/* global data */ -static struct option *_longOptions; -static subcommand_t *_subcommands; -static object_t *_objects; -static objectRules_t *_objectRules; -static optionRules_t *_optionRules; -static optionTbl_t *_clientOptionTbl; -static char *commandName; - - -/* - * input: - * object - object value - * output: - * opCmd - pointer to opCmd_t structure allocated by caller - * - * On successful return, opCmd contains the rules for the value in - * object. On failure, the contents of opCmd is unspecified. - * - * Returns: - * zero on success - * non-zero on failure - * - */ -static int -getObjectRules(uint_t object, objectRules_t **objectRules) -{ - objectRules_t *sp; - - for (sp = _objectRules; sp->value; sp++) { - if (sp->value == object) { - *objectRules = sp; - return (0); - } - } - return (1); -} - -/* - * input: - * arg - pointer to array of char containing object string - * - * output: - * object - pointer to object_t structure pointer - * on success, contains the matching object structure based on - * input object name - * - * Returns: - * zero on success - * non-zero otherwise - * - */ -static int -getObject(char *arg, object_t **object) -{ - - object_t *op; - int len; - - for (op = _objects; op->name; op++) { - len = strlen(arg); - if (len == strlen(op->name) && - strncasecmp(arg, op->name, len) == 0) { - *object = op; - return (0); - } - } - return (1); -} - -/* - * input: - * arg - pointer to array of char containing subcommand string - * output: - * subcommand - pointer to subcommand_t pointer - * on success, contains the matching subcommand structure based on - * input subcommand name - * - * Returns: - * zero on success - * non-zero on failure - */ -static int -getSubcommand(char *arg, subcommand_t **subcommand) -{ - subcommand_t *sp; - int len; - - for (sp = _subcommands; sp->name; sp++) { - len = strlen(arg); - if (len == strlen(sp->name) && - strncasecmp(arg, sp->name, len) == 0) { - *subcommand = sp; - return (0); - } - } - return (1); -} - -/* - * input: - * object - object for which to get options - * subcommand - subcommand for which to get options - * - * Returns: - * on success, optionsProp_t pointer to structure matching input object - * value - * on failure, NULL is returned - */ -static optionProp_t * -getOptions(uint_t object, uint_t subcommand) -{ - uint_t currObject; - optionRules_t *op = _optionRules; - while (op && ((currObject = op->objectValue) != 0)) { - if ((currObject == object) && - (op->subcommandValue == subcommand)) { - return (&(op->optionProp)); - } - op++; - } - return (NULL); -} - -/* - * 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, HELP_USAGE, DETAIL_USAGE - * subcommand - pointer to subcommand_t structure - * - * Returns: - * none - * - */ -static void -subUsage(uint_t usageType, subcommand_t *subcommand) -{ - int i; - object_t *objp; - - - (void) fprintf(stdout, "%s:\t%s %s [", - gettext("Usage"), commandName, subcommand->name); - - for (i = 0; standardSubCmdOptions[i].name; i++) { - (void) fprintf(stdout, "-%c", - standardSubCmdOptions[i].val); - if (standardSubCmdOptions[i+1].name) - (void) fprintf(stdout, ","); - } - - (void) fprintf(stdout, "] %s [", "<OBJECT>"); - - for (i = 0; standardSubCmdOptions[i].name; i++) { - (void) fprintf(stdout, "-%c", - standardSubCmdOptions[i].val); - if (standardSubCmdOptions[i+1].name) - (void) fprintf(stdout, ","); - } - - (void) fprintf(stdout, "] %s", "[<OPERAND>]"); - (void) fprintf(stdout, "\n"); - - if (usageType == GENERAL_USAGE) { - return; - } - - (void) fprintf(stdout, "%s:\n", gettext("Usage by OBJECT")); - - /* - * iterate through object table - * For each object, print appropriate usage - * based on rules tables - */ - for (objp = _objects; objp->value; objp++) { - subUsageObject(usageType, subcommand, objp); - } -} - -/* - * Print usage for a subcommand and object. - * - * input: - * usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE - * subcommand - pointer to subcommand_t structure - * objp - pointer to a object_t structure - * - * Returns: - * none - * - */ -static void -subUsageObject(uint_t usageType, subcommand_t *subcommand, object_t *objp) -{ - int i; - objectRules_t *objRules = NULL; - opCmd_t *opCmd = NULL; - optionProp_t *options; - char *optionArgDesc; - char *longOpt; - - - if (getObjectRules(objp->value, &objRules) != 0) { - /* - * internal subcommand rules table error - * no object entry in object - */ - assert(0); - } - - opCmd = &(objRules->opCmd); - - if (opCmd->invOpCmd & subcommand->value) { - return; - } - - options = getOptions(objp->value, subcommand->value); - - /* print generic subcommand usage */ - (void) fprintf(stdout, "\t%s %s ", commandName, subcommand->name); - - /* print object */ - (void) fprintf(stdout, "%s ", objp->name); - - /* print options if applicable */ - if (options != NULL) { - if (options->required) { - (void) fprintf(stdout, "%s", gettext("<")); - } else { - (void) fprintf(stdout, "%s", gettext("[")); - } - (void) fprintf(stdout, "%s", gettext("OPTIONS")); - if (options->required) { - (void) fprintf(stdout, "%s ", gettext(">")); - } else { - (void) fprintf(stdout, "%s ", gettext("]")); - } - } - - /* print operand requirements */ - if (opCmd->optOpCmd & subcommand->value) { - (void) fprintf(stdout, gettext("[")); - } - if (!(opCmd->noOpCmd & subcommand->value)) { - (void) fprintf(stdout, gettext("<")); - if (objRules->operandDefinition) { - (void) fprintf(stdout, "%s", - objRules->operandDefinition); - } else { - /* - * Missing operand description - * from table - */ - assert(0); - } - } - if (opCmd->multOpCmd & subcommand->value) { - (void) fprintf(stdout, gettext(" ...")); - } - if (!(opCmd->noOpCmd & subcommand->value)) { - (void) fprintf(stdout, gettext(">")); - } - if (opCmd->optOpCmd & subcommand->value) { - (void) fprintf(stdout, gettext("]")); - } - - if (usageType == HELP_USAGE) { - (void) fprintf(stdout, "\n"); - return; - } - - /* print options for subcommand, object */ - if (options != NULL && options->optionString != NULL) { - (void) fprintf(stdout, "\n\t%s:", gettext("OPTIONS")); - for (i = 0; i < strlen(options->optionString); i++) { - if ((longOpt = getLongOption( - options->optionString[i])) - == NULL) { - /* no long option exists for short option */ - assert(0); - } - (void) fprintf(stdout, "\n\t\t-%c, --%s ", - options->optionString[i], longOpt); - optionArgDesc = - getOptionArgDesc(options->optionString[i]); - if (optionArgDesc != NULL) { - (void) fprintf(stdout, "<%s>", optionArgDesc); - } - if (options->exclusive && - strchr(options->exclusive, - options->optionString[i])) { - (void) fprintf(stdout, " (%s)", - gettext("exclusive")); - } - } - } - (void) fprintf(stdout, "\n"); -} - -/* - * input: - * type of usage statement to print - * - * Returns: - * return value of subUsage - */ -static void -usage(uint_t usageType) -{ - int i; - subcommand_t subcommand; - subcommand_t *sp; - - /* print general command usage */ - (void) fprintf(stdout, "%s:\t%s ", - gettext("Usage"), commandName); - - for (i = 0; standardCmdOptions[i].name; i++) { - (void) fprintf(stdout, "-%c", - standardCmdOptions[i].val); - if (standardCmdOptions[i+1].name) - (void) fprintf(stdout, ","); - } - - if (usageType == HELP_USAGE || usageType == GENERAL_USAGE) { - for (i = 0; standardSubCmdOptions[i].name; i++) { - (void) fprintf(stdout, ",--%s", - standardSubCmdOptions[i].name); - if (standardSubCmdOptions[i+1].name) - (void) fprintf(stdout, ","); - } - } - - (void) fprintf(stdout, "\n"); - - - /* print all subcommand usage */ - for (sp = _subcommands; sp->name; sp++) { - subcommand.name = sp->name; - subcommand.value = sp->value; - if (usageType == HELP_USAGE) { - (void) fprintf(stdout, "\n"); - } - subUsage(usageType, &subcommand); - } -} - -/* - * 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, and subUsageObject handling command, - * subcommand and object usage respectively. - * - * When syntax is successfully validated, the associated function is called - * using the subcommands table functions. - * - * Syntax is as follows: - * command subcommand object [<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; - char *versionString; - char optionStringAll[MAXOPTIONSTRING + 1]; - optionProp_t *availOptions; - objectRules_t *objRules = NULL; - opCmd_t *opCmd = NULL; - subcommand_t *subcommand; - object_t *object; - cmdOptions_t cmdOptions[MAXOPTIONS + 1]; - struct option *lp; - optionTbl_t *optionTbl; - struct option intLongOpt[MAXOPTIONS + 1]; - - /* - * Check for NULLs on mandatory input arguments - * - * Note: longOptionTbl and optionRulesTbl can be NULL in the case - * where there is no caller defined options - * - */ - if (synTable.versionString == NULL || - synTable.subcommandTbl == NULL || - synTable.objectRulesTbl == NULL || - synTable.objectTbl == NULL || - funcRet == NULL) { - assert(0); - } - - - versionString = synTable.versionString; - - /* set global command name */ - commandName = getExecBasename(argv[0]); - - /* Set unbuffered output */ - setbuf(stdout, NULL); - - /* load globals */ - _subcommands = synTable.subcommandTbl; - _objectRules = synTable.objectRulesTbl; - _optionRules = synTable.optionRulesTbl; - _objects = synTable.objectTbl; - _clientOptionTbl = synTable.longOptionTbl; - - /* There must be at least two arguments */ - if (argc < 2) { - usage(GENERAL_USAGE); - return (1); - } - - bzero(&intLongOpt[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(HELP_USAGE); - return (1); - } else { - usage(GENERAL_USAGE); - return (1); - } - case 'V': - (void) fprintf(stdout, "%s: %s %s\n", - commandName, gettext("Version"), - versionString); - return (1); - 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 (getSubcommand(argv[1], &subcommand) != 0) { - (void) fprintf(stderr, "%s: %s\n", - commandName, gettext("invalid subcommand")); - usage(GENERAL_USAGE); - return (1); - } - - if (argc == 2) { - (void) fprintf(stderr, "%s: %s\n", - commandName, gettext("missing object")); - subUsage(GENERAL_USAGE, subcommand); - return (1); - } - - getoptargv = argv; - getoptargv++; - getoptargc = argc; - getoptargc -= 1; - - while ((opt = getopt_long(getoptargc, getoptargv, "+?", - standardSubCmdOptions, NULL)) != EOF) { - switch (opt) { - case '?': - /* - * getopt can return a '?' when no - * option letters match string. Check for - * the 'real' '?' in optopt. - */ - if (optopt == '?') { - subUsage(HELP_USAGE, subcommand); - return (1); - } else { - subUsage(GENERAL_USAGE, subcommand); - return (1); - } - default: - break; - } - } - - - /* - * object is always in the third argument. If there is no - * recognized object in the third argument, print error, - * help usage for the subcommand and then return. - */ - if (getObject(argv[2], &object) != 0) { - (void) fprintf(stderr, "%s: %s\n", - commandName, gettext("invalid object")); - subUsage(HELP_USAGE, subcommand); - return (1); - } - - if (getObjectRules(object->value, &objRules) != 0) { - /* - * internal subcommand rules table error - * no object entry in object table - */ - assert(0); - } - - opCmd = &(objRules->opCmd); - - /* - * Is command valid for this object? - */ - if (opCmd->invOpCmd & subcommand->value) { - (void) fprintf(stderr, "%s: %s %s\n", commandName, - gettext("invalid subcommand for"), object->name); - subUsage(HELP_USAGE, subcommand); - return (1); - } - - /* - * offset getopt arg begin since - * getopt(3C) assumes options - * follow first argument - */ - getoptargv = argv; - getoptargv++; - getoptargv++; - getoptargc = argc; - getoptargc -= 2; - - bzero(optionStringAll, sizeof (optionStringAll)); - bzero(&cmdOptions[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, check against object - * and subcommand (option rules table) for validity. - * This is done later. - */ - while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll, - _longOptions, NULL)) != EOF) { - switch (opt) { - case '?': - if (optopt == '?') { - subUsageObject(DETAIL_USAGE, - subcommand, object); - return (1); - } else { - subUsage(GENERAL_USAGE, subcommand); - return (1); - } - default: - cmdOptions[i].optval = opt; - if (optarg) { - len = strlen(optarg); - if (len > sizeof (cmdOptions[i].optarg) - - 1) { - (void) fprintf(stderr, - "%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 + 2; - - /* - * Check validity of given options, if any were given - */ - - /* get option string for this object and subcommand */ - availOptions = getOptions(object->value, subcommand->value); - - if (cmdOptions[0].optval != 0) { /* options were input */ - if (availOptions == NULL) { /* no options permitted */ - (void) fprintf(stderr, "%s: %s\n", - commandName, gettext("no options permitted")); - subUsageObject(HELP_USAGE, subcommand, object); - return (1); - } - for (i = 0; cmdOptions[i].optval; i++) { - /* Check for invalid options */ - if (availOptions->optionString == NULL) { - /* - * internal option table error - * There must be an option string if - * there is an entry in the table - */ - assert(0); - } - /* is the option in the available option string? */ - - if (!(strchr(availOptions->optionString, - cmdOptions[i].optval))) { - (void) fprintf(stderr, - "%s: '-%c': %s\n", - commandName, cmdOptions[i].optval, - gettext("invalid option")); - subUsageObject(DETAIL_USAGE, subcommand, - object); - return (1); - - /* Check for exclusive options */ - } else if (cmdOptions[1].optval != 0 && - availOptions->exclusive && - strchr(availOptions->exclusive, - cmdOptions[i].optval)) { - (void) fprintf(stderr, - "%s: '-%c': %s\n", - commandName, cmdOptions[i].optval, - gettext("is an exclusive option")); - subUsageObject(DETAIL_USAGE, subcommand, - object); - return (1); - } - } - } else { /* no options were input */ - if (availOptions != NULL && (availOptions->required)) { - (void) fprintf(stderr, "%s: %s\n", commandName, - gettext("at least one option required")); - subUsageObject(DETAIL_USAGE, subcommand, - object); - return (1); - } - } - - /* - * If there are no more arguments (operands), - * check to see if this is okay - */ - if ((operInd == argc) && - (opCmd->reqOpCmd & subcommand->value)) { - (void) fprintf(stderr, "%s: %s %s %s\n", - commandName, subcommand->name, object->name, - gettext("requires an operand")); - subUsageObject(HELP_USAGE, subcommand, object); - return (1); - } - - /* - * If there are more operands, - * check to see if this is okay - */ - if ((argc > operInd) && (opCmd->noOpCmd & subcommand->value)) { - (void) fprintf(stderr, "%s: %s %s %s\n", commandName, - subcommand->name, object->name, - gettext("takes no operands")); - subUsageObject(HELP_USAGE, subcommand, object); - return (1); - } - - /* - * If there is more than one more operand, - * check to see if this is okay - */ - if ((argc > operInd) && ((argc - operInd) != 1) && - !(opCmd->multOpCmd & subcommand->value)) { - (void) fprintf(stderr, "%s: %s %s %s\n", commandName, - subcommand->name, object->name, - gettext("accepts only a single operand")); - subUsageObject(HELP_USAGE, subcommand, object); - return (1); - } - - /* Finished syntax checks */ - - - /* Call appropriate function */ - *funcRet = subcommand->handler(argc - operInd, &argv[operInd], - object->value, &cmdOptions[0], callArgs); - - return (0); -} diff --git a/usr/src/cmd/iscsi/iscsitadm/cmdparse.h b/usr/src/cmd/iscsi/iscsitadm/cmdparse.h deleted file mode 100644 index 6a8fe56c1d..0000000000 --- a/usr/src/cmd/iscsi/iscsitadm/cmdparse.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _CMDPARSE_H -#define _CMDPARSE_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include "getopt.h" - -/* subcommands must have a single bit on and must have exclusive values */ -#define SUBCOMMAND_BASE 1 -#define SUBCOMMAND(x) (SUBCOMMAND_BASE << x) - -#define OBJECT_BASE 1 -#define OBJECT(x) (OBJECT_BASE << x) - -/* maximum length of an option argument */ -#define MAXOPTARGLEN 256 - - -/* - * Add objects here - * - * EXAMPLE: - * object_t object[] = { - * {"target", TARGET}, - * {NULL, 0} - * }; - */ -typedef struct _object { - char *name; - uint_t value; -} object_t; - -/* - * 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; - - -/* - * list of objects, subcommands, valid short options, required flag and - * exlusive option string - * - * objectValue -> object - * subcommandValue -> subcommand value - * optionProp.optionString -> short options that are valid - * optionProp.required -> flag indicating whether at least one option is - * required - * optionProp.exclusive -> short options that are required to be exclusively - * entered - * - * - * If it's not here, there are no options for that object. - * - * The long options table specifies whether an option argument is required. - * - * - * EXAMPLE: - * - * Based on DISCOVERY entry below: - * - * MODIFY DISCOVERY accepts -i, -s, -t and -l - * MODIFY DISCOVERY requires at least one option - * MODIFY DISCOVERY has no exclusive options - * - * - * optionRules_t optionRules[] = { - * {DISCOVERY, MODIFY, "istl", B_TRUE, NULL}, - * {0, 0, NULL, 0, NULL} - * }; - */ -typedef struct _optionProp { - char *optionString; - boolean_t required; - char *exclusive; -} optionProp_t; - -typedef struct _optionRules { - uint_t objectValue; - uint_t subcommandValue; - optionProp_t optionProp; -} optionRules_t; - -/* - * Rules for subcommands and object operands - * - * Every object requires an entry - * - * value, reqOpCmd, optOpCmd, noOpCmd, invCmd, multOpCmd - * - * value -> numeric value of object - * - * The following five fields are comprised of values that are - * a bitwise OR of the subcommands related to the object - * - * reqOpCmd -> subcommands that must have an operand - * optOpCmd -> subcommands that may have an operand - * noOpCmd -> subcommands that will have no operand - * invCmd -> subcommands that are invalid - * multOpCmd -> subcommands that can accept multiple operands - * operandDefinition -> Usage definition for the operand of this object - * - * - * EXAMPLE: - * - * based on TARGET entry below: - * MODIFY and DELETE subcomamnds require an operand - * LIST optionally requires an operand - * There are no subcommands that requires that no operand is specified - * ADD and REMOVE are invalid subcommands for this operand - * DELETE can accept multiple operands - * - * objectRules_t objectRules[] = { - * {TARGET, MODIFY|DELETE, LIST, 0, ADD|REMOVE, DELETE, - * "target-name"}, - * {0, 0, 0, 0, 0, NULL} - * }; - */ -typedef struct _opCmd { - uint_t reqOpCmd; - uint_t optOpCmd; - uint_t noOpCmd; - uint_t invOpCmd; - uint_t multOpCmd; -} opCmd_t; - -typedef struct _objectRules { - uint_t value; - opCmd_t opCmd; - char *operandDefinition; -} objectRules_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[], int, cmdOptions_t *options, - void *callData); - -/* - * Add new subcommands here - * - * EXAMPLE: - * subcommand_t subcommands[] = { - * {"add", ADD, addFunc}, - * {NULL, 0, NULL} - * }; - */ -typedef struct _subcommand { - char *name; - uint_t value; - handler_t handler; -} subcommand_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; - subcommand_t *subcommandTbl; - object_t *objectTbl; - objectRules_t *objectRulesTbl; - optionRules_t *optionRulesTbl; -} synTables_t; - -/* - * cmdParse is a parser that checks syntax of the input command against - * various rules 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 subcommand [<options>] object [<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/cmd/iscsi/iscsitadm/helper.c b/usr/src/cmd/iscsi/iscsitadm/helper.c deleted file mode 100644 index e34bd3f8b6..0000000000 --- a/usr/src/cmd/iscsi/iscsitadm/helper.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdlib.h> -#include <stdio.h> -#include <wchar.h> -#include <widec.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <unistd.h> -#include <libintl.h> -#include <limits.h> -#include <string.h> -#include <strings.h> -#include <syslog.h> -#include <errno.h> -#include <netinet/in.h> -#include <sys/iscsi_protocol.h> -#include <door.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/mman.h> -#include <sys/filio.h> -#include <libxml/xmlreader.h> -#include <libscf.h> -#include <fcntl.h> - -#include <iscsitgt_impl.h> -#include "cmdparse.h" -#include "utility.h" -#include "helper.h" - -extern char *cmdName; - -static stat_delta_t *stat_head; - -/* - * []---- - * | buffer_xml -- buffer incoming XML response until complete - * | - * | Incoming data from target may not be a complete XML message. So, - * | we need to wait until we've got everything otherwise the XML routines - * | will generate a parsing error for a short buffer. - * []---- - */ -Boolean_t -buffer_xml(char *s, char **storage, tgt_node_t **np) -{ - tgt_node_t *node = NULL; - xmlTextReaderPtr r; - char *p, - *e, - *end_tag, - hold_ch; - - p = *storage; - if (s != NULL) { - if (p == NULL) { - p = strdup(s); - } else { - p = realloc(p, strlen(p) + strlen(s) + 1); - (void) strcat(p, s); - } - } - if (p == NULL) { - return (False); - } - - if (*p != '<') { - return (False); - } - - if ((e = strchr(p, '>')) == NULL) { - return (False); - } - - /* - * The +3 is for the slash, closing tag character and null - * For example if p is pointing at a string which starts with - * "<foo>...." - * p will point at '<' and e will point at '>'. e - p is 4, yet - * the tag length is really 5 characters. We will need to create - * the end tag which also has a slash and NULL byte. - */ - if ((end_tag = malloc(e - p + 3)) == NULL) { - return (False); - } - - end_tag[0] = '<'; - end_tag[1] = '/'; - - /* - * Copy in the tag value and the closing tag character '>'. - */ - bcopy(p + 1, &end_tag[2], e - p); - - /* - * Add the null byte - */ - end_tag[e - p + 2] = '\0'; - - /* - * Do we have the closing string yet? If not, just return - */ - if ((e = strstr(p, end_tag)) == NULL) { - *storage = p; - return (False); - } - - /* - * Move past the closing tag and free the end_tag memory - */ - e += strlen(end_tag); - free(end_tag); - - /* - * NULL terminate the string and remember to save that character - * so that we can restore it later. - */ - hold_ch = *e; - *e = '\0'; - - if ((r = (xmlTextReaderPtr)xmlReaderForMemory(p, strlen(p), NULL, - NULL, 0)) == NULL) - return (False); - - while (xmlTextReaderRead(r) == 1) { - if (tgt_node_process(r, &node) == False) - break; - } - - *np = node; - - xmlFreeTextReader(r); - - *e = hold_ch; - for (; isspace(*e); e++) - ; - if (*e != '\0') { - *storage = strdup(e); - } else - *storage = NULL; - free(p); - return (True); -} - -/* - * Retrieve CHAP secret from input - */ -int -getSecret(char *secret, int *secretLen, int minSecretLen, int maxSecretLen) -{ - char *chapSecret; - - /* XXX Should we prompt for hex or ascii printable input? */ - - /* get password */ - chapSecret = getpassphrase(gettext("Enter secret:")); - - if (strlen(chapSecret) > maxSecretLen) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("secret too long")); - *secret = NULL; - return (1); - } - - if (strlen(chapSecret) < minSecretLen && strlen(chapSecret) != 0) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("secret too short")); - *secret = NULL; - return (1); - } - - (void) strcpy(secret, chapSecret); - - chapSecret = getpassphrase(gettext("Re-enter secret:")); - if (strcmp(secret, chapSecret) != 0) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("secret not changed")); - *secret = NULL; - return (1); - } - *secretLen = strlen(chapSecret); - return (0); -} - -void -iSCSINameCheckStatusDisplay(iSCSINameCheckStatusType status) -{ - switch (status) { - case iSCSINameLenZero: - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("empty iSCSI name.")); - break; - case iSCSINameLenExceededMax: - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("iSCSI name exceeded maximum length.")); - break; - case iSCSINameUnknownType: - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("unknown iSCSI name type.")); - break; - case iSCSINameIqnFormatError: - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("iqn formatting error.")); - break; - case iSCSINameEUIFormatError: - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("eui formatting error.")); - break; - } -} - -/* - * This helper function could go into a utility module for general use. - */ -int -parseAddress(char *address_port_str, - uint16_t defaultPort, - char *address_str, - size_t address_str_len, - uint16_t *port, - boolean_t *isIpv6) -{ - char port_str[64]; - int tmp_port; - - if (address_port_str[0] == '[') { - /* IPv6 address */ - char *close_bracket_pos; - close_bracket_pos = strchr(address_port_str, ']'); - if (!close_bracket_pos) { - syslog(LOG_USER|LOG_DEBUG, - "IP address format error: %s\n", address_str); - return (PARSE_ADDR_MISSING_CLOSING_BRACKET); - } - - *close_bracket_pos = NULL; - (void) strlcpy(address_str, &address_port_str[1], - address_str_len); - - /* Extract the port number */ - close_bracket_pos++; - if (*close_bracket_pos == ':') { - close_bracket_pos++; - if (*close_bracket_pos != NULL) { - (void) strlcpy(port_str, close_bracket_pos, - 64); - tmp_port = atoi(port_str); - if (((tmp_port > 0) && - (tmp_port > USHRT_MAX)) || - (tmp_port < 0)) { - /* Port number out of range */ - syslog(LOG_USER|LOG_DEBUG, - "Specified port out of range: %d", - tmp_port); - return (PARSE_ADDR_PORT_OUT_OF_RANGE); - } else { - *port = (uint16_t)tmp_port; - } - } else { - *port = defaultPort; - } - } else { - *port = defaultPort; - } - - *isIpv6 = B_TRUE; - } else { - /* IPv4 address */ - char *colon_pos; - colon_pos = strchr(address_port_str, ':'); - if (!colon_pos) { - /* No port number specified. */ - *port = defaultPort; - (void) strlcpy(address_str, address_port_str, - address_str_len); - } else { - *colon_pos = (char)NULL; - (void) strlcpy(address_str, address_port_str, - address_str_len); - - /* Extract the port number */ - colon_pos++; - if (*colon_pos != NULL) { - (void) strlcpy(port_str, colon_pos, 64); - tmp_port = atoi(port_str); - if (((tmp_port > 0) && - (tmp_port > USHRT_MAX)) || - (tmp_port < 0)) { - /* Port number out of range */ - syslog(LOG_USER|LOG_DEBUG, - "Specified port out of range: %d", - tmp_port); - return (PARSE_ADDR_PORT_OUT_OF_RANGE); - } else { - *port = (uint16_t)tmp_port; - } - } else { - *port = defaultPort; - } - } - - *isIpv6 = B_FALSE; - } - - return (PARSE_ADDR_OK); -} - -/* - * []---- - * | Following routine (number_to_scaled_string) is lifted - * | from usr/src/cmd/fs.d/df.c - * []---- - */ -/* - * Convert an unsigned long long to a string representation and place the - * result in the caller-supplied buffer. - * The given number is in units of "unit_from" size, - * this will first be converted to a number in 1024 or 1000 byte size, - * depending on the scaling factor. - * Then the number is scaled down until it is small enough to be in a good - * human readable format i.e. in the range 0 thru scale-1. - * If it's smaller than 10 there's room enough to provide one decimal place. - * The value "(unsigned long long)-1" is a special case and is always - * converted to "-1". - * Returns a pointer to the caller-supplied buffer. - */ -char * -number_to_scaled_string( - char *buf, /* put the result here */ - unsigned long long number, /* convert this number */ - int unit_from, - int scale) -{ - unsigned long long save = 0; - char *M = "KMGTPE"; /* Measurement: kilo, mega, giga, tera, peta, exa */ - char *uom = M; /* unit of measurement, initially 'K' (=M[0]) */ - - if ((long long)number == (long long)-1) { - (void) strcpy(buf, "-1"); - return (buf); - } - - if ((number < scale) && (unit_from == 1)) { - (void) sprintf(buf, "%4llu", number); - return (buf); - } - /* - * Convert number from unit_from to given scale (1024 or 1000). - * This means multiply number by unit_from and divide by scale. - * - * Would like to multiply by unit_from and then divide by scale, - * but if the first multiplication would overflow, then need to - * divide by scale and then multiply by unit_from. - */ - if (number > (UINT64_MAX / (unsigned long long)unit_from)) { - number = (number / (unsigned long long)scale) * - (unsigned long long)unit_from; - } else { - number = (number * (unsigned long long)unit_from) / - (unsigned long long)scale; - } - - /* - * Now we have number as a count of scale units. - * Stop scaling when we reached exa bytes, then something is - * probably wrong with our number. - */ - - while ((number >= scale) && (*uom != 'E')) { - uom++; /* next unit of measurement */ - save = number; - number = (number + (scale / 2)) / scale; - } - /* check if we should output a decimal place after the point */ - if (save && ((save / scale) < 10)) { - /* sprintf() will round for us */ - float fnum = (float)save / scale; - (void) sprintf(buf, "%2.1f%c", fnum, *uom); - } else { - (void) sprintf(buf, "%4llu%c", number, *uom); - } - return (buf); -} - -void -stats_load_counts(tgt_node_t *n, stat_delta_t *d) -{ - tgt_node_t *conn = NULL, - *lun; - char *val; - - bzero(d, sizeof (*d)); - d->device = n->x_value; - - while (conn = tgt_node_next(n, XML_ELEMENT_CONN, conn)) { - lun = NULL; - while (lun = tgt_node_next(conn, XML_ELEMENT_LUN, lun)) { - if (tgt_find_value_str(lun, XML_ELEMENT_READCMDS, - &val) == True) { - d->read_cmds += strtoll(val, NULL, 0); - free(val); - } - if (tgt_find_value_str(lun, XML_ELEMENT_WRITECMDS, - &val) == True) { - d->write_cmds += strtoll(val, NULL, 0); - free(val); - } - if (tgt_find_value_str(lun, XML_ELEMENT_READBLKS, - &val) == True) { - d->read_blks += strtoll(val, NULL, 0); - free(val); - } - if (tgt_find_value_str(lun, XML_ELEMENT_WRITEBLKS, - &val) == True) { - d->write_blks += strtoll(val, NULL, 0); - free(val); - } - } - } -} - -stat_delta_t * -stats_prev_counts(stat_delta_t *cp) -{ - stat_delta_t *n; - - for (n = stat_head; n; n = n->next) { - if (strcmp(n->device, cp->device) == 0) - return (n); - } - if ((n = calloc(1, sizeof (*n))) == NULL) - return (NULL); - n->device = strdup(cp->device); - if (stat_head == NULL) - stat_head = n; - else { - n->next = stat_head; - stat_head = n; - } - return (n); -} - -void -stats_update_counts(stat_delta_t *p, stat_delta_t *c) -{ - p->read_cmds += c->read_cmds - p->read_cmds; - p->write_cmds += c->write_cmds - p->write_cmds; - p->read_blks += c->read_blks - p->read_blks; - p->write_blks += c->write_blks - p->write_blks; -} - -void -stats_free() -{ - stat_delta_t *n; - - /* CSTYLED */ - for (;stat_head;) { - n = stat_head->next; - free(stat_head->device); - free(stat_head); - stat_head = n; - } -} - -static char spaces[128]; - -/* - * []---- - * | dospace -- generate a string which has the appropriate number of spaces - * | - * | NOTE: Since this function modifies a static buffer usage of this - * | function may not be what's expected. For example: - * | printf("%sfoo%sbar\n", dospace(1), dospace(2)); would produce - * | ' foo bar' - * | instead of - * | ' foo bar' - * []---- - */ -char * -dospace(int n) -{ - (void) memset(spaces, ' ', sizeof (spaces)); - spaces[sizeof (spaces) - 1] = '\0'; - - if (n < sizeof (spaces)) - spaces[n * 4] = '\0'; - return (spaces); -} diff --git a/usr/src/cmd/iscsi/iscsitadm/helper.h b/usr/src/cmd/iscsi/iscsitadm/helper.h deleted file mode 100644 index 0f4727db6e..0000000000 --- a/usr/src/cmd/iscsi/iscsitadm/helper.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _HELPER_H -#define _HELPER_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_ISCSI_NAME_LEN 223 -#define MAX_ADDRESS_LEN 255 -#define MIN_CHAP_SECRET_LEN 12 -#define MAX_CHAP_SECRET_LEN 16 -#define DEFAULT_ISCSI_PORT 3260 -#define DEFAULT_RADIUS_PORT 1812 -#define MAX_CHAP_NAME_LEN 512 - -/* forward declarations */ -#define PARSE_ADDR_OK 0 -#define PARSE_ADDR_MISSING_CLOSING_BRACKET 1 -#define PARSE_ADDR_PORT_OUT_OF_RANGE 2 -#define PARSE_TARGET_OK 0 -#define PARSE_TARGET_INVALID_TPGT 1 -#define PARSE_TARGET_INVALID_ADDR 2 - -typedef enum iSCSINameCheckStatus { - iSCSINameCheckOK, - iSCSINameLenZero, - iSCSINameLenExceededMax, - iSCSINameUnknownType, - iSCSINameIqnFormatError, - iSCSINameEUIFormatError -} iSCSINameCheckStatusType; - -typedef struct stat_delta { - struct stat_delta *next; - char *device; - size_t read_cmds, - write_cmds, - read_blks, - write_blks; -} stat_delta_t; - -/* helper functions */ -int getSecret(char *, int *, int, int); -tgt_node_t *send_data(char *hostname, char *first_str); -int parseAddress(char *address_port_str, uint16_t defaultPort, - char *address_str, size_t address_str_len, - uint16_t *port, boolean_t *isIpv6); -char *number_to_scaled_string( - char *buf, - unsigned long long number, - int unit_from, - int scale); -void stats_load_counts(tgt_node_t *n, stat_delta_t *d); -stat_delta_t *stats_prev_counts(stat_delta_t *cp); -void stats_update_counts(stat_delta_t *p, stat_delta_t *c); -void stats_free(); -char *dospace(int n); - -#ifdef __cplusplus -} -#endif - -#endif /* _HELPER_H */ diff --git a/usr/src/cmd/iscsi/iscsitadm/main.c b/usr/src/cmd/iscsi/iscsitadm/main.c deleted file mode 100644 index a9fde81567..0000000000 --- a/usr/src/cmd/iscsi/iscsitadm/main.c +++ /dev/null @@ -1,1674 +0,0 @@ -/* - * 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. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/param.h> -#include <unistd.h> -#include <libintl.h> -#include <limits.h> -#include <string.h> -#include <syslog.h> -#include <errno.h> -#include <sys/stat.h> -#include <zone.h> -#include <netdb.h> - -#include <iscsitgt_impl.h> -#include "cmdparse.h" -#include "helper.h" - -#define CREATE SUBCOMMAND(0) -#define LIST SUBCOMMAND(1) -#define MODIFY SUBCOMMAND(2) -#define DELETE SUBCOMMAND(3) -#define SHOW SUBCOMMAND(4) - -#define TARGET OBJECT(0) -#define INITIATOR OBJECT(1) -#define ADMIN OBJECT(2) -#define TPGT OBJECT(3) -#define STATS OBJECT(4) - -#define VERSION_STRING_MAX_LEN 10 -#define MAX_IPADDRESS_LEN 128 - -/* - * Version number: - * 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 OPT_ENABLE "enable" -#define OPT_DISABLE "disable" -#define OPT_TRUE "true" -#define OPT_FALSE "false" - -/* subcommand functions */ -static int createFunc(int, char **, int, cmdOptions_t *, void *); -static int listFunc(int, char **, int, cmdOptions_t *, void *); -static int modifyFunc(int, char **, int, cmdOptions_t *, void *); -static int deleteFunc(int, char **, int, cmdOptions_t *, void *); -static int showFunc(int, char **, int, cmdOptions_t *, void *); - -/* object functions per subcommand */ -static int createTarget(int, char *[], cmdOptions_t *); -static int createInitiator(int, char *[], cmdOptions_t *); -static int createTpgt(int, char *[], cmdOptions_t *); -static int modifyTarget(int, char *[], cmdOptions_t *); -static int modifyInitiator(int, char *[], cmdOptions_t *); -static int modifyTpgt(int, char *[], cmdOptions_t *); -static int modifyAdmin(int, char *[], cmdOptions_t *); -static int deleteTarget(int, char *[], cmdOptions_t *); -static int deleteInitiator(int, char *[], cmdOptions_t *); -static int deleteTpgt(int, char *[], cmdOptions_t *); -static int listTarget(int, char *[], cmdOptions_t *); -static int listInitiator(int, char *[], cmdOptions_t *); -static int listTpgt(int, char *[], cmdOptions_t *); -static int showAdmin(int, char *[], cmdOptions_t *); -static int showStats(int, char *[], cmdOptions_t *); - -/* globals */ -char *cmdName; - -/* - * Add new options here - */ -optionTbl_t longOptions[] = { - {"size", required_arg, 'z', "size k/m/g/t"}, - {"type", required_arg, 't', "disk/tape/osd/raw"}, - {"lun", required_arg, 'u', "number"}, - {"alias", required_arg, 'a', "value"}, - {"backing-store", required_arg, 'b', "pathname"}, - {"tpgt", required_arg, 'p', "tpgt number"}, - {"acl", required_arg, 'l', "local initiator"}, - {"maxrecv", required_arg, 'm', "max recv data segment length"}, - {"chap-secret", no_arg, 'C', NULL}, - {"chap-name", required_arg, 'H', "chap username"}, - {"iqn", required_arg, 'n', "iSCSI node name"}, - {"ip-address", required_arg, 'i', "ip address"}, - {"base-directory", required_arg, 'd', "directory"}, - {"radius-access", required_arg, 'R', "enable/disable"}, - {"radius-server", required_arg, 'r', "hostname[:port]"}, - {"radius-secret", no_arg, 'P', NULL}, - {"isns-access", required_arg, 'S', "enable/disable"}, - {"isns-server", required_arg, 's', "hostname[:port]"}, - {"fast-write-ack", required_arg, 'f', "enable/disable"}, - {"verbose", no_arg, 'v', NULL}, - {"interval", required_arg, 'I', "seconds"}, - {"count", required_arg, 'N', "number"}, - {"all", no_arg, 'A', NULL}, - {NULL, 0, 0, 0} -}; - -/* - * Add new subcommands here - */ -subcommand_t subcommands[] = { - {"create", CREATE, createFunc}, - {"list", LIST, listFunc}, - {"modify", MODIFY, modifyFunc}, - {"delete", DELETE, deleteFunc}, - {"show", SHOW, showFunc}, - {NULL, 0, NULL} -}; - -/* - * Add objects here - */ -object_t objects[] = { - {"target", TARGET}, - {"initiator", INITIATOR}, - {"admin", ADMIN}, - {"tpgt", TPGT}, - {"stats", STATS}, - {NULL, 0} -}; - -/* - * Rules for subcommands and objects - * ReqiredOp, OptioalOp, NoOp, InvalidOp, MultiOp - */ -objectRules_t objectRules[] = { - /* - * create/modify/delete subcmd requires an operand - * list subcmd optionally requires an operand - * no subcmd requires no operand - * no subcmd is invalid for this operand - * no subcmd can accept multiple operands - */ - {TARGET, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-target"}, - /* - * create/modify/delete subcmd requires an operand - * list subcmd optionally requires an operand - * no subcmd requires no operand - * no subcmd is invalid for this operand - * no subcmd can accept multiple operands - */ - {INITIATOR, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-initiator"}, - /* - * no subcmd requires an operand - * no subcmd optionally requires an operand - * modify/list subcmd requires no operand - * create/delete subcmd are invlaid for this operand - * no subcmd can accept multiple operands - */ - {ADMIN, 0, 0, MODIFY|SHOW, CREATE|DELETE|LIST, 0, NULL}, - /* - * create/modify/delete subcmd requires an operand - * list subcmd optionally requires an operand - * no subcmd requires no operand - * no subcmd is invalid for this operand - * no subcmd can accept multiple operands - */ - {TPGT, CREATE|MODIFY|DELETE, LIST, 0, SHOW, 0, "local-tpgt"}, - /* - * no subcmd requires an operand - * list subcmd optionally requires an operand - * no subcmd requires no operand - * create/delete/modify subcmd are invalid for this operand - * no subcmd can accept multiple operands - */ - {STATS, 0, SHOW, 0, CREATE|MODIFY|DELETE|LIST, 0, "local-target"}, - {0, 0, 0, 0, 0, NULL} -}; - -/* - * list of objects, subcommands, valid short options, required flag and - * exclusive option string - * - * If it's not here, there are no options for that object. - */ -optionRules_t optionRules[] = { - {TARGET, CREATE, "tuzab", B_TRUE, NULL}, - {TARGET, MODIFY, "plamzu", B_TRUE, NULL}, - {TARGET, DELETE, "ulp", B_TRUE, NULL}, - {TARGET, LIST, "v", B_FALSE, NULL}, - {INITIATOR, CREATE, "n", B_TRUE, NULL}, - {INITIATOR, MODIFY, "CH", B_TRUE, NULL}, - {INITIATOR, DELETE, "A", B_TRUE, NULL}, - {INITIATOR, LIST, "v", B_FALSE, NULL}, - {TPGT, MODIFY, "i", B_TRUE, NULL}, - {TPGT, DELETE, "Ai", B_TRUE, NULL}, - {TPGT, LIST, "v", B_FALSE, NULL}, - {ADMIN, MODIFY, "dHCRrPSsf", B_TRUE, NULL}, - {STATS, SHOW, "IN", B_FALSE, NULL}, -}; - - - -/*ARGSUSED*/ -static int -createFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, - void *addArgs) -{ - int ret; - - switch (object) { - case TARGET: - ret = createTarget(operandLen, operand, options); - break; - case INITIATOR: - ret = createInitiator(operandLen, operand, options); - break; - case TPGT: - ret = createTpgt(operandLen, operand, options); - break; - default: - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("unknown object")); - ret = 1; - break; - } - return (ret); -} - -/*ARGSUSED*/ -static int -listFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, - void *addArgs) -{ - int ret; - - switch (object) { - case TARGET: - ret = listTarget(operandLen, operand, options); - break; - case INITIATOR: - ret = listInitiator(operandLen, operand, options); - break; - case TPGT: - ret = listTpgt(operandLen, operand, options); - break; - default: - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("unknown object")); - ret = 1; - break; - } - return (ret); -} - -/*ARGSUSED*/ -static int -showFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, - void *addArgs) -{ - int ret; - - switch (object) { - case STATS: - ret = showStats(operandLen, operand, options); - break; - case ADMIN: - ret = showAdmin(operandLen, operand, options); - break; - default: - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("unknown object")); - ret = 1; - break; - } - return (ret); -} - -/*ARGSUSED*/ -static int -modifyFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, - void *addArgs) -{ - int ret; - - switch (object) { - case TARGET: - ret = modifyTarget(operandLen, operand, options); - break; - case INITIATOR: - ret = modifyInitiator(operandLen, operand, options); - break; - case TPGT: - ret = modifyTpgt(operandLen, operand, options); - break; - case ADMIN: - ret = modifyAdmin(operandLen, operand, options); - break; - default: - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("unknown object")); - ret = 1; - break; - } - return (ret); -} - -/*ARGSUSED*/ -static int -deleteFunc(int operandLen, char *operand[], int object, cmdOptions_t *options, - void *addArgs) -{ - int ret; - - switch (object) { - case TARGET: - ret = deleteTarget(operandLen, operand, options); - break; - case INITIATOR: - ret = deleteInitiator(operandLen, operand, options); - break; - case TPGT: - ret = deleteTpgt(operandLen, operand, options); - break; - default: - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("unknown object")); - ret = 1; - break; - } - return (ret); -} - -static int -formatErrString(tgt_node_t *node) -{ - int code = 0; - int rtn = 0; - char *msg = NULL; - - if (node == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Unable to contact target daemon")); - return (1); - } - if ((strcmp(node->x_name, XML_ELEMENT_ERROR) == 0) && - (tgt_find_value_int(node, XML_ELEMENT_CODE, &code) == B_TRUE) && - (tgt_find_value_str(node, XML_ELEMENT_MESSAGE, &msg) == B_TRUE)) { - - /* - * 1000 is the success code, so we don't need to display - * the success message. - */ - if (code != 1000) { - (void) fprintf(stderr, "%s: %s %s\n", - cmdName, gettext("Error"), msg); - rtn = 1; - } - } else { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - rtn = 1; - } - if (msg) - free(msg); - return (rtn); -} - -/*ARGSUSED*/ -static int -createTarget(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "create", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - for (; optionList->optval; optionList++) { - switch (optionList->optval) { - case 't': /* type */ - if ((strcmp(optionList->optarg, "disk")) && - (strcmp(optionList->optarg, "tape")) && - (strcmp(optionList->optarg, "raw")) && - (strcmp(optionList->optarg, "osd"))) { - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown type")); - free(first_str); - return (1); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_TYPE, - optionList->optarg); - } - break; - case 'z': /* size */ - tgt_buf_add(&first_str, XML_ELEMENT_SIZE, - optionList->optarg); - break; - case 'u': /* lun number */ - tgt_buf_add(&first_str, XML_ELEMENT_LUN, - optionList->optarg); - break; - case 'a': /* alias */ - tgt_buf_add(&first_str, XML_ELEMENT_ALIAS, - optionList->optarg); - break; - case 'b': /* backing store */ - tgt_buf_add(&first_str, XML_ELEMENT_BACK, - optionList->optarg); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); - tgt_buf_add_tag(&first_str, "create", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -createInitiator(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - - if (operand == NULL) - return (1); - if (options == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "create", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - switch (optionList->optval) { - case 'n': /* iqn */ - tgt_buf_add(&first_str, XML_ELEMENT_INAME, optionList->optarg); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End); - tgt_buf_add_tag(&first_str, "create", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -createTpgt(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "create", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End); - tgt_buf_add_tag(&first_str, "create", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -modifyTarget(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "modify", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - for (; optionList->optval; optionList++) { - switch (optionList->optval) { - case 'p': /* tpgt number */ - tgt_buf_add(&first_str, XML_ELEMENT_TPGT, - optionList->optarg); - break; - case 'l': /* acl */ - tgt_buf_add(&first_str, XML_ELEMENT_ACL, - optionList->optarg); - break; - case 'a': /* alias */ - tgt_buf_add(&first_str, XML_ELEMENT_ALIAS, - optionList->optarg); - break; - case 'm': /* max recv */ - tgt_buf_add(&first_str, XML_ELEMENT_MAXRECV, - optionList->optarg); - break; - case 'z': /* grow lun size */ - tgt_buf_add(&first_str, XML_ELEMENT_SIZE, - optionList->optarg); - break; - case 'u': - tgt_buf_add(&first_str, XML_ELEMENT_LUN, - optionList->optarg); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); - tgt_buf_add_tag(&first_str, "modify", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -modifyInitiator(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - char chapSecret[MAX_CHAP_SECRET_LEN+1]; - int secretLen = 0; - int ret = 0; - - if (operand == NULL) - return (1); - if (options == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "modify", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - for (; optionList->optval; optionList++) { - switch (optionList->optval) { - case 'H': /* chap-name */ - if (strlen(optionList->optarg) != 0) { - tgt_buf_add(&first_str, XML_ELEMENT_CHAPNAME, - optionList->optarg); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_DELETE_CHAPNAME, - OPT_TRUE); - } - break; - case 'C': /* chap-secret */ - ret = getSecret((char *)&chapSecret[0], &secretLen, - MIN_CHAP_SECRET_LEN, MAX_CHAP_SECRET_LEN); - if (ret != 0) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Cannot read CHAP secret")); - return (ret); - } - chapSecret[secretLen] = '\0'; - if (secretLen != 0) { - tgt_buf_add(&first_str, XML_ELEMENT_CHAPSECRET, - chapSecret); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_DELETE_CHAPSECRET, - OPT_TRUE); - } - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - } - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End); - tgt_buf_add_tag(&first_str, "modify", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -modifyTpgt(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - boolean_t isIpv6 = B_FALSE; - uint16_t port; - char IpAddress[MAX_IPADDRESS_LEN]; - - if (operand == NULL) - return (1); - if (optionList == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "modify", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - switch (optionList->optval) { - case 'i': /* ip address */ - if (parseAddress(optionList->optarg, 0, - IpAddress, 256, &port, &isIpv6) != - PARSE_ADDR_OK) { - return (1); - } - tgt_buf_add(&first_str, XML_ELEMENT_IPADDR, IpAddress); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End); - tgt_buf_add_tag(&first_str, "modify", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -modifyAdmin(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - char chapSecret[MAX_CHAP_SECRET_LEN+1]; - char olddir[MAXPATHLEN]; - char newdir[MAXPATHLEN]; - int secretLen = 0; - int ret = 0; - - if (operand == NULL) - return (1); - if (options == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "modify", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - for (; optionList->optval; optionList++) { - switch (optionList->optval) { - case 'd': /* base directory */ - (void) getcwd(olddir, sizeof (olddir)); - - /* - * Attempt to create the new base directory. - * This may fail for one of two reasons. - * (a) The path given is invalid or (b) it - * already exists. If (a) is true then then - * following chdir() will fail and the user - * notified. If (b) is true, then chdir() will - * succeed. - */ - (void) mkdir(optionList->optarg, 0700); - - if (chdir(optionList->optarg) == -1) { - (void) fprintf(stderr, "%s: %s\n", - cmdName, gettext("Invalid path")); - free(first_str); - return (1); - } - (void) getcwd(newdir, sizeof (newdir)); - tgt_buf_add(&first_str, XML_ELEMENT_BASEDIR, - newdir); - (void) chdir(olddir); - break; - case 'H': /* chap name */ - if (strlen(optionList->optarg) != 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_CHAPNAME, - optionList->optarg); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_DELETE_CHAPNAME, - OPT_TRUE); - } - break; - case 'C': /* chap secert */ - ret = getSecret((char *)&chapSecret[0], - &secretLen, - MIN_CHAP_SECRET_LEN, - MAX_CHAP_SECRET_LEN); - if (ret != 0) { - (void) fprintf(stderr, "%s: %s\n", - cmdName, - gettext("Cannot read CHAP secret")); - free(first_str); - return (ret); - } - chapSecret[secretLen] = '\0'; - if (secretLen != 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_CHAPSECRET, - chapSecret); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_DELETE_CHAPSECRET, - OPT_TRUE); - } - break; - case 'R': /* radius access */ - if (strcmp(optionList->optarg, - OPT_ENABLE) == 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_RAD_ACCESS, OPT_TRUE); - } else - if (strcmp(optionList->optarg, - OPT_DISABLE) == 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_RAD_ACCESS, OPT_FALSE); - } else { - (void) fprintf(stderr, "%s: %s\n", - cmdName, - gettext("Option value should be" - "enable/disable")); - free(first_str); - return (1); - } - break; - case 'r': /* radius server */ - if (strlen(optionList->optarg) != 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_RAD_SERV, - optionList->optarg); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_DELETE_RAD_SERV, - OPT_TRUE); - } - break; - case 'P': /* radius secret */ - ret = getSecret((char *)&chapSecret[0], - &secretLen, MIN_CHAP_SECRET_LEN, - MAX_CHAP_SECRET_LEN); - if (ret != 0) { - (void) fprintf(stderr, "%s: %s\n", - cmdName, - gettext("Cannot read RADIUS " - "secret")); - free(first_str); - return (ret); - } - chapSecret[secretLen] = '\0'; - if (secretLen != 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_RAD_SECRET, - chapSecret); - } else { - tgt_buf_add(&first_str, - XML_ELEMENT_DELETE_RAD_SECRET, - OPT_TRUE); - } - break; - case 'S': /* iSNS access */ - if (strcmp(optionList->optarg, - OPT_ENABLE) == 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_ISNS_ACCESS, OPT_TRUE); - } else - if (strcmp(optionList->optarg, - OPT_DISABLE) == 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_ISNS_ACCESS, OPT_FALSE); - } else { - (void) fprintf(stderr, "%s: %s\n", - cmdName, - gettext("Option value should be" - "enable/disable")); - free(first_str); - return (1); - } - break; - case 's': /* iSNS server */ - if (strlen(optionList->optarg) > - MAXHOSTNAMELEN) { - (void) fprintf(stderr, "%s: %s\n", - cmdName, - gettext("option too long")); - return (1); - } - tgt_buf_add(&first_str, XML_ELEMENT_ISNS_SERV, - optionList->optarg); - break; - case 'f': /* fast write back */ - if (strcmp(optionList->optarg, - OPT_ENABLE) == 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_FAST, OPT_TRUE); - } else - if (strcmp(optionList->optarg, - OPT_DISABLE) == 0) { - tgt_buf_add(&first_str, - XML_ELEMENT_FAST, OPT_FALSE); - } else { - (void) fprintf(stderr, "%s: %s\n", - cmdName, - gettext("Option value should be" - "enable/disable")); - free(first_str); - return (1); - } - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End); - tgt_buf_add_tag(&first_str, "modify", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -deleteTarget(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - - if (operand == NULL) - return (1); - if (options == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "delete", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - switch (optionList->optval) { - case 'u': /* all */ - tgt_buf_add(&first_str, XML_ELEMENT_LUN, optionList->optarg); - break; - case 'l': /* acl */ - tgt_buf_add(&first_str, XML_ELEMENT_ACL, optionList->optarg); - break; - case 'p': /* tpgt number */ - tgt_buf_add(&first_str, XML_ELEMENT_TPGT, optionList->optarg); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); - tgt_buf_add_tag(&first_str, "delete", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -deleteInitiator(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - - if (operand == NULL) - return (1); - if (options == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "delete", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - switch (optionList->optval) { - case 'A': /* all */ - tgt_buf_add(&first_str, XML_ELEMENT_ALL, optionList->optarg); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End); - tgt_buf_add_tag(&first_str, "delete", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -/*ARGSUSED*/ -static int -deleteTpgt(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - cmdOptions_t *optionList = options; - boolean_t isIpv6 = B_FALSE; - uint16_t port; - char IpAddress[MAX_IPADDRESS_LEN]; - - if (operand == NULL) - return (1); - if (options == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "delete", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start); - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - switch (optionList->optval) { - case 'A': /* all */ - tgt_buf_add(&first_str, XML_ELEMENT_ALL, optionList->optarg); - break; - case 'i': /* ip address */ - if (parseAddress(optionList->optarg, 0, - IpAddress, 256, &port, &isIpv6) != - PARSE_ADDR_OK) { - return (1); - } - tgt_buf_add(&first_str, XML_ELEMENT_IPADDR, IpAddress); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End); - tgt_buf_add_tag(&first_str, "delete", Tag_End); - - node = tgt_door_call(first_str, 0); - free(first_str); - return (formatErrString(node)); -} - -static int -listTarget(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node = NULL; - tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ - tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ - tgt_node_t *n3 = NULL; /* pointer to node (depth=3) */ - tgt_node_t *n4 = NULL; /* pointer to node (depth=4) */ - int conns; - char buf[32]; - Boolean_t verbose = False; - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "list", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); - - if (operandLen) - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - /* - * Always retrieve the iostats which will give us the - * connection count information even if we're not doing - * a verbose output. - */ - tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE); - - if (options) { - switch (options->optval) { - case 0: - break; - case 'v': - tgt_buf_add(&first_str, XML_ELEMENT_LUNINFO, OPT_TRUE); - verbose = True; - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", cmdName, - options->optval, gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); - tgt_buf_add_tag(&first_str, "list", Tag_End); - - if ((node = tgt_door_call(first_str, 0)) == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("No reponse from daemon")); - return (1); - } - free(first_str); - - if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - return (1); - } - - n1 = NULL; - while ((n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) != NULL) { - (void) printf("%s: %s\n", gettext("Target"), n1->x_value); - n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"), - n2 ? n2->x_value : gettext("Not set")); - - if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_ALIAS, NULL)) != - NULL) - (void) printf("%s%s: %s\n", dospace(1), - gettext("Alias"), n2->x_value); - - if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_MAXRECV, NULL)) != - NULL) - (void) printf("%s%s: %s\n", dospace(1), - gettext("MaxRecv"), n2->x_value); - - /* - * Count the number of connections available. - */ - n2 = NULL; - conns = 0; - while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2)) - conns++; - (void) printf("%s%s: %d\n", dospace(1), gettext("Connections"), - conns); - - if (verbose == False) - continue; - - /* - * Displaying the individual connections must be done - * first when verbose is turned on because you'll notice - * above that we've left the output hanging with a label - * indicating connections are coming next. - */ - n2 = NULL; - while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2)) { - (void) printf("%s%s:\n", dospace(2), - gettext("Initiator")); - (void) printf("%s%s: %s\n", dospace(3), - gettext("iSCSI Name"), n2->x_value); - n3 = tgt_node_next_child(n2, XML_ELEMENT_ALIAS, NULL); - (void) printf("%s%s: %s\n", dospace(3), - gettext("Alias"), - n3 ? n3->x_value : gettext("unknown")); - } - - (void) printf("%s%s:\n", dospace(1), gettext("ACL list")); - n2 = tgt_node_next_child(n1, XML_ELEMENT_ACLLIST, NULL); - n3 = NULL; - while (n3 = tgt_node_next_child(n2, XML_ELEMENT_INIT, n3)) { - (void) printf("%s%s: %s\n", dospace(2), - gettext("Initiator"), - n3->x_value); - } - - (void) printf("%s%s:\n", dospace(1), gettext("TPGT list")); - n2 = tgt_node_next_child(n1, XML_ELEMENT_TPGTLIST, NULL); - n3 = NULL; - while (n3 = tgt_node_next_child(n2, XML_ELEMENT_TPGT, n3)) { - (void) printf("%s%s: %s\n", dospace(2), - gettext("TPGT"), - n3->x_value); - } - - (void) printf("%s%s:\n", dospace(1), - gettext("LUN information")); - n2 = tgt_node_next_child(n1, XML_ELEMENT_LUNINFO, NULL); - n3 = NULL; - while (n3 = tgt_node_next_child(n2, XML_ELEMENT_LUN, n3)) { - (void) printf("%s%s: %s\n", dospace(2), gettext("LUN"), - n3->x_value); - - n4 = tgt_node_next_child(n3, XML_ELEMENT_GUID, NULL); - (void) printf("%s%s: %s\n", dospace(3), gettext("GUID"), - n4 ? n4->x_value : gettext("unknown")); - - n4 = tgt_node_next_child(n3, XML_ELEMENT_VID, NULL); - (void) printf("%s%s: %s\n", dospace(3), gettext("VID"), - n4 ? n4->x_value : gettext("unknown")); - - n4 = tgt_node_next_child(n3, XML_ELEMENT_PID, NULL); - (void) printf("%s%s: %s\n", dospace(3), gettext("PID"), - n4 ? n4->x_value : gettext("unknown")); - - n4 = tgt_node_next_child(n3, XML_ELEMENT_DTYPE, NULL); - (void) printf("%s%s: %s\n", dospace(3), gettext("Type"), - n4 ? n4->x_value : gettext("unknown")); - - n4 = tgt_node_next_child(n3, XML_ELEMENT_SIZE, NULL); - if (n4 && (strtol(n4->x_value, NULL, 0) != 0)) { - (void) printf("%s%s: %s\n", dospace(3), - gettext("Size"), - number_to_scaled_string(buf, - strtoll(n4->x_value, - NULL, 0), 512, 1024)); - } else { - (void) printf("%s%s: %s\n", dospace(3), - gettext("Size"), gettext("unknown")); - } - - n4 = tgt_node_next_child(n3, XML_ELEMENT_BACK, NULL); - if (n4) { - (void) printf("%s%s: %s\n", dospace(3), - gettext("Backing store"), n4->x_value); - } - - n4 = tgt_node_next_child(n3, XML_ELEMENT_STATUS, NULL); - (void) printf("%s%s: %s\n", dospace(3), - gettext("Status"), - n4 ? n4->x_value : gettext("unknown")); - } - } - - return (0); -} - -static int -listInitiator(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node; - tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ - tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ - Boolean_t verbose = False; - cmdOptions_t *optionList = options; - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "list", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start); - - if (operandLen) { - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - } - if (optionList) { - switch (optionList->optval) { - case 0: - break; - case 'v': - verbose = True; - tgt_buf_add(&first_str, - XML_ELEMENT_VERBOSE, OPT_TRUE); - break; - - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End); - tgt_buf_add_tag(&first_str, "list", Tag_End); - - if ((node = tgt_door_call(first_str, 0)) == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("No reponse from daemon")); - return (1); - } - free(first_str); - - if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - return (1); - } - - n1 = NULL; - while (n1 = tgt_node_next_child(node, XML_ELEMENT_INIT, n1)) { - (void) printf("%s: %s\n", gettext("Initiator"), n1->x_value); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"), - n2 ? n2->x_value : gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"), - n2 ? n2->x_value : gettext("Not set")); - - if (verbose == True) { - n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPSECRET, - NULL); - (void) printf("%s%s: %s\n", dospace(1), - gettext("CHAP Secret"), - n2 ? gettext("Set") : gettext("Not set")); - } - - } - - return (0); -} - -static int -listTpgt(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node = NULL; - tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ - tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ - cmdOptions_t *optionList = options; - Boolean_t verbose = False; - int addrs; - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "list", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start); - - if (operandLen) - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - if (optionList) { - switch (optionList->optval) { - case 0: /* no options, treat as --verbose */ - break; - case 'v': - verbose = True; - tgt_buf_add(&first_str, - XML_ELEMENT_VERBOSE, OPT_TRUE); - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", - cmdName, optionList->optval, - gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End); - tgt_buf_add_tag(&first_str, "list", Tag_End); - - if ((node = tgt_door_call(first_str, 0)) == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("No reponse from daemon")); - return (1); - } - free(first_str); - - if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - return (1); - } - - n1 = NULL; - while (n1 = tgt_node_next_child(node, XML_ELEMENT_TPGT, n1)) { - (void) printf("%s: %s\n", gettext("TPGT"), n1->x_value); - n2 = NULL; - addrs = 0; - while (n2 = tgt_node_next(n1, XML_ELEMENT_IPADDR, n2)) { - if (verbose == True) - (void) printf("%s%s: %s\n", dospace(1), - gettext("IP Address"), - n2 ? n2->x_value : gettext("Not set")); - addrs++; - } - - if (verbose == False) { - (void) printf("%s%s: %d\n", dospace(1), - gettext("IP Address count"), addrs); - } else if (addrs == 0) { - - /* - * Verbose is true, but there where no addresses - * for this TPGT. To keep the output consistent - * dump a "Not set" string out. - */ - (void) printf("%s%s: %s\n", dospace(1), - gettext("IP Address"), gettext("Not set")); - } - } - - return (0); -} - -/*ARGSUSED*/ -static int -showAdmin(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - tgt_node_t *node = NULL; - tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ - tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ - - if (operand == NULL) - return (1); - - tgt_buf_add_tag(&first_str, "list", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End); - tgt_buf_add_tag(&first_str, "list", Tag_End); - - if ((node = tgt_door_call(first_str, 0)) == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("No reponse from daemon")); - return (1); - } - free(first_str); - - if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - return (1); - } - - (void) printf("%s:\n", cmdName); - - n1 = tgt_node_next_child(node, XML_ELEMENT_ADMIN, NULL); - if (n1 == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - return (1); - } - - n2 = tgt_node_next_child(n1, XML_ELEMENT_BASEDIR, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("Base Directory"), - n2 ? n2->x_value : gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"), - n2 ? n2->x_value : gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_ACCESS, NULL); - (void) printf("%s%s: ", dospace(1), gettext("RADIUS Access")); - if (n2) { - if (strcmp(n2->x_value, OPT_TRUE) == 0) - (void) printf("%s\n", gettext("Enabled")); - else - (void) printf("%s\n", gettext("Disabled")); - } else - (void) printf("%s\n", gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_SERV, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("RADIUS Server"), - n2 ? n2->x_value : gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_ACCESS, NULL); - (void) printf("%s%s: ", dospace(1), gettext("iSNS Access")); - if (n2) { - if (strcmp(n2->x_value, OPT_TRUE) == 0) - (void) printf("%s\n", gettext("Enabled")); - else - (void) printf("%s\n", gettext("Disabled")); - } else - (void) printf("%s\n", gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERV, NULL); - (void) printf("%s%s: %s\n", dospace(1), gettext("iSNS Server"), - n2 ? n2->x_value : gettext("Not set")); - - n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERVER_STATUS, NULL); - if (n2) { - /* - * if NULL, that means either the isns discovery is - * disabled or the server address is not set. - */ - if (n2->x_value != NULL) { - (void) printf("%s%s: ", dospace(1), - gettext("iSNS Server Status")); - (void) printf("%s\n", n2->x_value); - } - } - - n2 = tgt_node_next_child(n1, XML_ELEMENT_FAST, NULL); - (void) printf("%s%s: ", dospace(1), gettext("Fast Write ACK")); - if (n2) { - if (strcmp(n2->x_value, OPT_TRUE) == 0) - (void) printf("%s\n", gettext("Enabled")); - else - (void) printf("%s\n", gettext("Disabled")); - } else - (void) printf("%s\n", gettext("Not set")); - - return (0); -} - -static int -showStats(int operandLen, char *operand[], cmdOptions_t *options) -{ - char *first_str = NULL; - char scale_buf[16]; - tgt_node_t *node, *n1; - int interval = -1; - int count = -1; - int header; - stat_delta_t cur_data, *pd; - - tgt_buf_add_tag(&first_str, "list", Tag_Start); - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); - - tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE); - if (operandLen) - tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); - - for (; options->optval; options++) { - switch (options->optval) { - case 0: - break; - case 'I': /* optarg = refresh interval */ - interval = atoi(options->optarg); - if (interval == 0) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("interval must be non-zero")); - free(first_str); - return (1); - } - break; - case 'N': - count = atoi(options->optarg); - if (count == 0) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("count must be non-zero")); - free(first_str); - return (1); - } - break; - default: - (void) fprintf(stderr, "%s: %c: %s\n", cmdName, - options->optval, gettext("unknown option")); - free(first_str); - return (1); - } - } - - tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); - tgt_buf_add_tag(&first_str, "list", Tag_End); - - header = 1; - /*CONSTANTCONDITION*/ - while (1) { - if (--header == 0) { - (void) printf("%20s %12s %12s\n", " ", - gettext("operations"), gettext("bandwidth ")); - (void) printf("%-20s %5s %5s %5s %5s\n", - gettext("device"), gettext("read"), - gettext("write"), gettext("read"), - gettext("write")); - (void) printf("%-20s %5s %5s %5s %5s\n", - "--------------------", "-----", "-----", - "-----", "-----"); - header = 20; - } - if ((node = tgt_door_call(first_str, 0)) == NULL) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("No reponse from daemon")); - return (1); - } - - if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { - (void) fprintf(stderr, "%s: %s\n", cmdName, - gettext("Bad XML response")); - free(first_str); - tgt_node_free(node); - stats_free(); - return (1); - } - - n1 = NULL; - while (n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) { - stats_load_counts(n1, &cur_data); - if ((pd = stats_prev_counts(&cur_data)) == NULL) { - free(first_str); - tgt_node_free(node); - return (1); - } - (void) printf("%-20s ", pd->device); - (void) printf("%5s ", - number_to_scaled_string(scale_buf, - cur_data.read_cmds - pd->read_cmds, 1, 1024)); - (void) printf("%5s ", - number_to_scaled_string(scale_buf, - cur_data.write_cmds - pd->write_cmds, 1, 1024)); - (void) printf("%5s ", - number_to_scaled_string(scale_buf, - cur_data.read_blks - pd->read_blks, 512, 1024)); - (void) printf("%5s\n", - number_to_scaled_string(scale_buf, - cur_data.write_blks - pd->write_blks, 512, 1024)); - stats_update_counts(pd, &cur_data); - } - tgt_node_free(node); - - if (count == -1) { - if (interval == -1) - /* No count or internal, do it just once */ - break; - else - (void) sleep(interval); - } else if (--count) { - if (interval == -1) - break; - else - (void) sleep(interval); - } else - break; - } - - stats_free(); - free(first_str); - return (0); -} - -/* - * 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); -} - -/* - * main calls a parser that checks syntax of the input command against - * various rules tables. - * - * The parser provides usage feedback based upon same tables by calling - * two usage functions, usage and subUsage, handling command and subcommand - * usage respectively. - * - * The parser handles all printing of usage syntactical errors - * - * When syntax is successfully validated, the parser calls the associated - * function using the subcommands table functions. - * - * Syntax is as follows: - * command subcommand [options] resource-type [<object>] - * - * The return value from the function is placed in funcRet - */ -int -main(int argc, char *argv[]) -{ - synTables_t synTables; - char versionString[VERSION_STRING_MAX_LEN]; - int ret; - int funcRet; - void *subcommandArgs = NULL; - - /* set global command name */ - cmdName = getExecBasename(argv[0]); - - if (getzoneid() != GLOBAL_ZONEID) { - (void) fprintf(stderr, - "%s: this command is only available in the 'global' " - "zone\n", cmdName); - exit(1); - } - - (void) snprintf(versionString, sizeof (versionString), "%s.%s", - VERSION_STRING_MAJOR, VERSION_STRING_MINOR); - synTables.versionString = versionString; - synTables.longOptionTbl = &longOptions[0]; - synTables.subcommandTbl = &subcommands[0]; - synTables.objectTbl = &objects[0]; - synTables.objectRulesTbl = &objectRules[0]; - synTables.optionRulesTbl = &optionRules[0]; - - /* call the CLI parser */ - ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet); - if (ret == 1) { - (void) printf("%s %s(1M)\n", - gettext("For more information, please see"), cmdName); - return (1); - } else if (ret == -1) { - perror(cmdName); - return (1); - } - - return (funcRet); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/Makefile b/usr/src/cmd/iscsi/iscsitgtd/Makefile deleted file mode 100644 index 8e13a10705..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/Makefile +++ /dev/null @@ -1,94 +0,0 @@ -# -# 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. -# - -PROG= iscsitgtd -OBJS = main.o mgmt.o mgmt_create.o mgmt_list.o mgmt_modify.o mgmt_remove.o -OBJS += iscsi_authclient.o iscsi_authglue.o iscsi_cmd.o iscsi_conn.o -OBJS += iscsi_crc.o iscsi_ffp.o iscsi_login.o iscsi_sess.o radius.o -OBJS += t10_sam.o t10_spc.o t10_sbc.o t10_raw_if.o t10_ssc.o t10_osd.o -OBJS += t10_spc_pr.o util.o util_err.o util_ifname.o util_port.o util_queue.o -OBJS += isns_client.o isns.o mgmt_scf.o -POFILE= iscsitgtd.po -POFILES = $(OBJS:%.o=%.po) - -include ../../Makefile.cmd -include $(SRC)/cmd/iscsi/Makefile.iscsi - -$(64ONLY)SUBDIRS= $(MACH) -$(BUILD64)SUBDIRS += $(MACH64) - -MANIFEST = iscsi_target.xml -SVCMETHOD = svc-iscsitgt - -ROOTMANIFESTDIR = $(ROOTSVCSYSTEM) -$(ROOTSVCSYSTEM)/iscsi_target.xml := FILEMODE = 0444 - -DLIBSRCS = iscsi.d - -ROOTDLIBDIR = $(ROOT)/usr/lib/dtrace -ROOTDLIBS = $(DLIBSRCS:%=$(ROOTDLIBDIR)/%) -$(ROOTDLIBS) := FILEMODE = 0644 - -CPPFLAGS += -D_FILE_OFFSET_BITS=64 -I${ISCSICOMMONDIR} -I${HDCRCCOMMONDIR} - -all := TARGET = all -install := TARGET = install -clean := TARGET = clean -clobber := TARGET = clobber -lint := TARGET = lint - -.KEEP_STATE: - -all: $(SUBDIRS) - -clean clobber lint: $(SUBDIRS) - -install: $(SUBDIRS) $(ROOTMANIFEST) $(ROOTDLIBS) $(ROOTSVCMETHOD) - -$(RM) $(ROOTUSRSBINPROG) - -$(LN) $(ISAEXEC) $(ROOTUSRSBINPROG) - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -catalog: $(POFILE) - -$(POFILE): $(POFILES) - $(RM) $@ - cat $(POFILES) > $@ - -check: $(CHKMANIFEST) - -$(ROOTDLIBDIR): - $(INS.dir) - -$(ROOTDLIBDIR)/%.d: %.d - $(INS.file) - -$(ROOTDLIBS): $(ROOTDLIBDIR) - -FRC: - -include ../../Makefile.targ diff --git a/usr/src/cmd/iscsi/iscsitgtd/Makefile.com b/usr/src/cmd/iscsi/iscsitgtd/Makefile.com deleted file mode 100644 index 6f11ad50d3..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/Makefile.com +++ /dev/null @@ -1,91 +0,0 @@ -# -# 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. -# - -PROG = iscsitgtd - -DSRC = iscsi_provider.d -DTRACE_HEADER = $(DSRC:%.d=%.h) - -COBJS = main.o mgmt.o mgmt_create.o mgmt_list.o mgmt_modify.o mgmt_remove.o -COBJS += iscsi_authclient.o iscsi_authglue.o iscsi_cmd.o iscsi_conn.o -COBJS += iscsi_crc.o iscsi_ffp.o iscsi_login.o iscsi_sess.o radius.o -COBJS += t10_sam.o t10_spc.o t10_sbc.o t10_raw_if.o t10_ssc.o t10_osd.o -COBJS += t10_spc_pr.o util.o util_err.o util_ifname.o util_port.o util_queue.o -COBJS += isns_client.o isns.o mgmt_scf.o -OBJS= $(COBJS) $(DSRC:%.d=%.o) -SRCS= $(COBJS:%.o=../%.c) $(COMMON_SRCS) - -include ../../../Makefile.cmd -include $(SRC)/cmd/iscsi/Makefile.iscsi - -CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS) -CTFCONVERT_HOOK = && $(CTFCONVERT_O) -CFLAGS += $(CTF_FLAGS) -CFLAGS64 += $(CTF_FLAGS) -NATIVE_CFLAGS += $(CTF_FLAGS) - -CFLAGS += $(CCVERBOSE) -CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -I/usr/include/libxml2 -I${HDCRCCOMMONDIR} -CFLAGS64 += $(CCVERBOSE) - -CLEANFILES += $(OBJS) ../$(DTRACE_HEADER) - -.KEEP_STATE: - -all: $(PROG) - -LDLIBS += -lumem -luuid -lsocket -lnsl -lavl -lmd5 -ladm -lefi -LDLIBS += -liscsitgt -lzfs -ldlpi -lscf -lsasl -XMLLIB = -lxml2 - -$(PROG): $(OBJS) $(COMMON_OBJS) - $(LINK.c) $(OBJS) $(COMMON_OBJS) -o $@ $(LDLIBS) $(XMLLIB) $(CTFMERGE_HOOK) - $(POST_PROCESS) - -lint := LINTFLAGS += -unv -lint := LINTFLAGS64 += -unv - -lint: $$(SRCS) - $(LINT.c) -I.. ${INCLUDES} $(SRCS) $(LDLIBS) - - -../%.h: ../%.d - $(DTRACE) -xnolibs -h -s $< -o $@ - -%.o: $(ISCSICOMMONDIR)/%.c ../$(DTRACE_HEADER) - $(COMPILE.c) $< $(CTFCONVERT_HOOK) - $(POST_PROCESS_O) - -%.o: ../%.c ../$(DTRACE_HEADER) - $(COMPILE.c) $< $(CTFCONVERT_HOOK) - $(POST_PROCESS_O) - -%.o: ../%.d $(COBJS) - $(COMPILE.d) -xnolibs -s $< $(COBJS) - -clean: - $(RM) $(CLEANFILES) $(COMMON_OBJS) - -include ../../../Makefile.targ diff --git a/usr/src/cmd/iscsi/iscsitgtd/amd64/Makefile b/usr/src/cmd/iscsi/iscsitgtd/amd64/Makefile deleted file mode 100644 index cee9d7ffbe..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/amd64/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.com -include ../../../Makefile.cmd.64 - -install: all $(ROOTUSRSBINPROG64) diff --git a/usr/src/cmd/iscsi/iscsitgtd/errcode.h b/usr/src/cmd/iscsi/iscsitgtd/errcode.h deleted file mode 100644 index ff351bbb85..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/errcode.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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 _TARGET_ERRCODE_H -#define _TARGET_ERRCODE_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - ERR_SUCCESS = 1000, - ERR_NULL_XML_MESSAGE, - ERR_SYNTAX_EMPTY, - ERR_SYNTAX_MISSING_ALL, - ERR_SYNTAX_MISSING_BACKING_STORE, - ERR_SYNTAX_MISSING_INAME, - ERR_SYNTAX_MISSING_IPADDR, - ERR_SYNTAX_MISSING_NAME, - ERR_SYNTAX_MISSING_OBJECT, - ERR_SYNTAX_MISSING_OPERAND, - ERR_SYNTAX_MISSING_SIZE, - ERR_SYNTAX_MISSING_TYPE, - ERR_SYNTAX_EMPTY_ACL, - ERR_SYNTAX_EMPTY_ALIAS, - ERR_SYNTAX_EMPTY_CHAPNAME, - ERR_SYNTAX_EMPTY_CHAPSECRET, - ERR_SYNTAX_EMPTY_IPADDR, - ERR_SYNTAX_EMPTY_MAXRECV, - ERR_SYNTAX_EMPTY_TPGT, - ERR_SYNTAX_INVALID_NAME, - ERR_INVALID_COMMAND, - ERR_INVALID_OBJECT, - ERR_INVALID_IP, - ERR_INVALID_BASEDIR, - ERR_INVALID_TPGT, - ERR_INVALID_MAXRECV, - ERR_INVALID_RADSRV, - ERR_INVALID_SIZE, - ERR_INIT_EXISTS, - ERR_NAME_TOO_LONG, - ERR_LUN_EXISTS, - ERR_TPGT_EXISTS, - ERR_ACL_NOT_FOUND, - ERR_INIT_NOT_FOUND, - ERR_TARG_NOT_FOUND, - ERR_LUN_NOT_FOUND, - ERR_LUN_INVALID_RANGE, - ERR_TPGT_NOT_FOUND, - ERR_ACCESS_RAW_DEVICE_FAILED, - ERR_CREATE_METADATA_FAILED, - ERR_CREATE_SYMLINK_FAILED, - ERR_CREATE_NAME_TOO_LONG, - ERR_DISK_BACKING_MUST_BE_REGULAR_FILE, - ERR_DISK_BACKING_NOT_VALID_RAW, - ERR_DISK_BACKING_SIZE_OR_FILE, - ERR_STAT_BACKING_FAILED, - ERR_RAW_PART_NOT_CAP, - ERR_CREATE_TARGET_DIR_FAILED, - ERR_ENCODE_GUID_FAILED, - ERR_INIT_XML_READER_FAILED, - ERR_INVALID_XML_REQUEST, - ERR_OPEN_PARAM_FILE_FAILED, - ERR_UPDATE_MAINCFG_FAILED, - ERR_UPDATE_TARGCFG_FAILED, - ERR_VALID_TARG_EXIST, - ERR_TARGCFG_MISSING_INAME, - ERR_NO_MATCH, - ERR_NO_MEM, - ERR_LUN_ZERO_NOT_LAST, - ERR_LUN_ZERO_NOT_FIRST, - ERR_SIZE_MOD_BLOCK, - ERR_CANT_SHRINK_LU, - ERR_RESIZE_WRONG_TYPE, - ERR_RESIZE_WRONG_DTYPE, - ERR_LUN_NOT_GROWN, - ERR_FILE_TOO_BIG, - ERR_FAILED_TO_CREATE_LU, - ERR_TAPE_NOT_SUPPORTED_IN_32BIT, - ERR_INTERNAL_ERROR, - ERR_BAD_CREDS, - ERR_NO_PERMISSION, - ERR_INVALID_ISNS_SRV, - ERR_ISNS_ERROR, - ERR_TPGT_NO_IPADDR, - ERR_TPGT_IN_USE, - ERR_ZFS_ISCSISHARE_OFF -} err_code_t; - -char * -errcode_to_str(err_code_t err_code); - -#ifdef __cplusplus -} -#endif - -#endif /* _TARGET_ERRCODE_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/i386/Makefile b/usr/src/cmd/iscsi/iscsitgtd/i386/Makefile deleted file mode 100644 index fde14781e6..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/i386/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# cmd/iscsi/iscsitgt/i386/Makefile - -include ../Makefile.com - -install: all $(ROOTUSRSBINPROG32) diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi.d b/usr/src/cmd/iscsi/iscsitgtd/iscsi.d deleted file mode 100644 index f77d53cf25..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi.d +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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. - */ - -#pragma D depends_on library net.d -#pragma D depends_on module genunix -#pragma D depends_on library scsi.d - -typedef struct uiscsiproto uiscsiproto_t; - -typedef struct uiscsiproto64 { - struct sockaddr_storage *uip_taddr; - struct sockaddr_storage *uip_iaddr; - - uint64_t uip_target; - uint64_t uip_initiator; - uint64_t uip_lun; - - uint32_t uip_itt; - uint32_t uip_ttt; - - uint32_t uip_cmdsn; - uint32_t uip_statsn; - uint32_t uip_datasn; - - uint32_t uip_datalen; - uint32_t uip_flags; -} uiscsiproto64_t; - -typedef struct uiscsiproto32 { - struct sockaddr_storage *uip_taddr; - struct sockaddr_storage *uip_iaddr; - - uint32_t uip_target; - uint32_t uip_initiator; - uint64_t uip_lun; - - uint32_t uip_itt; - uint32_t uip_ttt; - - uint32_t uip_cmdsn; - uint32_t uip_statsn; - uint32_t uip_datasn; - - uint32_t uip_datalen; - uint32_t uip_flags; -} uiscsiproto32_t; - -#pragma D binding "1.5" translator -translator conninfo_t < uiscsiproto_t *P > { - ci_local = (2 == *(sa_family_t *) - copyin((uintptr_t)((curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_taddr), sizeof (uint32_t)) : - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_taddr), sizeof (uint64_t))), - sizeof (sa_family_t))) ? - - inet_ntoa((ipaddr_t *)copyin((uintptr_t) - &((struct sockaddr_in *) - ((curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_taddr), sizeof (uint32_t)) : - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_taddr), sizeof (uint64_t)))) - ->sin_addr, sizeof (ipaddr_t))) : - - inet_ntoa6((in6_addr_t *)copyin((uintptr_t) - &((struct sockaddr_in6 *) - ((curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_taddr), sizeof (uint32_t)) : - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_taddr), sizeof (uint64_t)))) - ->sin6_addr, sizeof (in6_addr_t))); - - ci_remote = (2 == *(sa_family_t *) - copyin((uintptr_t)((curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_iaddr), sizeof (uint32_t)) : - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_iaddr), sizeof (uint64_t))), - sizeof (sa_family_t))) ? - - inet_ntoa((ipaddr_t *)copyin((uintptr_t) - &((struct sockaddr_in *) - ((curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_iaddr), sizeof (uint32_t)) : - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_iaddr), sizeof (uint64_t)))) - ->sin_addr, sizeof (ipaddr_t))) : - - inet_ntoa6((in6_addr_t *)copyin((uintptr_t) - &((struct sockaddr_in6 *) - ((curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_iaddr), sizeof (uint32_t)) : - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_iaddr), sizeof (uint64_t)))) - ->sin6_addr, sizeof (in6_addr_t))); - - ci_protocol = (*(sa_family_t *)copyin((uintptr_t) - ((curthread->t_procp->p_model == 0x00100000) ? - - *(uint32_t *)copyin((uintptr_t) - &(((uiscsiproto32_t *)P)->uip_taddr), sizeof (uint32_t)) : - - *(uint64_t *)copyin((uintptr_t) - &(((uiscsiproto64_t *)P)->uip_taddr), sizeof (uint64_t))), - - sizeof (sa_family_t)) == 2) ? "ipv4" : "ipv6"; -}; - -#pragma D binding "1.5" translator -translator iscsiinfo_t < uiscsiproto_t *P > { - ii_initiator = (curthread->t_procp->p_model == 0x00100000) ? - copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_initiator, sizeof (uint32_t))) : - copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_initiator, sizeof (uint64_t))); - - ii_target = (curthread->t_procp->p_model == 0x00100000) ? - copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_target, sizeof (uint32_t))) : - copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_target, sizeof (uint64_t))); - - ii_lun = (curthread->t_procp->p_model == 0x00100000) ? - *(uint64_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_lun, sizeof (uint64_t)) : - *(uint64_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_lun, sizeof (uint64_t)); - - ii_itt = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_itt, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_itt, sizeof (uint32_t)); - - ii_ttt = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_ttt, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_ttt, sizeof (uint32_t)); - - ii_cmdsn = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_cmdsn, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_cmdsn, sizeof (uint32_t)); - - ii_statsn = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_statsn, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_statsn, sizeof (uint32_t)); - - ii_datasn = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_datasn, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_datasn, sizeof (uint32_t)); - - ii_datalen = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_datalen, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_datalen, sizeof (uint32_t)); - - ii_flags = (curthread->t_procp->p_model == 0x00100000) ? - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto32_t *)P)->uip_flags, sizeof (uint32_t)) : - *(uint32_t *)copyin((uintptr_t) - &((uiscsiproto64_t *)P)->uip_flags, sizeof (uint32_t)); -}; - -typedef struct iscsicmd { - uint64_t ic_len; /* CDB length */ - uint8_t *ic_cdb; /* CDB data */ -} iscsicmd_t; - -typedef struct uiscsicmd { - uint64_t uic_len; - uint8_t *uic_cdb; -} uiscsicmd_t; - -#pragma D binding "1.5" translator -translator iscsicmd_t < uiscsicmd_t *P > { - ic_len = *(uint64_t *)copyin((uintptr_t)&P->uic_len, sizeof (uint64_t)); - ic_cdb = (uint8_t *)copyin((curthread->t_procp->p_model == 0x00100000) ? - (uintptr_t)*(uint32_t *)copyin((uintptr_t)&P->uic_cdb, - sizeof (uint32_t)) : - (uintptr_t)*(uint64_t *)copyin((uintptr_t)&P->uic_cdb, - sizeof (uint64_t)), - *(uint64_t *)copyin((uintptr_t)&P->uic_len, sizeof (uint64_t))); -}; - -inline int ISCSI_FLAG_FINAL = 0x80; -#pragma D binding "1.5" ISCSI_FLAG_FINAL -inline int ISCSI_FLAG_CMD_WRITE = 0x20; -#pragma D binding "1.5" ISCSI_FLAG_CMD_WRITE -inline int ISCSI_FLAG_CMD_READ = 0x40; -#pragma D binding "1.5" ISCSI_FLAG_CMD_READ -inline int ISCSI_FLAG_CMD_BIDI_UNDERFLOW = 0x08; -#pragma D binding "1.5" ISCSI_FLAG_CMD_BIDI_UNDERFLOW -inline int ISCSI_FLAG_CMD_BIDI_OVERFLOW = 0x10; -#pragma D binding "1.5" ISCSI_FLAG_CMD_BIDI_OVERFLOW -inline int ISCSI_FLAG_CMD_UNDERFLOW = 0x02; -#pragma D binding "1.5" ISCSI_FLAG_CMD_UNDERFLOW -inline int ISCSI_FLAG_CMD_OVERFLOW = 0x04; -#pragma D binding "1.5" ISCSI_FLAG_CMD_OVERFLOW -inline int ISCSI_FLAG_DATA_STATUS = 0x01; -#pragma D binding "1.5" ISCSI_FLAG_DATA_STATUS -inline int ISCSI_FLAG_DATA_UNDERFLOW = 0x02; -#pragma D binding "1.5" ISCSI_FLAG_DATA_UNDERFLOW -inline int ISCSI_FLAG_DATA_OVERFLOW = 0x04; -#pragma D binding "1.5" ISCSI_FLAG_DATA_OVERFLOW -inline int ISCSI_FLAG_DATA_ACK = 0x40; -#pragma D binding "1.5" ISCSI_FLAG_DATA_ACK -inline int ISCSI_FLAG_TEXT_CONTINUE = 0x40; -#pragma D binding "1.5" ISCSI_FLAG_TEXT_CONTINUE -inline int ISCSI_FLAG_LOGIN_CONTINUE = 0x40; -#pragma D binding "1.5" ISCSI_FLAG_LOGIN_CONTINUE -inline int ISCSI_FLAG_LOGIN_TRANSIT = 0x80; -#pragma D binding "1.5" ISCSI_FLAG_LOGIN_TRANSIT diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_authclient.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_authclient.c deleted file mode 100644 index 8aa279ed0e..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_authclient.c +++ /dev/null @@ -1,3042 +0,0 @@ -/* - * 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 2000 by Cisco Systems, Inc. All rights reserved. - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * FIXME: If this is true we have some problems. draft 15!? - * - * This file implements the iSCSI CHAP authentication method based on - * draft-ietf-ips-iscsi-15.txt. The code in this file is meant - * to be platform independent, and makes use of only limited library - * functions, presently only string.h. Platform dependent routines - * are defined in iscsi_authclient.h, but implemented in another file. - * - * This code in this files assumes a single thread of execution - * for each IscsiAuthClient structure, and does no locking. - */ -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef _KERNEL - -#include "iscsi.h" - -#else - -#include <strings.h> -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#endif - -#include <sys/iscsi_authclient.h> - -struct iscsiAuthKeyInfo_t { - const char *name; -}; -typedef struct iscsiAuthKeyInfo_t IscsiAuthKeyInfo; - - -IscsiAuthClientGlobalStats iscsiAuthClientGlobalStats; - -/* - * Note: The ordering of this table must match the order - * defined by IscsiAuthKeyType in iscsiAuthClient.h. - */ -static IscsiAuthKeyInfo iscsiAuthClientKeyInfo[iscsiAuthKeyTypeMaxCount] = { - {"AuthMethod"}, - {"CHAP_A"}, - {"CHAP_N"}, - {"CHAP_R"}, - {"CHAP_I"}, - {"CHAP_C"} -}; - -static const char iscsiAuthClientHexString[] = "0123456789abcdefABCDEF"; -static const char iscsiAuthClientBase64String[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char iscsiAuthClientAuthMethodChapOptionName[] = "CHAP"; - - -static int -iscsiAuthClientCheckString(const char *s, - unsigned int maxLength, unsigned int *pOutLength) -{ - unsigned int length; - - if (!s) { - return (TRUE); - } - - for (length = 0; length < maxLength; length++) { - if (*s++ == '\0') { - if (pOutLength) { - *pOutLength = length; - } - return (FALSE); - } - } - - return (TRUE); -} - - -static int -iscsiAuthClientStringCopy(char *stringOut, const char *stringIn, - unsigned int length) -{ - if (!stringOut || !stringIn || length == 0) { - return (TRUE); - } - - while ((*stringOut++ = *stringIn++) != '\0') { - if (--length == 0) { - stringOut--; - *stringOut = '\0'; - return (TRUE); - } - } - - return (FALSE); -} - - -static int -iscsiAuthClientStringAppend(char *stringOut, const char *stringIn, - unsigned int length) -{ - if (!stringOut || !stringIn || length == 0) { - return (TRUE); - } - - while (*stringOut++ != '\0') { - if (--length == 0) { - stringOut--; - *stringOut = '\0'; - return (TRUE); - } - } - - stringOut--; - - while ((*stringOut++ = *stringIn++) != '\0') { - if (--length == 0) { - stringOut--; - *stringOut = '\0'; - return (TRUE); - } - } - - return (FALSE); -} - - -static int -iscsiAuthClientStringIndex(const char *s, int c) -{ - int n = 0; - - while (*s != '\0') { - if (*s++ == c) { - return (n); - } - n++; - } - - return (-1); -} - - -static int -iscsiAuthClientCheckNodeType(int nodeType) -{ - if (nodeType == iscsiAuthNodeTypeInitiator || - nodeType == iscsiAuthNodeTypeTarget) { - return (FALSE); - } - - return (TRUE); -} - - -static int -iscsiAuthClientCheckVersion(int value) -{ - if (value == iscsiAuthVersionDraft8 || value == iscsiAuthVersionRfc) { - - return (FALSE); - } - - return (TRUE); -} - -static int -iscsiAuthClientCheckAuthMethodOption(int value) -{ - if (value == iscsiAuthOptionNone || value == iscsiAuthMethodChap) { - - return (FALSE); - } - - return (TRUE); -} - - -static const char * -iscsiAuthClientAuthMethodOptionToText(IscsiAuthClient * client, int value) -{ - const char *s; - - switch (value) { - case iscsiAuthOptionReject: - s = client->rejectOptionName; - break; - - case iscsiAuthOptionNone: - s = client->noneOptionName; - break; - - case iscsiAuthMethodChap: - s = iscsiAuthClientAuthMethodChapOptionName; - break; - - default: - s = 0; - } - - return (s); -} - - -static int -iscsiAuthClientCheckChapAlgorithmOption(int chapAlgorithm) -{ - if (chapAlgorithm == iscsiAuthOptionNone || - chapAlgorithm == iscsiAuthChapAlgorithmMd5) { - return (FALSE); - } - - return (TRUE); -} - - -static int -iscsiAuthClientDataToHex(unsigned char *data, unsigned int dataLength, - char *text, unsigned int textLength) -{ - unsigned long n; - - if (!text || textLength == 0) { - return (TRUE); - } - - if (!data || dataLength == 0) { - *text = '\0'; - return (TRUE); - } - - if (textLength < 3) { - *text = '\0'; - return (TRUE); - } - - *text++ = '0'; - *text++ = 'x'; - - textLength -= 2; - - while (dataLength > 0) { - - if (textLength < 3) { - *text = '\0'; - return (TRUE); - } - - n = *data++; - dataLength--; - - *text++ = iscsiAuthClientHexString[(n >> 4) & 0xf]; - *text++ = iscsiAuthClientHexString[n & 0xf]; - - textLength -= 2; - } - - *text = '\0'; - - return (FALSE); -} - - -static int -iscsiAuthClientDataToBase64(unsigned char *data, unsigned int dataLength, - char *text, unsigned int textLength) -{ - unsigned long n; - - if (!text || textLength == 0) { - return (TRUE); - } - - if (!data || dataLength == 0) { - *text = '\0'; - return (TRUE); - } - - if (textLength < 3) { - *text = '\0'; - return (TRUE); - } - - *text++ = '0'; - *text++ = 'b'; - - textLength -= 2; - - while (dataLength >= 3) { - - if (textLength < 5) { - *text = '\0'; - return (TRUE); - } - - n = *data++; - n = (n << 8) | *data++; - n = (n << 8) | *data++; - dataLength -= 3; - - *text++ = iscsiAuthClientBase64String[(n >> 18) & 0x3f]; - *text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f]; - *text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f]; - *text++ = iscsiAuthClientBase64String[n & 0x3f]; - - textLength -= 4; - } - - if (dataLength == 1) { - - if (textLength < 5) { - *text = '\0'; - return (TRUE); - } - - n = *data++; - n = n << 4; - - *text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f]; - *text++ = iscsiAuthClientBase64String[n & 0x3f]; - *text++ = '='; - *text++ = '='; - - } else if (dataLength == 2) { - - if (textLength < 5) { - return (TRUE); - } - - n = *data++; - n = (n << 8) | *data++; - n = n << 2; - - *text++ = iscsiAuthClientBase64String[(n >> 12) & 0x3f]; - *text++ = iscsiAuthClientBase64String[(n >> 6) & 0x3f]; - *text++ = iscsiAuthClientBase64String[n & 0x3f]; - *text++ = '='; - } - - *text = '\0'; - - return (FALSE); -} - - -static int -iscsiAuthClientDataToText(int base64, unsigned char *data, - unsigned int dataLength, char *text, unsigned int textLength) -{ - int status; - - if (base64) { - status = iscsiAuthClientDataToBase64( - data, dataLength, text, textLength); - } else { - status = iscsiAuthClientDataToHex( - data, dataLength, text, textLength); - } - - return (status); -} - - -static int -iscsiAuthClientHexToData(const char *text, unsigned int textLength, - unsigned char *data, unsigned int *pDataLength) -{ - int i; - unsigned int n1; - unsigned int n2; - unsigned int dataLength = *pDataLength; - - if ((textLength % 2) == 1) { - i = iscsiAuthClientStringIndex(iscsiAuthClientHexString, - *text++); - if (i < 0) { - return (TRUE); /* error, bad character */ - } - - if (i > 15) - i -= 6; - n2 = i; - - if (dataLength < 1) { - return (TRUE); /* error, too much data */ - } - - *data++ = n2; - dataLength--; - } - - while (*text != '\0') { - - i = iscsiAuthClientStringIndex( - iscsiAuthClientHexString, *text++); - if (i < 0) { - return (TRUE); /* error, bad character */ - } - - if (i > 15) - i -= 6; - n1 = i; - - if (*text == '\0') { - return (TRUE); /* error, odd string length */ - } - - i = iscsiAuthClientStringIndex( - iscsiAuthClientHexString, *text++); - if (i < 0) { - return (TRUE); /* error, bad character */ - } - - if (i > 15) - i -= 6; - n2 = i; - - if (dataLength < 1) { - return (TRUE); /* error, too much data */ - } - - *data++ = (n1 << 4) | n2; - dataLength--; - } - - if (dataLength >= *pDataLength) { - return (TRUE); /* error, no data */ - } - - *pDataLength = *pDataLength - dataLength; - - return (FALSE); /* no error */ -} - - -static int -iscsiAuthClientBase64ToData(const char *text, unsigned int textLength, - unsigned char *data, unsigned int *pDataLength) -{ - int i; - unsigned int n; - unsigned int count; - unsigned int dataLength = *pDataLength; - - textLength = textLength; /* not used */ - - n = 0; - count = 0; - - while (*text != '\0' && *text != '=') { - - i = iscsiAuthClientStringIndex( - iscsiAuthClientBase64String, *text++); - if (i < 0) { - return (TRUE); /* error, bad character */ - } - - n = (n << 6 | (unsigned int)i); - count++; - - if (count >= 4) { - if (dataLength < 3) { - return (TRUE); /* error, too much data */ - } - *data++ = n >> 16; - *data++ = n >> 8; - *data++ = n; - dataLength -= 3; - n = 0; - count = 0; - } - } - - while (*text != '\0') { - if (*text++ != '=') { - return (TRUE); /* error, bad pad */ - } - } - - if (count == 0) { - /* - * do nothing - */ - /* EMPTY */ - } else if (count == 2) { - if (dataLength < 1) { - return (TRUE); /* error, too much data */ - } - n = n >> 4; - *data++ = n; - dataLength--; - } else if (count == 3) { - if (dataLength < 2) { - return (TRUE); /* error, too much data */ - } - n = n >> 2; - *data++ = n >> 8; - *data++ = n; - dataLength -= 2; - } else { - return (TRUE); /* bad encoding */ - } - - if (dataLength >= *pDataLength) { - return (TRUE); /* error, no data */ - } - - *pDataLength = *pDataLength - dataLength; - - return (FALSE); /* no error */ -} - - -static int -iscsiAuthClientTextToData(const char *text, unsigned char *data, - unsigned int *dataLength) -{ - int status; - unsigned int textLength; - - status = iscsiAuthClientCheckString(text, - 2 + 2 * iscsiAuthLargeBinaryMaxLength + 1, &textLength); - - if (status) { - return (status); - } - - if (text[0] == '0' && (text[1] == 'x' || text[1] == 'X')) { - /* - * skip prefix - */ - text += 2; - textLength -= 2; - status = iscsiAuthClientHexToData(text, - textLength, data, dataLength); - } else if (text[0] == '0' && (text[1] == 'b' || text[1] == 'B')) { - /* - * skip prefix - */ - text += 2; - textLength -= 2; - status = iscsiAuthClientBase64ToData(text, - textLength, data, dataLength); - } else { - status = TRUE; /* prefix not recognized. */ - } - - return (status); -} - - -static IscsiAuthDebugStatus -iscsiAuthClientChapComputeResponse(IscsiAuthClient * client, - int remoteAuthentication, unsigned int id, - unsigned char *challengeData, unsigned int challengeLength, - unsigned char *responseData) -{ - unsigned char idData[1]; - IscsiAuthMd5Context context; - unsigned char outData[iscsiAuthStringMaxLength]; - unsigned int outLength = iscsiAuthStringMaxLength; - - if (!client->passwordPresent) { - return (iscsiAuthDebugStatusLocalPasswordNotSet); - } - - iscsiAuthMd5Init(&context); - - /* - * id byte - */ - idData[0] = id; - iscsiAuthMd5Update(&context, idData, 1); - - /* - * decrypt password - */ - if (iscsiAuthClientData(outData, &outLength, - client->passwordData, client->passwordLength)) { - - return (iscsiAuthDebugStatusPasswordDecryptFailed); - } - - if (!remoteAuthentication && !client->ipSec && outLength < 12) { - return (iscsiAuthDebugStatusPasswordTooShortWithNoIpSec); - } - - /* - * shared secret - */ - iscsiAuthMd5Update(&context, outData, outLength); - - /* - * clear decrypted password - */ - bzero(outData, iscsiAuthStringMaxLength); - - /* - * challenge value - */ - iscsiAuthMd5Update(&context, challengeData, challengeLength); - - iscsiAuthMd5Final(responseData, &context); - - return (iscsiAuthDebugStatusNotSet); /* no error */ -} - - -static void -iscsiAuthClientInitKeyBlock(IscsiAuthKeyBlock * keyBlock) -{ - char *stringBlock = keyBlock->stringBlock; - - bzero(keyBlock, sizeof (*keyBlock)); - keyBlock->stringBlock = stringBlock; -} - - -static void -iscsiAuthClientSetKeyValue(IscsiAuthKeyBlock * keyBlock, - int keyType, const char *keyValue) -{ - unsigned int length; - char *string; - - if (keyBlock->key[keyType].valueSet) { - keyBlock->duplicateSet = TRUE; - return; - } - - keyBlock->key[keyType].valueSet = TRUE; - - if (!keyValue) { - return; - } - - if (iscsiAuthClientCheckString(keyValue, - iscsiAuthStringMaxLength, &length)) { - keyBlock->stringTooLong = TRUE; - return; - } - - length += 1; - - if ((keyBlock->blockLength + length) > iscsiAuthStringBlockMaxLength) { - keyBlock->tooMuchData = TRUE; - return; - } - - string = &keyBlock->stringBlock[keyBlock->blockLength]; - - if (iscsiAuthClientStringCopy(string, keyValue, length)) { - keyBlock->tooMuchData = TRUE; - return; - } - keyBlock->blockLength += length; - - keyBlock->key[keyType].string = string; - keyBlock->key[keyType].present = TRUE; -} - - -static const char * -iscsiAuthClientGetKeyValue(IscsiAuthKeyBlock * keyBlock, int keyType) -{ - keyBlock->key[keyType].processed = TRUE; - - if (!keyBlock->key[keyType].present) { - return (0); - } - - return (keyBlock->key[keyType].string); -} - - -static void -iscsiAuthClientCheckKey(IscsiAuthClient * client, - int keyType, - int *negotiatedOption, - unsigned int optionCount, - int *optionList, const char *(*valueToText) (IscsiAuthClient *, int)) -{ - const char *keyValue; - int length; - unsigned int i; - - keyValue = iscsiAuthClientGetKeyValue(&client->recvKeyBlock, keyType); - if (!keyValue) { - *negotiatedOption = iscsiAuthOptionNotPresent; - return; - } - - while (*keyValue != '\0') { - - length = 0; - - while (*keyValue != '\0' && *keyValue != ',') { - client->scratchKeyValue[length++] = *keyValue++; - } - - if (*keyValue == ',') - keyValue++; - client->scratchKeyValue[length++] = '\0'; - - for (i = 0; i < optionCount; i++) { - const char *s = (*valueToText) (client, optionList[i]); - - if (!s) - continue; - - if (strcmp(client->scratchKeyValue, s) == 0) { - *negotiatedOption = optionList[i]; - return; - } - } - } - - *negotiatedOption = iscsiAuthOptionReject; -} - - -static void -iscsiAuthClientSetKey(IscsiAuthClient * client, - int keyType, - unsigned int optionCount, - int *optionList, const char *(*valueToText) (IscsiAuthClient *, int)) -{ - unsigned int i; - - if (optionCount == 0) { - /* - * No valid options to send, but we always want to - * send something. - */ - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, keyType, - client->noneOptionName); - return; - } - - if (optionCount == 1 && optionList[0] == iscsiAuthOptionNotPresent) { - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, keyType, 0); - return; - } - - for (i = 0; i < optionCount; i++) { - const char *s = (*valueToText) (client, optionList[i]); - - if (!s) - continue; - - if (i == 0) { - (void) iscsiAuthClientStringCopy(client->scratchKeyValue, - s, iscsiAuthStringMaxLength); - } else { - (void) iscsiAuthClientStringAppend(client->scratchKeyValue, - ",", iscsiAuthStringMaxLength); - (void) iscsiAuthClientStringAppend(client->scratchKeyValue, - s, iscsiAuthStringMaxLength); - } - } - - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - keyType, client->scratchKeyValue); -} - - -static void -iscsiAuthClientCheckAuthMethodKey(IscsiAuthClient * client) -{ - iscsiAuthClientCheckKey(client, - iscsiAuthKeyTypeAuthMethod, - &client->negotiatedAuthMethod, - client->authMethodValidCount, - client->authMethodValidList, iscsiAuthClientAuthMethodOptionToText); -} - - -static void -iscsiAuthClientSetAuthMethodKey(IscsiAuthClient * client, - unsigned int authMethodCount, int *authMethodList) -{ - iscsiAuthClientSetKey(client, iscsiAuthKeyTypeAuthMethod, - authMethodCount, authMethodList, - iscsiAuthClientAuthMethodOptionToText); -} - - -static void -iscsiAuthClientCheckChapAlgorithmKey(IscsiAuthClient * client) -{ - const char *keyValue; - int length; - unsigned long number; - unsigned int i; - - keyValue = iscsiAuthClientGetKeyValue(&client->recvKeyBlock, - iscsiAuthKeyTypeChapAlgorithm); - if (!keyValue) { - client->negotiatedChapAlgorithm = iscsiAuthOptionNotPresent; - return; - } - - while (*keyValue != '\0') { - length = 0; - - while (*keyValue != '\0' && *keyValue != ',') { - client->scratchKeyValue[length++] = *keyValue++; - } - - if (*keyValue == ',') - keyValue++; - client->scratchKeyValue[length++] = '\0'; - - if (iscsiAuthClientTextToNumber(client->scratchKeyValue, - &number)) { - continue; - } - - for (i = 0; i < client->chapAlgorithmCount; i++) { - - if (number == (unsigned long)client-> - chapAlgorithmList[i]) { - client->negotiatedChapAlgorithm = number; - return; - } - } - } - - client->negotiatedChapAlgorithm = iscsiAuthOptionReject; -} - - -static void -iscsiAuthClientSetChapAlgorithmKey(IscsiAuthClient * client, - unsigned int chapAlgorithmCount, int *chapAlgorithmList) -{ - unsigned int i; - - if (chapAlgorithmCount == 0) { - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapAlgorithm, 0); - return; - } - - if (chapAlgorithmCount == 1 && - chapAlgorithmList[0] == iscsiAuthOptionNotPresent) { - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapAlgorithm, 0); - return; - } - - if (chapAlgorithmCount == 1 && - chapAlgorithmList[0] == iscsiAuthOptionReject) { - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapAlgorithm, client->rejectOptionName); - return; - } - - for (i = 0; i < chapAlgorithmCount; i++) { - char s[20]; - - iscsiAuthClientNumberToText(chapAlgorithmList[i], - s, sizeof (s)); - - if (i == 0) { - (void) iscsiAuthClientStringCopy(client->scratchKeyValue, s, - iscsiAuthStringMaxLength); - } else { - (void) iscsiAuthClientStringAppend(client->scratchKeyValue, - ",", iscsiAuthStringMaxLength); - (void) iscsiAuthClientStringAppend(client->scratchKeyValue, - s, iscsiAuthStringMaxLength); - } - } - - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapAlgorithm, client->scratchKeyValue); -} - - -static void -iscsiAuthClientNextPhase(IscsiAuthClient * client) -{ - switch (client->phase) { - case iscsiAuthPhaseConfigure: - client->phase = iscsiAuthPhaseNegotiate; - break; - - case iscsiAuthPhaseNegotiate: - client->phase = iscsiAuthPhaseAuthenticate; - - if (client->negotiatedAuthMethod == - iscsiAuthOptionReject || - client->negotiatedAuthMethod == - iscsiAuthOptionNotPresent || - client->negotiatedAuthMethod == iscsiAuthOptionNone) { - - client->localState = iscsiAuthLocalStateDone; - client->remoteState = iscsiAuthRemoteStateDone; - - if (client->authRemote) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - } else { - client->remoteAuthStatus = iscsiAuthStatusPass; - } - - switch (client->negotiatedAuthMethod) { - case iscsiAuthOptionReject: - client->debugStatus = - iscsiAuthDebugStatusAuthMethodReject; - break; - - case iscsiAuthOptionNotPresent: - client->debugStatus = - iscsiAuthDebugStatusAuthMethodNotPresent; - break; - - case iscsiAuthOptionNone: - client->debugStatus = - iscsiAuthDebugStatusAuthMethodNone; - } - - } else if (client->negotiatedAuthMethod == - iscsiAuthMethodChap) { - client->localState = iscsiAuthLocalStateSendAlgorithm; - client->remoteState = iscsiAuthRemoteStateSendAlgorithm; - } else { - client->localState = iscsiAuthLocalStateDone; - client->remoteState = iscsiAuthRemoteStateDone; - client->remoteAuthStatus = iscsiAuthStatusFail; - client->debugStatus = iscsiAuthDebugStatusAuthMethodBad; - } - - break; - - case iscsiAuthPhaseAuthenticate: - client->phase = iscsiAuthPhaseDone; - break; - - case iscsiAuthPhaseDone: - case iscsiAuthPhaseError: - default: - client->phase = iscsiAuthPhaseError; - } -} - - -static void -iscsiAuthClientLocalAuthentication(IscsiAuthClient * client) -{ - unsigned int chapIdentifier; - unsigned char responseData[iscsiAuthChapResponseLength]; - unsigned long number; - int status; - IscsiAuthDebugStatus debugStatus; - const char *chapIdentifierKeyValue; - const char *chapChallengeKeyValue; - - switch (client->localState) { - case iscsiAuthLocalStateSendAlgorithm: - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - iscsiAuthClientSetChapAlgorithmKey( - client, client->chapAlgorithmCount, - client->chapAlgorithmList); - client->localState = iscsiAuthLocalStateRecvAlgorithm; - break; - } - - /* FALLTHRU */ - - case iscsiAuthLocalStateRecvAlgorithm: - iscsiAuthClientCheckChapAlgorithmKey(client); - - if (client->nodeType == iscsiAuthNodeTypeTarget) { - - iscsiAuthClientSetChapAlgorithmKey(client, 1, - &client->negotiatedChapAlgorithm); - } - - /* - * Make sure only supported CHAP algorithm is used. - */ - if (client->negotiatedChapAlgorithm == - iscsiAuthOptionNotPresent) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapAlgorithmExpected; - break; - - } else if (client->negotiatedChapAlgorithm == - iscsiAuthOptionReject) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapAlgorithmReject; - break; - - } else if (client->negotiatedChapAlgorithm != - iscsiAuthChapAlgorithmMd5) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapAlgorithmBad; - break; - } - - if (client->nodeType == iscsiAuthNodeTypeTarget) { - - client->localState = iscsiAuthLocalStateRecvChallenge; - break; - } - - /* FALLTHRU */ - - case iscsiAuthLocalStateRecvChallenge: - chapIdentifierKeyValue = iscsiAuthClientGetKeyValue( - &client->recvKeyBlock, iscsiAuthKeyTypeChapIdentifier); - chapChallengeKeyValue = iscsiAuthClientGetKeyValue( - &client->recvKeyBlock, iscsiAuthKeyTypeChapChallenge); - - if (client->nodeType == iscsiAuthNodeTypeTarget) { - if (!chapIdentifierKeyValue && !chapChallengeKeyValue) { - client->localState = iscsiAuthLocalStateDone; - break; - } - } - - if (!chapIdentifierKeyValue) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapIdentifierExpected; - break; - } - - if (!chapChallengeKeyValue) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapChallengeExpected; - break; - } - - status = iscsiAuthClientTextToNumber( - chapIdentifierKeyValue, &number); - - if (status || (255 < number)) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapIdentifierBad; - break; - } - chapIdentifier = number; - - if (client->recvChapChallengeStatus) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapChallengeBad; - break; - } - - if (client->nodeType == iscsiAuthNodeTypeTarget && - client->recvChapChallenge.length == - client->sendChapChallenge.length && - bcmp(client->recvChapChallenge.largeBinary, - client->sendChapChallenge.largeBinary, - client->sendChapChallenge.length) == 0) { - - client->localState = iscsiAuthLocalStateError; - client->debugStatus = - iscsiAuthDebugStatusChapChallengeReflected; - break; - } - - debugStatus = iscsiAuthClientChapComputeResponse(client, - FALSE, - chapIdentifier, - client->recvChapChallenge.largeBinary, - client->recvChapChallenge.length, responseData); - - if (debugStatus != iscsiAuthDebugStatusNotSet) { - client->localState = iscsiAuthLocalStateError; - client->debugStatus = debugStatus; - break; - } - - (void) iscsiAuthClientDataToText(client->base64, - responseData, iscsiAuthChapResponseLength, - client->scratchKeyValue, iscsiAuthStringMaxLength); - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapResponse, client->scratchKeyValue); - - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapUsername, client->username); - - client->localState = iscsiAuthLocalStateDone; - break; - - case iscsiAuthLocalStateDone: - break; - - case iscsiAuthLocalStateError: - default: - client->phase = iscsiAuthPhaseError; - } -} - - -static void -iscsiAuthClientRemoteAuthentication(IscsiAuthClient * client) -{ - unsigned char idData[1]; - unsigned char responseData[iscsiAuthStringMaxLength]; - unsigned int responseLength = iscsiAuthStringMaxLength; - unsigned char myResponseData[iscsiAuthChapResponseLength]; - int status; - IscsiAuthDebugStatus debugStatus; - const char *chapResponseKeyValue; - const char *chapUsernameKeyValue; - - switch (client->remoteState) { - case iscsiAuthRemoteStateSendAlgorithm: - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - client->remoteState = iscsiAuthRemoteStateSendChallenge; - break; - } - - /* FALLTHRU */ - - case iscsiAuthRemoteStateSendChallenge: - if (!client->authRemote) { - client->remoteAuthStatus = iscsiAuthStatusPass; - client->debugStatus = - iscsiAuthDebugStatusAuthRemoteFalse; - client->remoteState = iscsiAuthRemoteStateDone; - break; - } - - iscsiAuthRandomSetData(idData, 1); - client->sendChapIdentifier = idData[0]; - - iscsiAuthClientNumberToText(client->sendChapIdentifier, - client->scratchKeyValue, iscsiAuthStringMaxLength); - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapIdentifier, client->scratchKeyValue); - - client->sendChapChallenge.length = client->chapChallengeLength; - iscsiAuthRandomSetData(client->sendChapChallenge.largeBinary, - client->sendChapChallenge.length); - - iscsiAuthClientSetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeChapChallenge, ""); - - client->remoteState = iscsiAuthRemoteStateRecvResponse; - break; - - case iscsiAuthRemoteStateRecvResponse: - chapResponseKeyValue = iscsiAuthClientGetKeyValue( - &client->recvKeyBlock, iscsiAuthKeyTypeChapResponse); - - chapUsernameKeyValue = iscsiAuthClientGetKeyValue( - &client->recvKeyBlock, iscsiAuthKeyTypeChapUsername); - - if (!chapResponseKeyValue) { - client->remoteState = iscsiAuthRemoteStateError; - client->debugStatus = - iscsiAuthDebugStatusChapResponseExpected; - break; - } - - if (!chapUsernameKeyValue) { - client->remoteState = iscsiAuthRemoteStateError; - client->debugStatus = - iscsiAuthDebugStatusChapUsernameExpected; - break; - } - - status = iscsiAuthClientTextToData(chapResponseKeyValue, - responseData, &responseLength); - - if (status) { - client->remoteState = iscsiAuthRemoteStateError; - client->debugStatus = - iscsiAuthDebugStatusChapResponseBad; - break; - } - - if (responseLength == iscsiAuthChapResponseLength) { - debugStatus = iscsiAuthClientChapComputeResponse( - client, TRUE, client->sendChapIdentifier, - client->sendChapChallenge.largeBinary, - client->sendChapChallenge.length, myResponseData); - - /* - * Check if the same CHAP secret is being used for - * authentication in both directions. - */ - if (debugStatus == iscsiAuthDebugStatusNotSet && - bcmp(myResponseData, responseData, - iscsiAuthChapResponseLength) == 0) { - - client->remoteState = - iscsiAuthRemoteStateError; - client->debugStatus = - iscsiAuthDebugStatusPasswordIdentical; - break; - } - } - - (void) iscsiAuthClientStringCopy(client->chapUsername, - chapUsernameKeyValue, iscsiAuthStringMaxLength); - - /* To verify the target's response. */ - status = iscsiAuthClientChapAuthRequest( - client, client->chapUsername, client->sendChapIdentifier, - client->sendChapChallenge.largeBinary, - client->sendChapChallenge.length, responseData, - responseLength); - - if (status == iscsiAuthStatusInProgress) { - iscsiAuthClientGlobalStats.requestSent++; - client->remoteState = iscsiAuthRemoteStateAuthRequest; - break; - } - - client->remoteAuthStatus = (IscsiAuthStatus) status; - client->authResponseFlag = TRUE; - - /* FALLTHRU */ - - case iscsiAuthRemoteStateAuthRequest: - /* - * client->remoteAuthStatus already set - */ - if (client->authServerErrorFlag) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->debugStatus = - iscsiAuthDebugStatusAuthServerError; - } else if (client->remoteAuthStatus == iscsiAuthStatusPass) { - client->debugStatus = iscsiAuthDebugStatusAuthPass; - } else if (client->remoteAuthStatus == iscsiAuthStatusFail) { - client->debugStatus = iscsiAuthDebugStatusAuthFail; - } else { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->debugStatus = iscsiAuthDebugStatusAuthStatusBad; - } - client->remoteState = iscsiAuthRemoteStateDone; - - /* FALLTHRU */ - - case iscsiAuthRemoteStateDone: - break; - - case iscsiAuthRemoteStateError: - default: - client->phase = iscsiAuthPhaseError; - } -} - - -static void -iscsiAuthClientHandshake(IscsiAuthClient * client) -{ - if (client->phase == iscsiAuthPhaseDone) { - /* - * Should only happen if authentication - * protocol error occured. - */ - return; - } - - if (client->remoteState == iscsiAuthRemoteStateAuthRequest) { - /* - * Defer until authentication response received - * from internal authentication service. - */ - return; - } - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - - /* - * Target should only have set T bit on response if - * initiator set it on previous message. - */ - if (client->recvKeyBlock.transitBit && - client->transitBitSentFlag == 0) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusTbitSetIllegal; - return; - } - } - - if (client->phase == iscsiAuthPhaseNegotiate) { - /* - * Should only happen if waiting for peer - * to send AuthMethod key or set Transit Bit. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - client->sendKeyBlock.transitBit = TRUE; - } - return; - } - - if (client->remoteState == iscsiAuthRemoteStateRecvResponse || - client->remoteState == iscsiAuthRemoteStateDone) { - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - if (client->recvKeyBlock.transitBit) { - if (client->remoteState != - iscsiAuthRemoteStateDone) { - goto recvTransitBitError; - } - iscsiAuthClientNextPhase(client); - } else { - client->sendKeyBlock.transitBit = TRUE; - } - } else { - if (client->remoteState == iscsiAuthRemoteStateDone && - client->remoteAuthStatus != iscsiAuthStatusPass) { - - /* - * Authentication failed, don't - * do T bit handshake. - */ - iscsiAuthClientNextPhase(client); - } else { - - /* - * Target can only set T bit on response if - * initiator set it on current message. - */ - if (client->recvKeyBlock.transitBit) { - client->sendKeyBlock.transitBit = TRUE; - iscsiAuthClientNextPhase(client); - } - } - } - } else { - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - if (client->recvKeyBlock.transitBit) { - goto recvTransitBitError; - } - } - } - - return; - -recvTransitBitError: - /* - * Target set T bit on response but - * initiator was not done with authentication. - */ - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = iscsiAuthDebugStatusTbitSetPremature; -} - - -static int -iscsiAuthClientRecvEndStatus(IscsiAuthClient * client) -{ - int authStatus; - int keyType; - - if (client->phase == iscsiAuthPhaseError) { - return (iscsiAuthStatusError); - } - - if (client->phase == iscsiAuthPhaseDone) { - - /* - * Perform sanity check against configured parameters. - */ - - if (client->authRemote && !client->authResponseFlag && - client->remoteAuthStatus == iscsiAuthStatusPass) { - - client->remoteAuthStatus = iscsiAuthStatusFail; - client->debugStatus = - iscsiAuthDebugStatusAuthPassNotValid; - } - - authStatus = client->remoteAuthStatus; - } else if (client->remoteState == iscsiAuthRemoteStateAuthRequest) { - authStatus = iscsiAuthStatusInProgress; - } else { - authStatus = iscsiAuthStatusContinue; - } - - if (authStatus != iscsiAuthStatusInProgress) { - client->recvInProgressFlag = FALSE; - } - - if (authStatus == iscsiAuthStatusContinue || - authStatus == iscsiAuthStatusPass) { - if (client->sendKeyBlock.duplicateSet) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusSendDuplicateSetKeyValue; - authStatus = iscsiAuthStatusFail; - } else if (client->sendKeyBlock.stringTooLong) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusSendStringTooLong; - authStatus = iscsiAuthStatusFail; - } else if (client->sendKeyBlock.tooMuchData) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusSendTooMuchData; - authStatus = iscsiAuthStatusFail; - } else { - /* - * Check that all incoming keys have been processed. - */ - for (keyType = iscsiAuthKeyTypeFirst; - keyType < iscsiAuthKeyTypeMaxCount; keyType++) { - if (client->recvKeyBlock.key[keyType].present && - client->recvKeyBlock.key[keyType]. - processed == 0) { - break; - } - } - - if (keyType < iscsiAuthKeyTypeMaxCount) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusUnexpectedKeyPresent; - authStatus = iscsiAuthStatusFail; - } - } - } - - if (authStatus != iscsiAuthStatusPass && - authStatus != iscsiAuthStatusContinue && - authStatus != iscsiAuthStatusInProgress) { - int authMethodKeyPresent = FALSE; - int chapAlgorithmKeyPresent = FALSE; - - /* - * Suppress send keys on error, except - * for AuthMethod and CHAP_A. - */ - if (client->nodeType == iscsiAuthNodeTypeTarget) { - if (iscsiAuthClientGetKeyValue(&client->sendKeyBlock, - iscsiAuthKeyTypeAuthMethod)) { - authMethodKeyPresent = TRUE; - } else if (iscsiAuthClientGetKeyValue( - &client->sendKeyBlock, - iscsiAuthKeyTypeChapAlgorithm)) { - chapAlgorithmKeyPresent = TRUE; - } - } - - iscsiAuthClientInitKeyBlock(&client->sendKeyBlock); - - if (client->nodeType == iscsiAuthNodeTypeTarget) { - if (authMethodKeyPresent && - client->negotiatedAuthMethod == - iscsiAuthOptionReject) { - iscsiAuthClientSetKeyValue( - &client->sendKeyBlock, - iscsiAuthKeyTypeAuthMethod, - client->rejectOptionName); - } else if (chapAlgorithmKeyPresent && - client->negotiatedChapAlgorithm == - iscsiAuthOptionReject) { - iscsiAuthClientSetKeyValue( - &client->sendKeyBlock, - iscsiAuthKeyTypeChapAlgorithm, - client->rejectOptionName); - } - } - } - - return (authStatus); -} - - -int -iscsiAuthClientRecvBegin(IscsiAuthClient * client) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase == iscsiAuthPhaseError) { - return (iscsiAuthStatusError); - } - - if (client->phase == iscsiAuthPhaseDone) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (client->recvInProgressFlag) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->recvInProgressFlag = TRUE; - - if (client->phase == iscsiAuthPhaseConfigure) { - iscsiAuthClientNextPhase(client); - } - - client->transitBitSentFlag = client->sendKeyBlock.transitBit; - - iscsiAuthClientInitKeyBlock(&client->recvKeyBlock); - iscsiAuthClientInitKeyBlock(&client->sendKeyBlock); - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientRecvEnd(IscsiAuthClient * client, - IscsiAuthClientCallback * callback, void *userHandle, void *messageHandle) -{ - int nextPhaseFlag = FALSE; - - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase == iscsiAuthPhaseError) { - return (iscsiAuthStatusError); - } - - if (!callback || !client->recvInProgressFlag) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (client->recvEndCount > iscsiAuthRecvEndMaxCount) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusRecvMessageCountLimit; - } else if (client->recvKeyBlock.duplicateSet) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusRecvDuplicateSetKeyValue; - } else if (client->recvKeyBlock.stringTooLong) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = iscsiAuthDebugStatusRecvStringTooLong; - } else if (client->recvKeyBlock.tooMuchData) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = iscsiAuthDebugStatusRecvTooMuchData; - } - - client->recvEndCount++; - - client->callback = callback; - client->userHandle = userHandle; - client->messageHandle = messageHandle; - - switch (client->phase) { - case iscsiAuthPhaseNegotiate: - iscsiAuthClientCheckAuthMethodKey(client); - - if (client->authMethodValidNegRole == - iscsiAuthNegRoleResponder) { - if (client->negotiatedAuthMethod == - iscsiAuthOptionNotPresent) { - if (client->authRemote || - client->recvKeyBlock.transitBit == 0) { - /* - * No AuthMethod key from peer - * on first message, try moving - * the process along by sending - * the AuthMethod key. - */ - - client->authMethodValidNegRole = - iscsiAuthNegRoleOriginator; - - iscsiAuthClientSetAuthMethodKey(client, - client->authMethodValidCount, - client->authMethodValidList); - break; - } - - /* - * Special case if peer sent no - * AuthMethod key, but did set Transit - * Bit, allowing this side to do a - * null authentication, and compelete - * the iSCSI security phase without - * either side sending the AuthMethod - * key. - */ - } else { - /* - * Send response to AuthMethod key. - */ - - iscsiAuthClientSetAuthMethodKey(client, 1, - &client->negotiatedAuthMethod); - } - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - iscsiAuthClientNextPhase(client); - } else { - nextPhaseFlag = TRUE; - } - - } else { - if (client->negotiatedAuthMethod == - iscsiAuthOptionNotPresent) { - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - client->debugStatus = - iscsiAuthDebugStatusAuthMethodExpected; - break; - } - - iscsiAuthClientNextPhase(client); - } - break; - - case iscsiAuthPhaseAuthenticate: - case iscsiAuthPhaseDone: - break; - - default: - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - switch (client->phase) { - case iscsiAuthPhaseNegotiate: - if (nextPhaseFlag) { - iscsiAuthClientNextPhase(client); - } - break; - - case iscsiAuthPhaseAuthenticate: - /* - * Must call iscsiAuthClientLocalAuthentication() - * before iscsiAuthClientRemoteAuthentication() - * to insure processing of the CHAP algorithm key, - * and to avoid leaving an in progress request to the - * authentication service. - */ - iscsiAuthClientLocalAuthentication(client); - - if (client->localState != iscsiAuthLocalStateError) { - iscsiAuthClientRemoteAuthentication(client); - } - - if (client->localState == iscsiAuthLocalStateError || - client->remoteState == iscsiAuthRemoteStateError) { - - client->remoteAuthStatus = iscsiAuthStatusFail; - client->phase = iscsiAuthPhaseDone; - /* - * client->debugStatus should already be set. - */ - } - break; - - case iscsiAuthPhaseDone: - break; - - default: - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - iscsiAuthClientHandshake(client); - - return (iscsiAuthClientRecvEndStatus(client)); -} - - -#ifdef notused -void -iscsiAuthClientAuthResponse(IscsiAuthClient * client, int authStatus) -{ - iscsiAuthClientGlobalStats.responseReceived++; - - if (!client || client->signature != iscsiAuthClientSignature) { - return; - } - - if (!client->recvInProgressFlag || - client->phase != iscsiAuthPhaseAuthenticate || - client->remoteState != iscsiAuthRemoteStateAuthRequest) { - - client->phase = iscsiAuthPhaseError; - return; - } - - client->remoteAuthStatus = (IscsiAuthStatus) authStatus; - client->authResponseFlag = TRUE; - - iscsiAuthClientRemoteAuthentication(client); - - iscsiAuthClientHandshake(client); - - authStatus = iscsiAuthClientRecvEndStatus(client); - - client->callback(client->userHandle, client->messageHandle, authStatus); -} -#endif - - -const char * -iscsiAuthClientGetKeyName(int keyType) -{ - if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) { - return (0); - } - return (iscsiAuthClientKeyInfo[keyType].name); -} - - -int -iscsiAuthClientGetNextKeyType(int *pKeyType) -{ - int keyType = *pKeyType; - - if (keyType >= iscsiAuthKeyTypeLast) { - return (iscsiAuthStatusError); - } - - if (keyType < iscsiAuthKeyTypeFirst) { - keyType = iscsiAuthKeyTypeFirst; - } else { - keyType++; - } - - *pKeyType = keyType; - - return (iscsiAuthStatusNoError); -} - - -#ifdef notused -int -iscsiAuthClientKeyNameToKeyType(const char *keyName) -{ - int keyType = iscsiAuthKeyTypeNone; - - while (iscsiAuthClientGetNextKeyType(&keyType) == - iscsiAuthStatusNoError) { - const char *keyName2 = iscsiAuthClientGetKeyName(keyType); - - if (!keyName2) { - return (iscsiAuthKeyTypeNone); - } - - if (strcmp(keyName, keyName2) == 0) { - return (keyType); - } - } - - return (iscsiAuthKeyTypeNone); -} -#endif - - -int -iscsiAuthClientRecvKeyValue(IscsiAuthClient * client, int keyType, - const char *userKeyValue) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseNegotiate && - client->phase != iscsiAuthPhaseAuthenticate) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (keyType == iscsiAuthKeyTypeChapChallenge) { - client->recvChapChallenge.length = - iscsiAuthLargeBinaryMaxLength; - client->recvChapChallengeStatus = - iscsiAuthClientTextToData(userKeyValue, - client->recvChapChallenge.largeBinary, - &client->recvChapChallenge.length); - userKeyValue = ""; - } - - iscsiAuthClientSetKeyValue(&client->recvKeyBlock, - keyType, userKeyValue); - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientSendKeyValue(IscsiAuthClient * client, int keyType, - int *keyPresent, char *userKeyValue, unsigned int maxLength) -{ - const char *keyValue; - - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure && - client->phase != iscsiAuthPhaseNegotiate && - client->phase != iscsiAuthPhaseAuthenticate && - client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (keyType < iscsiAuthKeyTypeFirst || keyType > iscsiAuthKeyTypeLast) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - keyValue = iscsiAuthClientGetKeyValue(&client->sendKeyBlock, keyType); - if (keyValue) { - if (keyType == iscsiAuthKeyTypeChapChallenge) { - if (iscsiAuthClientDataToText(client->base64, - client->sendChapChallenge.largeBinary, - client->sendChapChallenge.length, - userKeyValue, maxLength)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - } else { - if (iscsiAuthClientStringCopy(userKeyValue, - keyValue, maxLength)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - } - *keyPresent = TRUE; - } else { - *keyPresent = FALSE; - } - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientRecvTransitBit(IscsiAuthClient * client, int value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseNegotiate && - client->phase != iscsiAuthPhaseAuthenticate) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (value) { - client->recvKeyBlock.transitBit = TRUE; - } else { - client->recvKeyBlock.transitBit = FALSE; - } - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientSendTransitBit(IscsiAuthClient * client, int *value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure && - client->phase != iscsiAuthPhaseNegotiate && - client->phase != iscsiAuthPhaseAuthenticate && - client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - *value = client->sendKeyBlock.transitBit; - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientInit(int nodeType, int bufferDescCount, - IscsiAuthBufferDesc * bufferDesc) -{ - IscsiAuthClient *client; - IscsiAuthStringBlock *recvStringBlock; - IscsiAuthStringBlock *sendStringBlock; - IscsiAuthLargeBinary *recvChapChallenge; - IscsiAuthLargeBinary *sendChapChallenge; - int valueList[2]; - - if (bufferDescCount != 5 || - bufferDesc == 0) { - return (iscsiAuthStatusError); - } - - if (!bufferDesc[0].address || - bufferDesc[0].length != sizeof (*client)) { - return (iscsiAuthStatusError); - } - client = (IscsiAuthClient *) bufferDesc[0].address; - - if (bufferDesc[1].address == 0 || - bufferDesc[1].length != sizeof (*recvStringBlock)) { - return (iscsiAuthStatusError); - } - recvStringBlock = (IscsiAuthStringBlock *) bufferDesc[1].address; - - if (bufferDesc[2].address == 0 || - bufferDesc[2].length != sizeof (*sendStringBlock)) { - return (iscsiAuthStatusError); - } - sendStringBlock = (IscsiAuthStringBlock *) bufferDesc[2].address; - - if (bufferDesc[3].address == 0 || - bufferDesc[3].length != sizeof (*recvChapChallenge)) { - return (iscsiAuthStatusError); - } - recvChapChallenge = (IscsiAuthLargeBinary *) bufferDesc[3].address; - - if (bufferDesc[4].address == 0 || - bufferDesc[4].length != sizeof (*sendChapChallenge)) { - return (iscsiAuthStatusError); - } - sendChapChallenge = (IscsiAuthLargeBinary *) bufferDesc[4].address; - - bzero(client, sizeof (*client)); - bzero(recvStringBlock, sizeof (*recvStringBlock)); - bzero(sendStringBlock, sizeof (*sendStringBlock)); - bzero(recvChapChallenge, sizeof (*recvChapChallenge)); - bzero(sendChapChallenge, sizeof (*sendChapChallenge)); - - client->recvKeyBlock.stringBlock = recvStringBlock->stringBlock; - client->sendKeyBlock.stringBlock = sendStringBlock->stringBlock; - client->recvChapChallenge.largeBinary = recvChapChallenge->largeBinary; - client->sendChapChallenge.largeBinary = sendChapChallenge->largeBinary; - - if (iscsiAuthClientCheckNodeType(nodeType)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->signature = iscsiAuthClientSignature; - client->nodeType = (IscsiAuthNodeType) nodeType; - /* Assume bi-directional authentication enabled. */ - client->authRemote = TRUE; - client->passwordPresent = FALSE; - client->version = iscsiAuthVersionRfc; - client->chapChallengeLength = iscsiAuthChapResponseLength; - client->ipSec = TRUE; - client->base64 = FALSE; - - client->phase = iscsiAuthPhaseConfigure; - client->negotiatedAuthMethod = iscsiAuthOptionNotPresent; - client->negotiatedChapAlgorithm = iscsiAuthOptionNotPresent; - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - client->authMethodNegRole = iscsiAuthNegRoleOriginator; - } else { - /* - * Initial value ignored for Target. - */ - client->authMethodNegRole = iscsiAuthNegRoleResponder; - } - - /* All supported authentication methods */ - valueList[0] = iscsiAuthMethodChap; - valueList[1] = iscsiAuthOptionNone; - - /* - * Must call after setting authRemote, password, - * version and authMethodNegRole - */ - if (iscsiAuthClientSetAuthMethodList(client, 2, valueList) != - iscsiAuthStatusNoError) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - valueList[0] = iscsiAuthChapAlgorithmMd5; - - if (iscsiAuthClientSetChapAlgorithmList(client, 1, valueList) != - iscsiAuthStatusNoError) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - return (iscsiAuthStatusNoError); -} - - -#ifdef notused -int -iscsiAuthClientFinish(IscsiAuthClient * client) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - iscsiAuthClientChapAuthCancel(client); - - bzero(client, sizeof (*client)); - - return (iscsiAuthStatusNoError); -} -#endif - - -static int -iscsiAuthClientSetOptionList(IscsiAuthClient * client, - unsigned int optionCount, - const int *optionList, - unsigned int *clientOptionCount, - int *clientOptionList, - unsigned int optionMaxCount, - int (*checkOption) (int), - int (*checkList) (unsigned int optionCount, const int *optionList)) -{ - unsigned int i; - unsigned int j; - - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - optionCount > optionMaxCount) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - for (i = 0; i < optionCount; i++) { - if ((*checkOption) (optionList[i])) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - } - - /* - * Check for duplicate entries. - */ - for (i = 0; i < optionCount; i++) { - for (j = 0; j < optionCount; j++) { - if (j == i) - continue; - if (optionList[i] == optionList[j]) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - } - } - - /* - * Check for key specific constraints. - */ - if (checkList) { - if ((*checkList) (optionCount, optionList)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - } - - for (i = 0; i < optionCount; i++) { - clientOptionList[i] = optionList[i]; - } - - *clientOptionCount = optionCount; - - return (iscsiAuthStatusNoError); -} - - -static void -iscsiAuthClientSetAuthMethodValid(IscsiAuthClient * client) -{ - static const char rejectOptionNameDraft8[] = "reject"; - static const char rejectOptionNameRfc[] = "Reject"; - static const char noneOptionNameDraft8[] = "none"; - static const char noneOptionNameRfc[] = "None"; - unsigned int i; - unsigned int j = 0; - int option = 0; - - if (client->version == iscsiAuthVersionDraft8) { - client->rejectOptionName = rejectOptionNameDraft8; - client->noneOptionName = noneOptionNameDraft8; - } else { - client->rejectOptionName = rejectOptionNameRfc; - client->noneOptionName = noneOptionNameRfc; - } - - /* - * Following checks may need to be revised if - * authentication options other than CHAP and none - * are supported. - */ - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - - if (client->authRemote) { - /* - * If initiator doing authentication, - * don't offer authentication option none. - */ - option = 1; - } else if (!client->passwordPresent) { - /* - * If initiator password not set, - * only offer authentication option none. - */ - option = 2; - } - } - - if (client->nodeType == iscsiAuthNodeTypeTarget) { - - if (client->authRemote) { - /* - * If target doing authentication, - * don't accept authentication option none. - */ - option = 1; - } else { - /* - * If target not doing authentication, - * only accept authentication option none. - */ - option = 2; - } - } - - for (i = 0; i < client->authMethodCount; i++) { - - if (option == 1) { - if (client->authMethodList[i] == iscsiAuthOptionNone) { - continue; - } - } else if (option == 2) { - if (client->authMethodList[i] != iscsiAuthOptionNone) { - continue; - } - } - - client->authMethodValidList[j++] = client->authMethodList[i]; - } - - client->authMethodValidCount = j; - - iscsiAuthClientInitKeyBlock(&client->sendKeyBlock); - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - if (client->authRemote) { - /* - * Initiator wants to authenticate target, - * always send AuthMethod key. - */ - client->sendKeyBlock.transitBit = FALSE; - client->authMethodValidNegRole = - iscsiAuthNegRoleOriginator; - } else { - client->sendKeyBlock.transitBit = TRUE; - client->authMethodValidNegRole = - client->authMethodNegRole; - } - } else { - client->sendKeyBlock.transitBit = FALSE; - client->authMethodValidNegRole = iscsiAuthNegRoleResponder; - } - - if (client->authMethodValidNegRole == iscsiAuthNegRoleOriginator) { - iscsiAuthClientSetAuthMethodKey(client, - client->authMethodValidCount, - client->authMethodValidList); - } else { - int value = iscsiAuthOptionNotPresent; - iscsiAuthClientSetAuthMethodKey(client, 1, &value); - } -} - - -static int -iscsiAuthClientCheckAuthMethodList(unsigned int optionCount, - const int *optionList) -{ - unsigned int i; - - if (!optionList || optionCount < 2) { - return (TRUE); - } - - if (optionList[optionCount - 1] != iscsiAuthOptionNone) { - return (TRUE); - } - - for (i = 0; i < (optionCount - 1); i++) { - if (optionList[i] != iscsiAuthOptionNone) { - return (FALSE); - } - } - - return (FALSE); -} - - -int -iscsiAuthClientSetAuthMethodList(IscsiAuthClient * client, - unsigned int optionCount, const int *optionList) -{ - int status; - - status = iscsiAuthClientSetOptionList( - client, optionCount, optionList, &client->authMethodCount, - client->authMethodList, iscsiAuthMethodMaxCount, - iscsiAuthClientCheckAuthMethodOption, - iscsiAuthClientCheckAuthMethodList); - - if (status != iscsiAuthStatusNoError) { - return (status); - } - - /* - * Setting authMethod affects authMethodValid. - */ - iscsiAuthClientSetAuthMethodValid(client); - - return (iscsiAuthStatusNoError); -} - -#ifdef notused -int -iscsiAuthClientSetAuthMethodNegRole(IscsiAuthClient * client, int negRole) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - iscsiAuthClientCheckNegRole(negRole) || - client->nodeType != iscsiAuthNodeTypeInitiator) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->authMethodNegRole = (IscsiAuthNegRole) negRole; - - /* - * Setting negRole affects authMethodValid. - */ - iscsiAuthClientSetAuthMethodValid(client); - - return (iscsiAuthStatusNoError); -} -#endif - - -static int -iscsiAuthClientCheckChapAlgorithmList(unsigned int optionCount, - const int *optionList) -{ - if (!optionList || optionCount < 1) { - return (TRUE); - } - - return (FALSE); -} - - -int -iscsiAuthClientSetChapAlgorithmList(IscsiAuthClient * client, - unsigned int optionCount, const int *optionList) -{ - return (iscsiAuthClientSetOptionList(client, - optionCount, - optionList, - &client->chapAlgorithmCount, - client->chapAlgorithmList, - iscsiAuthChapAlgorithmMaxCount, - iscsiAuthClientCheckChapAlgorithmOption, - iscsiAuthClientCheckChapAlgorithmList)); -} - - -int -iscsiAuthClientSetUsername(IscsiAuthClient * client, const char *username) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - iscsiAuthClientCheckString(username, iscsiAuthStringMaxLength, 0)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (iscsiAuthClientStringCopy(client->username, username, - iscsiAuthStringMaxLength)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientSetPassword(IscsiAuthClient * client, - const unsigned char *passwordData, unsigned int passwordLength) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - passwordLength > iscsiAuthStringMaxLength) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - bcopy(passwordData, client->passwordData, passwordLength); - client->passwordLength = passwordLength; - if (client->passwordLength > 0) { - client->passwordPresent = TRUE; - } else { - client->passwordPresent = FALSE; - } - - /* - * Setting password may affect authMethodValid. - */ - iscsiAuthClientSetAuthMethodValid(client); - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientSetAuthRemote(IscsiAuthClient * client, int authRemote) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->authRemote = authRemote; - - /* - * Setting authRemote may affect authMethodValid. - */ - iscsiAuthClientSetAuthMethodValid(client); - - return (iscsiAuthStatusNoError); -} - -#ifdef notused -int -iscsiAuthClientSetGlueHandle(IscsiAuthClient * client, void *glueHandle) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure && - client->phase != iscsiAuthPhaseNegotiate && - client->phase != iscsiAuthPhaseAuthenticate) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->glueHandle = glueHandle; - - return (iscsiAuthStatusNoError); -} - -int -iscsiAuthClientSetMethodListName(IscsiAuthClient *client, - const char *methodListName) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - iscsiAuthClientCheckString(methodListName, - iscsiAuthStringMaxLength, 0)) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (iscsiAuthClientStringCopy(client->methodListName, methodListName, - iscsiAuthStringMaxLength)) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - return (iscsiAuthStatusNoError); -} -#endif - - -int -iscsiAuthClientSetVersion(IscsiAuthClient * client, int version) -{ - if (client == 0 || - client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - iscsiAuthClientCheckVersion(version)) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->version = (IscsiAuthVersion) version; - - iscsiAuthClientSetAuthMethodValid(client); - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientSetIpSec(IscsiAuthClient * client, int ipSec) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->ipSec = ipSec; - - return (iscsiAuthStatusNoError); -} - -#ifdef notused -int -iscsiAuthClientSetBase64(IscsiAuthClient * client, int base64) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->base64 = base64; - - return (iscsiAuthStatusNoError); -} - -int -iscsiAuthClientSetChapChallengeLength(IscsiAuthClient * client, - unsigned int chapChallengeLength) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure || - chapChallengeLength < iscsiAuthChapResponseLength || - chapChallengeLength > iscsiAuthLargeBinaryMaxLength) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - client->chapChallengeLength = chapChallengeLength; - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientCheckPasswordNeeded(IscsiAuthClient *client, int *passwordNeeded) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - if (client->authRemote && !client->passwordPresent) { - *passwordNeeded = TRUE; - } else { - *passwordNeeded = FALSE; - } - } else { - *passwordNeeded = FALSE; - } - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientGetAuthPhase(IscsiAuthClient * client, int *value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - *value = client->phase; - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientGetAuthStatus(IscsiAuthClient * client, int *value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - *value = client->remoteAuthStatus; - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientAuthStatusPass(int authStatus) -{ - if (authStatus == iscsiAuthStatusPass) { - return (TRUE); - } - - return (FALSE); -} - - -int -iscsiAuthClientGetAuthMethod(IscsiAuthClient * client, int *value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseDone && - client->phase != iscsiAuthPhaseAuthenticate) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - *value = client->negotiatedAuthMethod; - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientGetChapAlgorithm(IscsiAuthClient * client, int *value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - *value = client->negotiatedChapAlgorithm; - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientGetChapUsername(IscsiAuthClient * client, - char *value, unsigned int maxLength) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (iscsiAuthClientStringCopy(value, client->chapUsername, maxLength)) { - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - return (iscsiAuthStatusNoError); -} - - -int -iscsiAuthClientSendStatusCode(IscsiAuthClient * client, int *statusCode) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseConfigure && - client->phase != iscsiAuthPhaseNegotiate && - client->phase != iscsiAuthPhaseAuthenticate && - client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseDone) { - *statusCode = 0x0000; - return (iscsiAuthStatusNoError); - } - - switch (client->remoteAuthStatus) { - case iscsiAuthStatusPass: - *statusCode = 0x0000; /* no error */ - break; - - case iscsiAuthStatusFail: - switch (client->debugStatus) { - case iscsiAuthDebugStatusAuthFail: - /* - * Authentication error with peer. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0300; - /* - * iSCSI Target error - */ - } else { - *statusCode = 0x0201; - /* - * iSCSI Initiator error - */ - } - break; - - case iscsiAuthDebugStatusAuthMethodExpected: - case iscsiAuthDebugStatusChapAlgorithmExpected: - case iscsiAuthDebugStatusChapIdentifierExpected: - case iscsiAuthDebugStatusChapChallengeExpected: - case iscsiAuthDebugStatusChapResponseExpected: - case iscsiAuthDebugStatusChapUsernameExpected: - /* - * Missing parameter with peer. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0300; - /* - * iSCSI Target error - */ - } else { - *statusCode = 0x0207; - /* - * iSCSI Initiator error - */ - } - break; - - case iscsiAuthDebugStatusAuthMethodNotPresent: - case iscsiAuthDebugStatusAuthMethodReject: - case iscsiAuthDebugStatusAuthMethodNone: - case iscsiAuthDebugStatusChapAlgorithmReject: - case iscsiAuthDebugStatusChapChallengeReflected: - case iscsiAuthDebugStatusPasswordIdentical: - /* - * Could not authenticate with peer. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0300; - /* - * iSCSI Target error - */ - } else { - *statusCode = 0x0201; - /* - * iSCSI Initiator error - */ - } - break; - - case iscsiAuthDebugStatusLocalPasswordNotSet: - /* - * Local password not set. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0200; - /* - * iSCSI Initiator error - */ - } else { - *statusCode = 0x0201; - /* - * iSCSI Target error - */ - } - break; - - case iscsiAuthDebugStatusChapIdentifierBad: - case iscsiAuthDebugStatusChapChallengeBad: - case iscsiAuthDebugStatusChapResponseBad: - case iscsiAuthDebugStatusUnexpectedKeyPresent: - case iscsiAuthDebugStatusTbitSetIllegal: - case iscsiAuthDebugStatusTbitSetPremature: - case iscsiAuthDebugStatusRecvMessageCountLimit: - case iscsiAuthDebugStatusRecvDuplicateSetKeyValue: - case iscsiAuthDebugStatusRecvStringTooLong: - case iscsiAuthDebugStatusRecvTooMuchData: - /* - * Other error with peer. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0300; - /* - * iSCSI Target error - */ - } else { - *statusCode = 0x0200; - /* - * iSCSI Initiator error - */ - } - break; - - case iscsiAuthDebugStatusNotSet: - case iscsiAuthDebugStatusAuthPass: - case iscsiAuthDebugStatusAuthRemoteFalse: - case iscsiAuthDebugStatusAuthMethodBad: - case iscsiAuthDebugStatusChapAlgorithmBad: - case iscsiAuthDebugStatusPasswordDecryptFailed: - case iscsiAuthDebugStatusPasswordTooShortWithNoIpSec: - case iscsiAuthDebugStatusAuthServerError: - case iscsiAuthDebugStatusAuthStatusBad: - case iscsiAuthDebugStatusAuthPassNotValid: - case iscsiAuthDebugStatusSendDuplicateSetKeyValue: - case iscsiAuthDebugStatusSendStringTooLong: - case iscsiAuthDebugStatusSendTooMuchData: - default: - /* - * Error on this side. - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0200; - /* - * iSCSI Initiator error - */ - } else { - *statusCode = 0x0300; - /* - * iSCSI Target error - */ - } - - } - break; - - case iscsiAuthStatusNoError: - case iscsiAuthStatusError: - case iscsiAuthStatusContinue: - case iscsiAuthStatusInProgress: - default: - /* - * Bad authStatus - */ - if (client->nodeType == iscsiAuthNodeTypeInitiator) { - *statusCode = 0x0200; - /* - * iSCSI Initiator error - */ - } else { - *statusCode = 0x0300; - /* - * iSCSI Target error - */ - } - } - - return (iscsiAuthStatusNoError); -} -#endif - - -int -iscsiAuthClientGetDebugStatus(IscsiAuthClient * client, int *value) -{ - if (!client || client->signature != iscsiAuthClientSignature) { - return (iscsiAuthStatusError); - } - - if (client->phase != iscsiAuthPhaseDone) { - - client->phase = iscsiAuthPhaseError; - return (iscsiAuthStatusError); - } - - *value = client->debugStatus; - - return (iscsiAuthStatusNoError); -} - - -const char * -iscsiAuthClientDebugStatusToText(int debugStatus) -{ - const char *s; - - switch (debugStatus) { - case iscsiAuthDebugStatusNotSet: - s = "Debug status not set"; - break; - - case iscsiAuthDebugStatusAuthPass: - s = "Authentication request passed"; - break; - - case iscsiAuthDebugStatusAuthRemoteFalse: - s = "Authentication not enabled"; - break; - - case iscsiAuthDebugStatusAuthFail: - s = "Authentication request failed"; - break; - - case iscsiAuthDebugStatusAuthMethodBad: - s = "AuthMethod bad"; - break; - - case iscsiAuthDebugStatusChapAlgorithmBad: - s = "CHAP algorithm bad"; - break; - - case iscsiAuthDebugStatusPasswordDecryptFailed: - s = "Decrypt password failed"; - break; - - case iscsiAuthDebugStatusPasswordTooShortWithNoIpSec: - s = "Local password too short with no IPSec"; - break; - - case iscsiAuthDebugStatusAuthServerError: - s = "Unexpected error from authentication server"; - break; - - case iscsiAuthDebugStatusAuthStatusBad: - s = "Authentication request status bad"; - break; - - case iscsiAuthDebugStatusAuthPassNotValid: - s = "Authentication pass status not valid"; - break; - - case iscsiAuthDebugStatusSendDuplicateSetKeyValue: - s = "Same key set more than once on send"; - break; - - case iscsiAuthDebugStatusSendStringTooLong: - s = "Key value too long on send"; - break; - - case iscsiAuthDebugStatusSendTooMuchData: - s = "Too much data on send"; - break; - - case iscsiAuthDebugStatusAuthMethodExpected: - s = "AuthMethod key expected"; - break; - - case iscsiAuthDebugStatusChapAlgorithmExpected: - s = "CHAP algorithm key expected"; - break; - - case iscsiAuthDebugStatusChapIdentifierExpected: - s = "CHAP identifier expected"; - break; - - case iscsiAuthDebugStatusChapChallengeExpected: - s = "CHAP challenge expected"; - break; - - case iscsiAuthDebugStatusChapResponseExpected: - s = "CHAP response expected"; - break; - - case iscsiAuthDebugStatusChapUsernameExpected: - s = "CHAP username expected"; - break; - - case iscsiAuthDebugStatusAuthMethodNotPresent: - s = "AuthMethod key not present"; - break; - - case iscsiAuthDebugStatusAuthMethodReject: - s = "AuthMethod negotiation failed"; - break; - - case iscsiAuthDebugStatusAuthMethodNone: - s = "AuthMethod negotiated to none"; - break; - - case iscsiAuthDebugStatusChapAlgorithmReject: - s = "CHAP algorithm negotiation failed"; - break; - - case iscsiAuthDebugStatusChapChallengeReflected: - s = "CHAP challange reflected"; - break; - - case iscsiAuthDebugStatusPasswordIdentical: - s = "Local password same as remote"; - break; - - case iscsiAuthDebugStatusLocalPasswordNotSet: - s = "Local password not set"; - break; - - case iscsiAuthDebugStatusChapIdentifierBad: - s = "CHAP identifier bad"; - break; - - case iscsiAuthDebugStatusChapChallengeBad: - s = "CHAP challenge bad"; - break; - - case iscsiAuthDebugStatusChapResponseBad: - s = "CHAP response bad"; - break; - - case iscsiAuthDebugStatusUnexpectedKeyPresent: - s = "Unexpected key present"; - break; - - case iscsiAuthDebugStatusTbitSetIllegal: - s = "T bit set on response, but not on previous message"; - break; - - case iscsiAuthDebugStatusTbitSetPremature: - s = "T bit set on response, but authenticaton not complete"; - break; - - case iscsiAuthDebugStatusRecvMessageCountLimit: - s = "Message count limit reached on receive"; - break; - - case iscsiAuthDebugStatusRecvDuplicateSetKeyValue: - s = "Same key set more than once on receive"; - break; - - case iscsiAuthDebugStatusRecvStringTooLong: - s = "Key value too long on receive"; - break; - - case iscsiAuthDebugStatusRecvTooMuchData: - s = "Too much data on receive"; - break; - - default: - s = "Unknown error"; - } - - return (s); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_authglue.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_authglue.c deleted file mode 100644 index 870707b187..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_authglue.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * 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 2000 by Cisco Systems, Inc. All rights reserved. - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * iSCSI Pseudo HBA Driver - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/random.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include <sys/socket.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> - -#include <sys/iscsi_protocol.h> -#include <sys/iscsi_authclient.h> -#include <sys/types.h> -#include <iscsitgt_impl.h> -#include "radius.h" -#include "queue.h" -#include "iscsi_sess.h" -#include "target.h" - -#define DEFAULT_RADIUS_PORT 1812 - -boolean_t -persistent_radius_get(iscsi_radius_props_t *radius) -{ - Boolean_t bRadiusAccess = False; - char *szRadiusServer = NULL; - char *szRadiusSecret = NULL; - char *szRadiusPort = NULL; - int ret = 0; - struct addrinfo *res; - - bzero(radius, sizeof (radius)); - radius->r_radius_config_valid = B_FALSE; - - /* Load RADIUS access option: enable/disable */ - if (tgt_find_value_boolean(main_config, XML_ELEMENT_RAD_ACCESS, - &bRadiusAccess) == False) { - return (B_FALSE); - } - if (bRadiusAccess == False) { - return (B_FALSE); - } - - /* Load RADIUS server: ipaddr[:port] */ - if (tgt_find_value_str(main_config, XML_ELEMENT_RAD_SERV, - &szRadiusServer) == False) { - return (B_FALSE); - } - - szRadiusPort = strchr(szRadiusServer, ':'); - if (szRadiusPort == NULL) { - radius->r_port = DEFAULT_RADIUS_PORT; - } else { - radius->r_port = strtoul(szRadiusPort + 1, NULL, 0); - if (radius->r_port == 0) { - radius->r_port = DEFAULT_RADIUS_PORT; - } - *szRadiusPort = '\0'; - } - - ret = getaddrinfo(szRadiusServer, NULL, NULL, &res); - free(szRadiusServer); - if (ret != 0) { - return (B_FALSE); - } - if (res->ai_family == PF_INET) { - struct sockaddr_in sa_tmp; - - bcopy(res->ai_addr, &sa_tmp, sizeof (sa_tmp)); - radius->r_insize = sizeof (in_addr_t); - radius->r_addr.u_in4 = sa_tmp.sin_addr; - } - /* - * We don't handle IPV6 currently. - */ - - /* Load RADIUS shared secret */ - if (tgt_find_value_str(main_config, XML_ELEMENT_RAD_SECRET, - &szRadiusSecret) == False) { - freeaddrinfo(res); - return (B_FALSE); - } - (void) strncpy((char *)radius->r_shared_secret, szRadiusSecret, - MAX_RAD_SHARED_SECRET_LEN); - radius->r_shared_secret_len = strlen((char *)radius->r_shared_secret); - free(szRadiusSecret); - freeaddrinfo(res); - - /* Set RADIUS config flag */ - radius->r_radius_access = B_TRUE; - radius->r_radius_config_valid = B_TRUE; - return (B_TRUE); -} - -/* - * Authenticate a target's CHAP response. - * - * username - Incoming username from the the target. - * responseData - Incoming response data from the target. - */ -int -iscsiAuthClientChapAuthRequest(IscsiAuthClient *client, - char *username, unsigned int id, uchar_t *challengeData, - unsigned int challengeLength, uchar_t *responseData, - unsigned int responseLength) -{ - iscsi_sess_t *isp = (iscsi_sess_t *)client->userHandle; - IscsiAuthMd5Context context; - iscsi_radius_props_t p_radius_cfg; - uchar_t verifyData[iscsiAuthChapResponseLength]; - char debug[128]; - - if (isp == NULL) { - return (iscsiAuthStatusFail); - } - - /* - * the expected credentials are in the session - */ - if (isp->sess_auth.username_in == NULL) { - (void) snprintf(debug, sizeof (debug), - "SES%x iscsi session(%u) failed authentication, " - "no incoming username configured to authenticate initiator", - isp->s_num); - - queue_str(isp->s_mgmtq, Q_SESS_ERRS, msg_log, debug); - return (iscsiAuthStatusFail); - } - if (strcmp(username, isp->sess_auth.username_in) != 0) { - (void) snprintf(debug, sizeof (debug), - "SES%x iscsi session(%u) failed authentication, " - "received incorrect username from initiator", - isp->s_num); - queue_str(isp->s_mgmtq, Q_SESS_ERRS, msg_log, debug); - return (iscsiAuthStatusFail); - } - - /* Check if RADIUS access is enabled */ - if (persistent_radius_get(&p_radius_cfg) == B_TRUE && - p_radius_cfg.r_radius_access == B_TRUE) { - chap_validation_status_type chap_valid_status; - int authStatus; - RADIUS_CONFIG radius_cfg; - - if (p_radius_cfg.r_radius_config_valid == B_FALSE) { - /* - * Radius enabled but configuration invalid - - * invalid condition - */ - return (iscsiAuthStatusFail); - } - - /* Use RADIUS server to authentication target */ - if (p_radius_cfg.r_insize == sizeof (in_addr_t)) { - /* IPv4 */ - radius_cfg.rad_svr_addr.i_addr.in4.s_addr = - p_radius_cfg.r_addr.u_in4.s_addr; - radius_cfg.rad_svr_addr.i_insize - = sizeof (in_addr_t); - } else if (p_radius_cfg.r_insize == sizeof (in6_addr_t)) { - /* IPv6 */ - bcopy(p_radius_cfg.r_addr.u_in6.s6_addr, - radius_cfg.rad_svr_addr.i_addr.in6.s6_addr, - 16); - radius_cfg.rad_svr_addr.i_insize = sizeof (in6_addr_t); - } else { - return (iscsiAuthStatusFail); - } - - radius_cfg.rad_svr_port = p_radius_cfg.r_port; - bcopy(p_radius_cfg.r_shared_secret, - radius_cfg.rad_svr_shared_secret, - MAX_RAD_SHARED_SECRET_LEN); - radius_cfg.rad_svr_shared_secret_len = - p_radius_cfg.r_shared_secret_len; - - chap_valid_status = radius_chap_validate( - isp->sess_auth.username_in, - isp->sess_auth.username, - challengeData, - challengeLength, - responseData, - responseLength, - id, - radius_cfg.rad_svr_addr, - radius_cfg.rad_svr_port, - radius_cfg.rad_svr_shared_secret, - radius_cfg.rad_svr_shared_secret_len); - - - switch (chap_valid_status) { - case CHAP_VALIDATION_PASSED: - authStatus = iscsiAuthStatusPass; - break; - case CHAP_VALIDATION_INVALID_RESPONSE: - authStatus = iscsiAuthStatusFail; - break; - case CHAP_VALIDATION_DUP_SECRET: - authStatus = iscsiAuthStatusFail; - break; - case CHAP_VALIDATION_RADIUS_ACCESS_ERROR: - authStatus = iscsiAuthStatusFail; - break; - case CHAP_VALIDATION_BAD_RADIUS_SECRET: - authStatus = iscsiAuthStatusFail; - break; - default: - authStatus = iscsiAuthStatusFail; - break; - } - return (authStatus); - } else { - /* Use target secret (if defined) to authenticate target */ - if ((isp->sess_auth.password_length_in < 1) || - (isp->sess_auth.password_in == NULL) || - (isp->sess_auth.password_in[0] == '\0')) { - /* No target secret defined - invalid condition */ - return (iscsiAuthStatusFail); - } - - /* - * challenge length is I->T, and shouldn't need to - * be checked - */ - if (responseLength != sizeof (verifyData)) { - (void) snprintf(debug, sizeof (debug), - "SES%x iscsi session(%u) failed " - "authentication, received incorrect CHAP response " - "from initiator", isp->s_num); - queue_str(isp->s_mgmtq, Q_SESS_ERRS, msg_log, debug); - return (iscsiAuthStatusFail); - } - - iscsiAuthMd5Init(&context); - - /* - * id byte - */ - verifyData[0] = id; - iscsiAuthMd5Update(&context, verifyData, 1); - - /* - * shared secret - */ - iscsiAuthMd5Update(&context, - (uchar_t *)isp->sess_auth.password_in, - isp->sess_auth.password_length_in); - - /* - * challenge value - */ - iscsiAuthMd5Update(&context, - (uchar_t *)challengeData, - challengeLength); - - iscsiAuthMd5Final(verifyData, &context); - - if (bcmp(responseData, verifyData, - sizeof (verifyData)) == 0) { - return (iscsiAuthStatusPass); - } - - (void) snprintf(debug, sizeof (debug), - "SES%x iscsi session(%u) failed authentication, " - "received incorrect CHAP response from initiator", - isp->s_num); - queue_str(isp->s_mgmtq, Q_SESS_ERRS, msg_log, debug); - } - return (iscsiAuthStatusFail); -} - -int -iscsiAuthClientTextToNumber(const char *text, unsigned long *pNumber) -{ - char *pEnd; - unsigned long number; - - number = strtoul(text, &pEnd, 0); - if (*text != '\0' && *pEnd == '\0') { - *pNumber = number; - return (0); /* No error */ - } else { - return (1); /* Error */ - } -} - -/* ARGSUSED */ -void -iscsiAuthClientNumberToText(unsigned long number, char *text, - unsigned int length) -{ - (void) snprintf(text, length, "%lu", number); -} - - -void -iscsiAuthRandomSetData(uchar_t *data, unsigned int length) -{ - int fd; - fd = open("/dev/random", O_RDONLY); - if (fd == -1) - return; - (void) read(fd, data, length); - (void) close(fd); -} - - -void -iscsiAuthMd5Init(IscsiAuthMd5Context * context) -{ - MD5Init(context); -} - - -void -iscsiAuthMd5Update(IscsiAuthMd5Context *context, uchar_t *data, - unsigned int length) -{ - MD5Update(context, data, length); -} - - -void -iscsiAuthMd5Final(uchar_t *hash, IscsiAuthMd5Context *context) -{ - MD5Final(hash, context); -} - - -int -iscsiAuthClientData(uchar_t *outData, unsigned int *outLength, - uchar_t *inData, unsigned int inLength) -{ - if (*outLength < inLength) { - return (1); /* error */ - } - bcopy(inData, outData, inLength); - *outLength = inLength; - return (0); /* no error */ -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_cmd.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_cmd.c deleted file mode 100644 index a02d131be8..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_cmd.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <pthread.h> -#include <stdlib.h> -#include <assert.h> -#include <syslog.h> -#include <synch.h> -#include <sys/time.h> -#include <sys/asynch.h> -#include <umem.h> -#include <strings.h> - -#include "iscsi_conn.h" -#include "iscsi_cmd.h" -#include "target.h" -#include "utility.h" - -static pthread_mutex_t cmd_mutex; -static int cmd_ttt; - -/* - * []---- - * | iscsi_cmd_init -- called at the beginning of time to initialize locks - * []---- - */ -void -iscsi_cmd_init() -{ - (void) pthread_mutex_init(&cmd_mutex, NULL); - cmd_ttt = 0; -} - -/* - * []---- - * | iscsi_cmd_alloc -- allocate space for new command - * []---- - */ -iscsi_cmd_t * -iscsi_cmd_alloc(iscsi_conn_t *c, int op) -{ - iscsi_cmd_t *cmd = umem_cache_alloc(iscsi_cmd_cache, UMEM_DEFAULT); - - if (cmd == NULL) { - queue_prt(mgmtq, Q_CONN_ERRS, "Failed to get command buf\n"); - return (NULL); - } - - bzero(cmd, sizeof (*cmd)); - (void) pthread_mutex_lock(&cmd_mutex); - cmd->c_ttt = cmd_ttt++; - (void) pthread_mutex_unlock(&cmd_mutex); - - (void) pthread_mutex_lock(&c->c_mutex); - cmd->c_opcode = op; - cmd->c_statsn = c->c_statsn; - cmd->c_state = CmdAlloc; - if (c->c_cmd_head == NULL) { - c->c_cmd_head = cmd; - assert(c->c_cmd_tail == NULL); - c->c_cmd_tail = cmd; - } else { - c->c_cmd_tail->c_next = cmd; - cmd->c_prev = c->c_cmd_tail; - c->c_cmd_tail = cmd; - } - cmd->c_allegiance = c; - cmd->c_t_start = gethrtime(); - c->c_cmds_active++; - (void) pthread_mutex_unlock(&c->c_mutex); - - return (cmd); -} - -/* - * []---- - * | iscsi_cmd_find -- search for a specific command and return it - * | - * | XXX Need to switch to use an AVL tree. - * []---- - */ -iscsi_cmd_t * -iscsi_cmd_find(iscsi_conn_t *c, uint32_t val, find_type_t type) -{ - iscsi_cmd_t *cmd = NULL; - - (void) pthread_mutex_lock(&c->c_mutex); - for (cmd = c->c_cmd_head; cmd; cmd = cmd->c_next) { - - /* - * Depending on type determine correct matching value. - * Only return a hit if the command hasn't already been - * freed. - */ - if ((((type == FindTTT) && (cmd->c_ttt == val)) || - ((type == FindITT) && (cmd->c_itt == val))) && - (cmd->c_state != CmdFree)) - break; - } - (void) pthread_mutex_unlock(&c->c_mutex); - - return (cmd); -} - -/* - * []---- - * | iscsi_cmd_free -- mark a command as freed. - * []---- - */ -void -iscsi_cmd_free(iscsi_conn_t *c, iscsi_cmd_t *cmd) -{ - hrtime_t h = gethrtime(); - - assert(cmd->c_state != CmdFree); - cmd->c_state = CmdFree; - cmd->c_t_completion = h - cmd->c_t_start; - c->c_cmds_avg_sum += cmd->c_t_completion; - c->c_cmds_avg_cnt++; - /* decrement active count here */ - c->c_cmds_active--; -} - -/* - * Find all duplicated t10_cmd and shoot an event - */ -void -iscsi_cancel_dups(iscsi_cmd_t *cmd, t10_cmd_event_t e) -{ - t10_cmd_t *c2free; - t10_cmd_t *nc; - - /* Run the list */ - c2free = cmd->c_t10_cmd; - while (c2free != NULL) { - nc = c2free->c_cmd_next; - t10_cmd_shoot_event(c2free, e); - c2free = nc; - } -} - -/* - * []---- - * | iscsi_cmd_cancel -- mark a command as canceled - * | - * | We don't actually stop commands in flight. We only prevent the canceled - * | commands from returning status and/or data to the initiator. At the - * | connection layer if a command is canceled nothing will be sent on the - * | wire and at that point the command is marked CmdFree so that future calls - * | to cmd_remove will actually free the space. - * | - * | NOTE: connection mutex must be held during this call. - * []---- - */ -void -iscsi_cmd_cancel(iscsi_conn_t *c, iscsi_cmd_t *cmd) -{ - assert(pthread_mutex_trylock(&c->c_mutex) != 0); - if (cmd->c_state == CmdAlloc) { - cmd->c_state = CmdCanceled; - if (cmd->c_t10_cmd != NULL) { - if (cmd->c_t10_dup) - iscsi_cancel_dups(cmd, T10_Cmd_T6); - else - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T6); - } - } -} - -/* - * []---- - * | iscsi_cmd_remove -- actually free space allocated to commands - * | - * | According to the iSCSI specification the target must kept resources - * | around until the initiator sends a command with a status serial - * | number higher than the held resource. This is so that an initiator - * | can request data again if needed. During the processing of each new - * | command this routine is called to free old commands. - * []---- - */ -void -iscsi_cmd_remove(iscsi_conn_t *c, uint32_t statsn) -{ - iscsi_cmd_t *cmd, *n; - iscsi_cmd_t *cmd_free = NULL; - - (void) pthread_mutex_lock(&c->c_mutex); - for (cmd = c->c_cmd_head; cmd; ) { - /* - * If the StatusSN for this command is less than the incoming - * StatusSN and the command has been freed remove it from - * list. Don't bother with commands that are in the state of - * CmdCanceled. Once the I/O has been completed the command - * is passed back to the connection handler where the state - * will be noticed and then the command will be freed. At that - * point the next incoming command with a valid expected - * status serial number will free the memory. - */ - if (sna_lt(cmd->c_statsn, statsn)) { - if (cmd->c_state == CmdFree) { - if (c->c_cmd_head == cmd) { - c->c_cmd_head = cmd->c_next; - if (c->c_cmd_head == NULL) - c->c_cmd_tail = NULL; - } else { - n = cmd->c_prev; - n->c_next = cmd->c_next; - if (cmd->c_next != NULL) - cmd->c_next->c_prev = n; - else { - assert(c->c_cmd_tail == cmd); - c->c_cmd_tail = n; - } - } - - /* - * Place on local command free list, to free - * once mutex is released - */ - n = cmd->c_next; - cmd->c_next = cmd_free; - cmd_free = cmd; - cmd = n; - } else { - cmd = cmd->c_next; - } - } else { - break; - } - } - (void) pthread_mutex_unlock(&c->c_mutex); - - /* - * Deallocate command free list - */ - cmd = cmd_free; - while (cmd != NULL) { - n = cmd->c_next; - if (cmd->c_scb_extended) - free(cmd->c_scb_extended); - if (cmd->c_data_alloc == True) { - free(cmd->c_data); - cmd->c_data = NULL; - } - umem_cache_free(iscsi_cmd_cache, cmd); - cmd = n; - } -} - -/* - * []---- - * | iscsi_cmd_window -- return the number of available commands - * | - * | There are currently 7 different places where this routine is called. - * | In some cases and command is allocated which will be freed shortly and - * | in others no command is held. This is why the number of commands found - * | will be decremented if larger than 0. Since the daemon doesn't have - * | any hard limits on the number of commands being supported this is more - * | arbitrary and the command window size is used for debugging other - * | initiators. - * | - * | NOTE: connection mutex must be held during this call. - * []---- - */ -int -iscsi_cmd_window(iscsi_conn_t *c) -{ - int cnt; - - assert(pthread_mutex_trylock(&c->c_mutex) != 0); - if (c->c_cmds_avg_cnt == 0) { - - /* - * If there are no outstanding commands clear the averages - * so that the initiator can start again. - */ - c->c_cmds_avg_sum = 0; - c->c_cmds_avg_cnt = 0; - cnt = c->c_maxcmdsn - c->c_cmds_active; - - } else if ((c->c_cmds_avg_sum / c->c_cmds_avg_cnt) >= NANOSEC) { - - /* - * It would appear things are taking a real long time to - * complete on our end. Close down the command window to - * prevent the initiator from timing out commands. - */ - cnt = (c->c_cmds_active >= c->c_maxcmdsn) ? 0 : - (c->c_maxcmdsn - c->c_cmds_active) / 2; - - } else { - cnt = (c->c_cmds_active >= c->c_maxcmdsn) ? 0 : - c->c_maxcmdsn - c->c_cmds_active; - } - - return (cnt); -} - -void -iscsi_cmd_delayed_store(iscsi_cmd_t *cmd, t10_cmd_t *t) -{ - iscsi_delayed_t *d, *n; - iscsi_delayed_t *l = NULL; - - if ((d = (iscsi_delayed_t *)calloc(1, sizeof (*d))) == NULL) { - syslog(LOG_ERR, "Failed to allocate space for delayed I/O"); - queue_prt(cmd->c_allegiance->c_mgmtq, Q_CONN_ERRS, - "CON%x Failed calloc for delayed I/O", - cmd->c_allegiance->c_num); - t10_cmd_shoot_event(t, T10_Cmd_T5); - return; - } - - d->id_offset = T10_DATA_OFFSET(t); - d->id_t10_cmd = t; - - for (n = cmd->c_t10_delayed; n; n = n->id_next) { - l = n; - if (d->id_offset < n->id_offset) { - if (n->id_prev == NULL) { - d->id_next = n; - n->id_prev = d; - cmd->c_t10_delayed = d; - } else { - d->id_prev = n->id_prev; - d->id_prev->id_next = d; - n->id_prev = d; - d->id_next = n; - } - return; - } - } - - if (l == NULL) { - cmd->c_t10_delayed = d; - } else { - l->id_next = d; - d->id_prev = l; - } -} - -void -iscsi_cmd_delayed_remove(iscsi_cmd_t *cmd, iscsi_delayed_t *d) -{ - if (cmd->c_t10_delayed == d) { - cmd->c_t10_delayed = d->id_next; - if (d->id_next) - d->id_next->id_prev = NULL; - } else { - d->id_prev->id_next = d->id_next; - if (d->id_next != NULL) - d->id_next->id_prev = d->id_prev; - } - free(d); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_cmd.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_cmd.h deleted file mode 100644 index 86e09e738a..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_cmd.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * 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 _TARGET_CMD_H -#define _TARGET_CMD_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/types.h> -#include <sys/avl.h> -#include <aio.h> - -#include <iscsitgt_impl.h> -#include "t10.h" - -#define CMD_MAXOUTSTANDING 16 - -typedef enum { - FindTTT, - FindITT -} find_type_t; - -typedef enum { - CmdAlloc, - CmdCanceled, - CmdFree -} cmd_state_t; - -typedef struct iscsi_delayed { - struct iscsi_delayed *id_prev, - *id_next; - t10_cmd_t *id_t10_cmd; - size_t id_offset; -} iscsi_delayed_t; - -typedef struct iscsi_cmd { - struct iscsi_cmd *c_next; - struct iscsi_cmd *c_prev; - - /* - * Always kept in network byte order since we only - * store this field - */ - uint32_t c_itt; - - uint32_t c_opcode; - uint32_t c_ttt; - uint32_t c_cmdsn; - uint32_t c_datasn; - uint32_t c_statsn; - uint32_t c_dlen_expected; - - Boolean_t c_writeop; - uint32_t c_lun; - - /* - * Default storage for SCB which is the most common size to day. - */ - uint8_t c_scb_default[16]; - - /* - * If the CDB is larger than 16 bytes an Alternate Header Segment - * is used and memory allocated which is pointed to by the following - */ - uint8_t *c_scb_extended; - - /* - * Points at the appropriate memory area for the SCB - */ - uint8_t *c_scb; - uint32_t c_scb_len; - - cmd_state_t c_state; - uint32_t c_status; - - /* - * When ImmediateData==Yes it'll be read in to a buffer - * allocated by the connection. This will be free'd when the - * callback is done which means the SAM-3 layer is finished with - * the data. - */ - char *c_data; - size_t c_data_len; - off_t c_offset_out; - - /* - * Arrange for the PDUs to always be sent in order. If DataPDUInOrder - * is True this is a *must* according to the specification. There's - * also a need that the final flag bit not be sent unless all other - * packets have been, regardless of order. Without keeping a complicated - * bitmap of which packets have been sent for this second case we - * just order things always. - */ - off_t c_offset_in; - iscsi_delayed_t *c_t10_delayed; - - Boolean_t c_data_alloc; - - void (*c_dataout_cb)(t10_cmd_t *cmd, char *data, - size_t *xfer); - - /* - * Used to hold the interface pointer when we've got an R2T - * for this command. This is needed because memory is allocated - * normally by the emulation layer and we can copy directly to that - * instead of allocating our own buffer. - */ - t10_cmd_t *c_t10_cmd; - uint32_t c_t10_dup; - - /* - * Used by the session layer to send packets out the same - * connection. - */ - struct iscsi_conn *c_allegiance; - - hrtime_t c_t_start, - c_t_completion; - -} iscsi_cmd_t; - - -void iscsi_cmd_init(); -iscsi_cmd_t *iscsi_cmd_alloc(struct iscsi_conn *c, int opcode); -iscsi_cmd_t *iscsi_cmd_find(struct iscsi_conn *c, uint32_t x, - find_type_t type); -void iscsi_cmd_free(struct iscsi_conn *c, iscsi_cmd_t *cmd); -void iscsi_cmd_cancel(struct iscsi_conn *c, iscsi_cmd_t *cmd); -void iscsi_cmd_remove(struct iscsi_conn *c, uint32_t statsn); -int iscsi_cmd_window(struct iscsi_conn *c); -void iscsi_cmd_delayed_store(iscsi_cmd_t *cmd, t10_cmd_t *t); -void iscsi_cmd_delayed_remove(iscsi_cmd_t *cmd, iscsi_delayed_t *d); -void iscsi_cancel_dups(iscsi_cmd_t *, t10_cmd_event_t); - -#ifdef __cplusplus -} -#endif - -#endif /* _TARGET_CMD_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_conn.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_conn.c deleted file mode 100644 index 53d24613dd..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_conn.c +++ /dev/null @@ -1,1591 +0,0 @@ -/* - * 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. - */ - -#include <signal.h> -#include <pthread.h> -#include <assert.h> -#include <sys/select.h> -#include <stdlib.h> -#include <poll.h> -#include <strings.h> -#include <sys/filio.h> -#include <errno.h> -#include <utility.h> -#include <unistd.h> -#include <sys/stropts.h> -#include <syslog.h> -#include <sys/iscsi_protocol.h> - -#include <iscsitgt_impl.h> -#include "iscsi_conn.h" -#include "iscsi_sess.h" -#include "iscsi_login.h" -#include "iscsi_ffp.h" -#include "iscsi_provider_impl.h" -#include "utility.h" -#include "target.h" -#include "port.h" -#include "t10.h" - -/* - * defined here so that pad_text is initialized to zero's. It's - * never modified. - */ -static const char pad_text[ISCSI_PAD_WORD_LEN] = { 0 }; - -static void iscsi_conn_data_rqst(t10_cmd_t *cmd); -static void iscsi_conn_cmdcmplt(t10_cmd_t *cmd); -static void iscsi_conn_data_in(t10_cmd_t *); -static void iscsi_conn_pkt(iscsi_conn_t *c, iscsi_rsp_hdr_t *in); - -static void send_datain_pdu(iscsi_conn_t *c, t10_cmd_t *cmd, - uint8_t final_flag); -static void send_scsi_rsp(iscsi_conn_t *c, t10_cmd_t *cmd); -static void queue_noop_in(iscsi_conn_t *c); -static char *state_to_str(iscsi_state_t s); -static void send_async_logout(iscsi_conn_t *c); -static void send_async_scsi(iscsi_conn_t *c, int key, int asc, int ascq); - -void * -conn_poller(void *v) -{ - iscsi_conn_t *c = (iscsi_conn_t *)v; - int nbytes; - int pval; - nfds_t nfds = 1; - struct pollfd fds[1]; - iscsi_state_t state; - target_queue_t *mgmtq = c->c_mgmtq; - Boolean_t one_time_noop = False; - - fds[0].fd = c->c_fd; - fds[0].events = POLLIN; - - util_title(c->c_mgmtq, Q_CONN_LOGIN, c->c_num, "Start Poller"); - while ((pval = poll(fds, nfds, 30 * 1000)) >= 0) { - - /* - * The true asynchronous events are when we're in S5_LOGGED_IN - * state. In the iscsi_full_feature() code the state is - * locked and checked before sending any messages along. The - * mutex is grabbed here only to prevent a collision between - * some thread setting the state and our reading of the value. - * There's no harm in us grabbing the state which might - * change right after we unlock the mutex. - */ - (void) pthread_mutex_lock(&c->c_state_mutex); - state = c->c_state; - (void) pthread_mutex_unlock(&c->c_state_mutex); - - switch (state) { - case S1_FREE: - /* - * If we moved to the free state. The session - * was sent a message to shutdown. Once it - * completes it will reply with a shutdown - * response which will close the main - * connection thread. So, this thread just - * returns a stop processing incoming packets. - */ - goto error; - - case S3_XPT_UP: - if (ioctl(c->c_fd, FIONREAD, &nbytes) < 0) { - queue_message_set(c->c_dataq, 0, msg_shutdown, - 0); - goto error; - } - - /* - * To be fully compliant the code should use - * ioctl(fd, I_PEEK, (struct strpeek v)); and - * look to see if the header is indeed a login - * packet. If not, just close the connection. - */ - if (nbytes < sizeof (iscsi_login_hdr_t)) { - queue_message_set(c->c_dataq, 0, - msg_shutdown, 0); - goto error; - } else { - /* - * Change the state to S4_IN_LOGIN. - * Since we haven't touched the data - * waiting on the stream when the - * sema_post() occurs below the poller - * will find data again and send - * another packet ready message at - * which point we deal with the - * login. - */ - conn_state(c, T4); - } - break; - - case S4_IN_LOGIN: - if (iscsi_handle_login_pkt(c) == False) - goto error; - break; - - case S7_LOGOUT_REQUESTED: - case S5_LOGGED_IN: - if (fds[0].revents & POLLIN) { - - if (iscsi_full_feature(c) == False) - goto error; - - } else { - /* - * Being S5_LOGGED_IN, and POLLIN not set, - * means the that the poll(,,timer) went off. - * If the session is normal, then queue a single - * NOOP request, but only once per connection. - */ - if (c->c_sess->s_type == SessionNormal) { - if (one_time_noop == False) { - queue_noop_in(c); - one_time_noop = True; - } - } - } - break; - - case S6_IN_LOGOUT: - goto error; - - case S8_CLEANUP_WAIT: - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "Haven't handled state S8\n"); - queue_message_set(c->c_dataq, 0, - msg_shutdown_rsp, 0); - goto error; - } - - } - -error: - /* - * Only when we're logged in would we have an active session - * which needs to be shut down. In the case of S4_IN_LOGIN we could - * transition to either S1_FREE in which case a shutdown message - * was sent to the session which in turn will reply with a shutdown - * response causing the conn_process to exit. - */ - if (c->c_state == S5_LOGGED_IN) - conn_state(c, T8); - - /* - * If a msg_conn_lost was already sent it's invalid to reference - * the management queue from the connection structure at this point. - */ - util_title(mgmtq, Q_CONN_LOGIN, c->c_num, "End Poller"); - - if (pval == -1) - queue_message_set(c->c_dataq, 0, msg_conn_lost, 0); - return (NULL); -} - -/* - * conn_process -- thread which runs a connection - */ -void * -conn_process(void *v) -{ - iscsi_conn_t *c = (iscsi_conn_t *)v; - iscsi_cmd_t *cmd; - Boolean_t process = True; - Boolean_t is_last = False; - msg_t *m; - void *thr_status; - int i; - mgmt_request_t *mgmt; - char debug[80]; - time_t tval = time((time_t *)0); - Boolean_t drop_t10_cmds = False; - - c->c_dataq = queue_alloc(); - c->c_maxcmdsn = CMD_MAXOUTSTANDING; - - if (sema_init(&c->c_datain, 0, USYNC_THREAD, NULL) != 0) { - port_conn_remove(c); - free(c); - return (NULL); - } - - util_title(c->c_mgmtq, Q_CONN_LOGIN, c->c_num, "Start Receiver"); - util_title(c->c_mgmtq, Q_CONN_LOGIN, c->c_num, - ctime_r(&tval, debug, sizeof (debug))); - - c->c_thr_id_process = pthread_self(); - - assert(c->c_state == S1_FREE); - conn_state(c, T3); - - (void) pthread_create(&c->c_thr_id_poller, NULL, - conn_poller, (void *)c); - - do { - m = queue_message_get(c->c_dataq); - switch (m->msg_type) { - case msg_mgmt_rqst: - mgmt = (mgmt_request_t *)m->msg_data; - if (c->c_state == S5_LOGGED_IN) { - if (mgmt->m_request == mgmt_logout) { - conn_state(c, T11); - queue_message_set(mgmt->m_q, 0, - msg_mgmt_rply, 0); - } else { - queue_message_set(c->c_sessq, 0, - msg_mgmt_rqst, m->msg_data); - } - } else { - /* - * Corner case which can occur when the - * connection has just started and is in the - * process of logging in and we get a - * mangement request. There's no session - * information or even a queue setup. Just - * show an empty connection. - * - * For the mgmt_logout, it's possible that - * we sent the T11 state change causing the - * connection to enter the S7 state. If we - * get a logout request again the specification - * says to just drop the connection. - */ - if (mgmt->m_request == mgmt_logout) - conn_state(c, T18); - else { - (void) pthread_mutex_lock( - &mgmt->m_resp_mutex); - tgt_buf_add(mgmt->m_u.m_resp, - "connection", NULL); - (void) pthread_mutex_unlock( - &mgmt->m_resp_mutex); - } - queue_message_set(mgmt->m_q, 0, - msg_mgmt_rply, 0); - } - m->msg_data = NULL; - break; - - case msg_conn_lost: - queue_prt(c->c_mgmtq, Q_CONN_LOGIN, - "CON%x Shutdown: connection\n", c->c_num); - - if (c->c_state == S5_LOGGED_IN) - conn_state(c, T8); - break; - - case msg_shutdown_rsp: - if (c->c_state == S6_IN_LOGOUT) - conn_state(c, T13); - (void) pthread_join(c->c_thr_id_poller, &thr_status); - is_last = (Boolean_t)m->msg_data; - m->msg_data = NULL; - process = False; - break; - - case msg_shutdown: - if (c->c_state == S5_LOGGED_IN) { - conn_state(c, T8); - } else if (c->c_state == S4_IN_LOGIN) { - conn_state(c, T7); - } else { - (void) pthread_join(c->c_thr_id_poller, - &thr_status); - process = False; - } - break; - - case msg_targ_inventory_change: - if (c->c_state == S5_LOGGED_IN) { - send_async_scsi(c, KEY_UNIT_ATTENTION, 0x3f, - 0x0e); - } - break; - - case msg_send_pkt: - iscsi_conn_pkt(c, (iscsi_rsp_hdr_t *)m->msg_data); - break; - - case msg_cmd_data_rqst: - /* - * The STE needs more data to complete - * the write command. - */ - if (!drop_t10_cmds) { - iscsi_conn_data_rqst((t10_cmd_t *)m->msg_data); - } - break; - - case msg_cmd_data_in: - /* - * Data is available to satisfy the READ command - */ - if (!drop_t10_cmds) { - iscsi_conn_data_in((t10_cmd_t *)m->msg_data); - } - break; - - case msg_cmd_cmplt: - /* - * Status is available for a previous STEOut. - * The status may be good and the previous STEOut data - * wasn't sent so we phase collapse. - */ - if (!drop_t10_cmds) { - iscsi_conn_cmdcmplt((t10_cmd_t *)m->msg_data); - } - break; - - case msg_wait_for_destroy: { - t10_conn_shutdown_t *t_c_s; - - /* - * Handshake through private queues with - * message sender. Acknowledge receipt of - * the msg which indicates the start of t10 - * cmd destroy, wait for a reply indicating - * the completion of cmd destroy handling, - * ack that, then drop any subsequent t10 cmd - * messages as they've already been canceled - * and freed. - */ - t_c_s = (t10_conn_shutdown_t *)m->msg_data; - queue_message_set(t_c_s->conn_to_t10_q, 0, 1, - (void *)NULL); - queue_message_free(queue_message_get( - t_c_s->t10_to_conn_q)); - queue_message_set(t_c_s->conn_to_t10_q, 0, 1, - (void *)NULL); - drop_t10_cmds = True; - break; - } - - default: - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x Didn't handle msg_type %d\n", c->c_num, - m->msg_type); - break; - } - - queue_message_free(m); - } while (process == True); - - /* - * Free any resources used. - */ - if (c->c_text_area) - free(c->c_text_area); - if (c->c_fd != -1) - (void) close(c->c_fd); - - /* - * It's possible, but very unlikely that c_sessq is NULL at this - * point. I saw one case where the system had problems causing the - * poller routine to exit real early so that the session was never - * setup causing the daemon to get a SEGV in queue_free when a NULL - * was passed in. - */ - if ((is_last == True) && (c->c_sessq != NULL)) - queue_free(c->c_sessq, sess_queue_data_remove); - - /* - * See if there are any commands outstanding and free them. - * NOTE: Should walk through the data_ptr list and find data structure - * who have alligence to this connection and free them as well. - */ - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_state_mutex); - - for (i = 0, cmd = c->c_cmd_head; cmd; i++) - cmd = cmd->c_next; /* debug count of lost ttt's */ - - (void) snprintf(debug, sizeof (debug), "CON%x %d Lost TTTs: ", - c->c_num, i); - - for (i = 0, cmd = c->c_cmd_head; cmd; i++) { - iscsi_cmd_t *n = cmd->c_next; - if (cmd->c_state != CmdCanceled) { - (void) snprintf(debug + strlen(debug), - sizeof (debug) - strlen(debug), - "0x%x ", cmd->c_ttt); - } - - /* - * Make sure to free the resources that the T10 - * layer still has allocated. These are commands which - * the T10 layer couldn't release directly during it's - * shutdown. - */ - if (cmd->c_t10_cmd) { - if (cmd->c_t10_dup) { - iscsi_cancel_dups(cmd, T10_Cmd_T8); - } else { - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T8); - } - } - - /* - * Perform the final clean up which is done during - * cmd_remove(). - */ - if (cmd->c_scb_extended) - free(cmd->c_scb_extended); - if (cmd->c_data_alloc == True) - free(cmd->c_data); - - umem_cache_free(iscsi_cmd_cache, cmd); - cmd = n; - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - if (i) { - /* - * If there where lost commands found send a message indicating - * which ones. This message is purely for information - * and is not indicative of an error. - */ - queue_prt(c->c_mgmtq, Q_CONN_LOGIN, debug); - } - - if (c->c_cmds_avg_cnt != 0) - queue_prt(c->c_mgmtq, Q_CONN_LOGIN, - "CON%x Average completion %lldms\n", c->c_num, - (c->c_cmds_avg_sum / c->c_cmds_avg_cnt) / (1000 * 1000)); - - (void) sema_destroy(&c->c_datain); - if (c->c_targ_alias) - free(c->c_targ_alias); - - util_title(c->c_mgmtq, Q_CONN_LOGIN, c->c_num, "End Receiver"); - - queue_message_set(c->c_mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - /* - * Remove this connection from linked list of current connections. - * This will also free the connection queue. Must not hold the - * q here because port_conn_remove-->queue_free->conn_queue_data - * will possible grab the mutex. - */ - port_conn_remove(c); - free(c); - return (NULL); -} - -/* - * []---- - * | iscsi_conn_pkt -- send out PDU from receive thread - * | - * | (1) This PDU could be either: - * | (a) A NOP request was sent from the initiator which the recieve - * | side processed and is requesting to be sent back. - * | (b) Nothing has been received in N seconds and we're looking - * | to see if the connection is still alive. - * | (c) A task management request was processed by the receive side - * | and the response must be sent. - * | (2) Fields to be filled in - * | Need to delay filling in several of the fields until - * | now to avoid using sequence number which would be out of - * | order. - * []---- - */ -static void -iscsi_conn_pkt(iscsi_conn_t *c, iscsi_rsp_hdr_t *in) -{ - if (c->c_state != S5_LOGGED_IN) { - free(in); - return; - } - - (void) pthread_mutex_lock(&c->c_mutex); - /* - * Make any final per command adjustments. - */ - switch (in->opcode & ISCSI_OPCODE_MASK) { - case ISCSI_OP_NOOP_IN: - in->statsn = htonl(c->c_statsn); - /* - * RFC 3720 section 10.19. specifies: - * - ITT is different from 0xffffffff in NOP-In when responding - * to incomming NOP-Out; and set to 0xffffffff otherwise - * - StatSN is not advanced for ITT set to 0xffffffff - */ - if (((iscsi_nop_in_hdr_t *)in)->itt != ISCSI_RSVD_TASK_TAG) - c->c_statsn++; - break; - } - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - in->expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - in->maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - - if (ISCSI_NOP_SEND_ENABLED() || ISCSI_TASK_RESPONSE_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = in->itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(in->expcmdsn); - info.uip_statsn = ntohl(in->statsn); - info.uip_datasn = 0; - - info.uip_datalen = ntoh24(in->dlength); - info.uip_flags = in->flags; - - switch (in->opcode & ISCSI_OPCODE_MASK) { - case ISCSI_OP_NOOP_IN: - ISCSI_NOP_SEND(&info); - break; - case ISCSI_OP_SCSI_TASK_MGT_RSP: - ISCSI_TASK_RESPONSE(&info); - break; - default: - assert(0); - } - } - - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - send_iscsi_pkt(c, (iscsi_hdr_t *)in, 0); - free(in); -} - -/* - * []---- - * | iscsi_conn_data_rqst -- request that data be sent from the initiator - * []---- - */ -static void -iscsi_conn_data_rqst(t10_cmd_t *t) -{ - iscsi_cmd_t *cmd = T10_TRANS_ID(t); - iscsi_conn_t *c; - iscsi_rtt_hdr_t rtt; - - bzero(&rtt, sizeof (rtt)); - - c = cmd->c_allegiance; - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_state_mutex); - if ((c->c_state != S5_LOGGED_IN) || - (cmd->c_state == CmdCanceled)) { - t10_cmd_shoot_event(t, T10_Cmd_T5); - (void) pthread_mutex_unlock(&c->c_state_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - return; - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - - /* - * Save the data pointer from the emulation code. It's their - * responsibility to allocate space for the data which the - * initiator will return. When we receive a DATAOUT packet - * we'll copy data from the socket directly to this buffer. - */ - cmd->c_data = T10_DATA(t); - - /* - * RFC3270.10.8.3 - * The statsn field will contain the next statsn. The statsn for this - * connection is not advanced after this PDU is sent. - */ - rtt.statsn = htonl(c->c_statsn); - - rtt.opcode = ISCSI_OP_RTT_RSP; - rtt.flags = ISCSI_FLAG_FINAL; - rtt.itt = cmd->c_itt; - rtt.ttt = cmd->c_ttt; - rtt.data_offset = htonl(T10_DATA_OFFSET(t)); - rtt.data_length = htonl(MIN(T10_DATA_LEN(t), c->c_max_burst_len)); - rtt.rttsn = htonl(cmd->c_datasn++); - - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - rtt.maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - rtt.expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - -#ifdef FULL_DEBUG - queue_prt(c->c_mgmtq, Q_CONN_IO, - "CON%x R2T TTT 0x%x offset 0x%x, len 0x%x\n", - c->c_num, cmd->c_ttt, T10_DATA_OFFSET(t), T10_DATA_LEN(t)); -#endif - - t10_cmd_shoot_event(t, T10_Cmd_T7); - (void) pthread_mutex_unlock(&c->c_mutex); - - if (ISCSI_DATA_REQUEST_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = cmd->c_lun; - - info.uip_itt = rtt.itt; - info.uip_ttt = rtt.ttt; - - info.uip_cmdsn = ntohl(rtt.expcmdsn); - info.uip_statsn = c->c_statsn; - info.uip_datasn = 0; - - info.uip_datalen = 0; - info.uip_flags = rtt.flags; - - ISCSI_DATA_REQUEST(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)&rtt, 0); -} - -/* - * []---- - * | iscsi_conn_data_in -- Send data to initiator - * []---- - */ -void -iscsi_conn_data_in(t10_cmd_t *t) -{ - iscsi_cmd_t *cmd = (iscsi_cmd_t *)T10_TRANS_ID(t); - iscsi_conn_t *c; - - c = cmd->c_allegiance; - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_state_mutex); - if ((c->c_state != S5_LOGGED_IN) || - (cmd->c_state == CmdCanceled)) { - - t10_cmd_shoot_event(t, T10_Cmd_T5); - while (cmd->c_t10_delayed) { - t10_cmd_shoot_event(cmd->c_t10_delayed->id_t10_cmd, - T10_Cmd_T5); - iscsi_cmd_delayed_remove(cmd, cmd->c_t10_delayed); - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - return; - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - - /* - * Need to deal with out of order data PDUs. RFC3720 allows - * the initiator to indicate if it can handle out-of-order - * PDUs. - */ - if ((c->c_data_pdu_in_order == True) && - (cmd->c_offset_in != T10_DATA_OFFSET(t))) { - iscsi_cmd_delayed_store(cmd, t); - (void) pthread_mutex_unlock(&c->c_mutex); - return; - } - - while (t != NULL) { - cmd->c_offset_in += T10_DATA_LEN(t); - if (T10_CMD_LAST(t) == True) { - if (cmd->c_offset_in == cmd->c_dlen_expected) { - send_datain_pdu(c, t, - ISCSI_FLAG_FINAL | ISCSI_FLAG_DATA_STATUS); - } else { - /* - * Normally the target only sends a SCSI - * Response PDU for DataOut operations since - * the it indicates successful completion - * in the last DataIn PDU per the spec. - * There are cases where the initiator asks - * for more data then we send, for example - * an INQUIRY command usually returns less - * data then asked for. So, in this case we - * send the DataIn PDU with the appropriate - * amount, followed by a SCSI Response - * indicating the difference between what the - * initiator expected and we're sending. - */ - - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x Underflow occurred\n", c->c_num); - send_datain_pdu(c, t, 0); - send_scsi_rsp(c, t); - } - iscsi_cmd_free(c, cmd); - } else { - send_datain_pdu(c, t, 0); - } - t10_cmd_shoot_event(t, T10_Cmd_T5); - - if (cmd->c_t10_delayed && - (cmd->c_t10_delayed->id_offset == cmd->c_offset_in)) { - t = cmd->c_t10_delayed->id_t10_cmd; - iscsi_cmd_delayed_remove(cmd, cmd->c_t10_delayed); - } else { - t = NULL; - } - } - (void) pthread_mutex_unlock(&c->c_mutex); -} - -/* - * []---- - * | iscsi_conn_cmdcmplt -- Send out appropriate completion PDU - * []---- - */ -static void -iscsi_conn_cmdcmplt(t10_cmd_t *t) -{ - iscsi_cmd_t *cmd = (iscsi_cmd_t *)T10_TRANS_ID(t); - iscsi_conn_t *c; - - c = cmd->c_allegiance; - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_state_mutex); - if ((c->c_state != S5_LOGGED_IN) || - (cmd->c_state == CmdCanceled)) { - - t10_cmd_shoot_event(t, T10_Cmd_T5); - (void) pthread_mutex_unlock(&c->c_state_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - return; - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - - if (T10_SENSE_LEN(t) || (T10_DATA(t) == 0)) { - - /* - * If d_sense_len is set there's a problem and we need to send - * a SCSI response packet. Or if there's no data buffer then - * this is an acknowledgement that a SCSI Write completed - * successfully. - */ - send_scsi_rsp(c, t); - - } else { - - /* - * send data out with final bit. Last packet of a SCSI - * READ Op and we'll send it out with the final/status - * bits set. - */ - send_datain_pdu(c, t, - ISCSI_FLAG_FINAL | ISCSI_FLAG_DATA_STATUS); - - } - - t10_cmd_shoot_event(t, T10_Cmd_T5); - - if (cmd->c_scb_extended != NULL) - free(cmd->c_scb_extended); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); -} - -/* - * []---- - * | send_datain_pdu -- Send DataIn PDU with READ data - * | - * | If this is the last read operation and it completed successfully - * | the final flag will be set along with the status bit which indicates - * | successful completion. This is known as a phase collapse for iSCSI. - * | - * | NOTE: connection mutex must be held. - * []---- - */ -static void -send_datain_pdu(iscsi_conn_t *c, t10_cmd_t *t, uint8_t final_flag) -{ - iscsi_cmd_t *cmd = (iscsi_cmd_t *)T10_TRANS_ID(t); - iscsi_data_rsp_hdr_t rsp; - - assert(pthread_mutex_trylock(&c->c_mutex) != 0); - bzero(&rsp, sizeof (rsp)); - - rsp.opcode = ISCSI_OP_SCSI_DATA_RSP; - rsp.flags = final_flag; - rsp.cmd_status = cmd->c_status; - rsp.itt = cmd->c_itt; - rsp.ttt = ISCSI_RSVD_TASK_TAG; - rsp.datasn = htonl(cmd->c_datasn++); - rsp.offset = htonl(T10_DATA_OFFSET(t)); - rsp.lun[1] = (uint8_t)cmd->c_lun; - - hton24(rsp.dlength, T10_DATA_LEN(t)); - - /* - * The statsn is only incremented when the Status bit is set - * for a DataIn PDU. This must be done *after* the value - * was stored in the PDU. - */ - if (final_flag & ISCSI_FLAG_DATA_STATUS) { - rsp.statsn = htonl(c->c_statsn); - c->c_statsn++; - } else - rsp.statsn = 0; - - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - rsp.maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - rsp.expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - - if (ISCSI_DATA_SEND_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = cmd->c_lun; - - info.uip_itt = rsp.itt; - info.uip_ttt = rsp.ttt; - - info.uip_cmdsn = ntohl(rsp.expcmdsn); - info.uip_statsn = ntohl(rsp.statsn); - info.uip_datasn = ntohl(rsp.datasn); - - info.uip_datalen = T10_DATA_LEN(t); - info.uip_flags = rsp.flags; - - ISCSI_DATA_SEND(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)&rsp, T10_DATA(t)); -} - -/* - * []---- - * | send_scsi_rsp -- Send SCSI reponse PDU - * | - * | NOTE: connection mutex must be held. - * []---- - */ -static void -send_scsi_rsp(iscsi_conn_t *c, t10_cmd_t *t) -{ - iscsi_cmd_t *cmd = (iscsi_cmd_t *)T10_TRANS_ID(t); - iscsi_scsi_rsp_hdr_t rsp; - void *auto_sense = NULL; - - assert(pthread_mutex_trylock(&c->c_mutex) != 0); - bzero(&rsp, sizeof (rsp)); - - rsp.opcode = ISCSI_OP_SCSI_RSP; - rsp.flags = ISCSI_FLAG_FINAL; - rsp.itt = cmd->c_itt; - rsp.statsn = htonl(c->c_statsn++); - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - rsp.expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - rsp.maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - rsp.cmd_status = T10_CMD_STATUS(t); - - if (cmd->c_writeop == True) { - if (cmd->c_offset_out != cmd->c_dlen_expected) - rsp.flags |= ISCSI_FLAG_CMD_OVERFLOW; - rsp.residual_count = htonl(cmd->c_dlen_expected - - cmd->c_offset_out); - } else { - if (cmd->c_offset_in != cmd->c_dlen_expected) - rsp.flags |= ISCSI_FLAG_CMD_UNDERFLOW; - rsp.residual_count = htonl(cmd->c_dlen_expected - - cmd->c_offset_in); - } - - if (rsp.cmd_status) { - rsp.response = ISCSI_STATUS_CMD_COMPLETED; - rsp.residual_count = htonl(T10_CMD_RESID(t)); - - if (T10_SENSE_LEN(t) != 0) { - /* - * Need to handle autosense stuff. The data should - * be store in the d_sense area - */ - auto_sense = (void *)T10_SENSE_DATA(t); - hton24(rsp.dlength, T10_SENSE_LEN(t)); - } - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x SCSI Error Status: %d\n", - c->c_num, rsp.cmd_status); - } else { - rsp.response = ISCSI_STATUS_CMD_COMPLETED; - rsp.expdatasn = htonl(cmd->c_datasn); - } - - if (ISCSI_SCSI_RESPONSE_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = cmd->c_lun; - - info.uip_itt = rsp.itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(rsp.expcmdsn); - info.uip_statsn = ntohl(rsp.statsn); - info.uip_datasn = ntohl(rsp.expdatasn); - - info.uip_datalen = T10_DATA_LEN(t); - info.uip_flags = rsp.flags; - - ISCSI_SCSI_RESPONSE(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)&rsp, auto_sense); -} - -static void -send_async_scsi(iscsi_conn_t *c, int key, int asc, int ascq) -{ - iscsi_async_evt_hdr_t a; - struct scsi_extended_sense s; - char *buf; - int dlen = sizeof (s) + 2; - - bzero(&a, sizeof (a)); - bzero(&s, sizeof (s)); - - s.es_class = CLASS_EXTENDED_SENSE; - s.es_code = CODE_FMT_FIXED_CURRENT; - s.es_key = key; - s.es_valid = 1; - s.es_add_code = asc; - s.es_qual_code = ascq; - - if ((buf = malloc(sizeof (s) + 2)) == NULL) - return; - - buf[0] = (sizeof (s) >> 8) & 0xff; - buf[1] = sizeof (s) & 0xff; - bcopy(&s, &buf[2], sizeof (s)); - - hton24(a.dlength, dlen); - a.opcode = ISCSI_OP_ASYNC_EVENT; - a.flags = ISCSI_FLAG_FINAL; - a.async_event = ISCSI_ASYNC_EVENT_SCSI_EVENT; - (void) pthread_mutex_lock(&c->c_mutex); - a.statsn = htonl(c->c_statsn++); - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - a.expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - a.maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, - "CON%x Sending async scsi sense\n", c->c_num); - - if (ISCSI_ASYNC_SEND_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = ISCSI_RSVD_TASK_TAG; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(a.expcmdsn); - info.uip_statsn = ntohl(a.statsn); - info.uip_datasn = 0; - - info.uip_datalen = dlen; - info.uip_flags = a.flags; - - ISCSI_ASYNC_SEND(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)&a, buf); -} - -/* - * []---- - * | send_async_logout -- request logout from initiator - * []---- - */ -static void -send_async_logout(iscsi_conn_t *c) -{ - iscsi_async_evt_hdr_t a; - - bzero(&a, sizeof (a)); - - a.opcode = ISCSI_OP_ASYNC_EVENT; - a.flags = ISCSI_FLAG_FINAL; - a.async_event = ISCSI_ASYNC_EVENT_REQUEST_LOGOUT; - (void) pthread_mutex_lock(&c->c_mutex); - a.statsn = htonl(c->c_statsn++); - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - a.expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - a.maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - a.param3 = htons(ASYNC_LOGOUT_TIMEOUT); - a.rsvd4[0] = 0xff; - a.rsvd4[1] = 0xff; /* According to the spec these four */ - a.rsvd4[2] = 0xff; /* values must be 0xff */ - a.rsvd4[3] = 0xff; - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, - "CON%x Sending async logout request\n", c->c_num); - - if (ISCSI_ASYNC_SEND_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = ISCSI_RSVD_TASK_TAG; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(a.expcmdsn); - info.uip_statsn = ntohl(a.statsn); - info.uip_datasn = 0; - - info.uip_datalen = 0; - info.uip_flags = a.flags; - - ISCSI_ASYNC_SEND(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)&a, 0); -} - -/* - * []---- - * | queue_noop_in -- generate a NOP request and queue it to be sent. - * []---- - */ -static void -queue_noop_in(iscsi_conn_t *c) -{ - iscsi_nop_in_hdr_t *in; - iscsi_cmd_t *cmd = iscsi_cmd_alloc(c, ISCSI_OP_NOOP_IN); - - if (cmd == NULL) - return; - - in = (iscsi_nop_in_hdr_t *)calloc(sizeof (*in), 1); - if (in == NULL) - return; - - /* - * Immediate flag is reserved in nop-in command. RFC-3720 10.19. - * See CR 6597310. - */ - in->opcode = ISCSI_OP_NOOP_IN; - in->flags = ISCSI_FLAG_FINAL; - in->ttt = cmd->c_ttt; - in->itt = ISCSI_RSVD_TASK_TAG; - - (void) pthread_mutex_lock(&c->c_mutex); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - queue_message_set(c->c_dataq, 0, msg_send_pkt, (void *)in); -} - -void -iscsi_capacity_change(char *targ_name, int lun) -{ - iscsi_conn_t *conn; - extern pthread_mutex_t port_mutex; - - /* - * SBC-2 revision 16, section 4.6 -- Initialization - * Any time the parameter data returned by the READ CAPACITY(10) - * (see 5.10) or the READ CAPACITY(16) command (see 5.11) changes, - * the device server should establish a unit attention condition for - * the initiator port associated with each I_T nexus. - * Since the transport knows which initiators are currently accessing - * the target the message will be sent from here. - */ - (void) pthread_mutex_lock(&port_mutex); - for (conn = conn_head; conn; conn = conn->c_next) { - (void) pthread_mutex_lock(&conn->c_state_mutex); - if ((conn->c_state == S5_LOGGED_IN) && - (conn->c_sess->s_type == SessionNormal) && - (strcmp(conn->c_sess->s_t_name, targ_name) == 0)) { - - queue_message_set(conn->c_sessq, 0, - msg_lu_capacity_change, (void *)(uintptr_t)lun); - } - (void) pthread_mutex_unlock(&conn->c_state_mutex); - } - (void) pthread_mutex_unlock(&port_mutex); -} - -/* - * []---- - * | iscsi_inventory_change -- Send notice to initiator that something changed. - * []---- - */ -void -iscsi_inventory_change(char *targ_name) -{ - iscsi_conn_t *c; - extern pthread_mutex_t port_mutex; - - /* - * SPC-3 revision 21c, Section 6.21 REPORT_LUNS - * If the logical unit inventory changes for any reason - * (e.g. completion of initialization, removal of a logical unit, - * or create of a logical unit), then the device server shall generate - * a unit attention condition for all I_T nexuses, with the additional - * sense code set to REPORTED LUNS DATA HAS CHANGED. - */ - (void) pthread_mutex_lock(&port_mutex); - for (c = conn_head; c; c = c->c_next) { - (void) pthread_mutex_lock(&c->c_state_mutex); - if ((c->c_state == S5_LOGGED_IN) && - (c->c_sess->s_type == SessionNormal) && - (strcmp(c->c_sess->s_t_name, targ_name) == 0)) { - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, - "CON%x Sending Inventory change out\n", c->c_num); - /* - * Send a message indicating that the logical unit - * inventory has changed. 1) This message is sent - * to the session level which will pass it onto - * the SAM layer causing a UNIT_ATTENTION during - * the next command. 2) This message is also sent - * directly to the outgoing side of the connection - * which will send an asynchronous event message - * to the initiator. - */ - queue_message_set(c->c_sessq, 0, - msg_targ_inventory_change, 0); - queue_message_set(c->c_dataq, 0, - msg_targ_inventory_change, 0); - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - } - (void) pthread_mutex_unlock(&port_mutex); -} - -/* - * []---- - * | state_to_str -- return string for given state, used for debug - * []---- - */ -static char * -state_to_str(iscsi_state_t s) -{ - switch (s) { - case S1_FREE: return ("FREE"); - case S3_XPT_UP: return ("XPT_UP"); - case S4_IN_LOGIN: return ("IN_LOGIN"); - case S5_LOGGED_IN: return ("LOGGED_IN"); - case S6_IN_LOGOUT: return ("IN_LOGOUT"); - case S7_LOGOUT_REQUESTED: return ("LOGOUT_REQUEST"); - case S8_CLEANUP_WAIT: return ("CLEANUP_WAIT"); - } - return ("Unknown"); -} - -/* - * []---- - * | event_to_str -- return string for given event, used for debug - * []---- - */ -static char * -event_to_str(iscsi_transition_t t) -{ - switch (t) { - case T3: return ("T3"); - case T4: return ("T4"); - case T5: return ("T5"); - case T6: return ("T6"); - case T7: return ("T7"); - case T8: return ("T8"); - case T9: return ("T9"); - case T10: return ("T10"); - case T11: return ("T11"); - case T12: return ("T12"); - case T13: return ("T13"); - case T15: return ("T15"); - case T16: return ("T16"); - case T17: return ("T17"); - case T18: return ("T18"); - } - return ("Unknown"); -} - -/* - * []---- - * | conn_state -- Attempt to change from one state to the next - * []---- - */ -void -conn_state(iscsi_conn_t *c, iscsi_transition_t t) -{ - iscsi_state_t old_state = c->c_state; - Boolean_t lock = False; - - (void) pthread_mutex_lock(&c->c_state_mutex); - lock = True; - - switch (c->c_state) { - case S1_FREE: - switch (t) { - case T3: - c->c_state = S3_XPT_UP; - break; - - } - break; - - case S3_XPT_UP: - switch (t) { - case T6: - c->c_state = S1_FREE; - break; - - case T4: - c->c_statsn = 0; - c->c_state = S4_IN_LOGIN; - break; - - } - break; - - case S4_IN_LOGIN: - switch (t) { - case T7: - /* - * When there's a session a shutdown messages is - * sent giving the opportunity to free resources - * used by the session code and STE. Very early - * on a session might not exist when a failure - * occurs like getting a bad opcode. The connection - * process routine is going to sit around waiting - * for a message which will never come so fake - * a completion message here if there's no session. - */ - if (c->c_sessq == NULL) { - queue_message_set(c->c_dataq, 0, - msg_shutdown_rsp, (void *)True); - } else { - queue_message_set(c->c_sessq, 0, msg_shutdown, - (void *)c); - } - c->c_state = S1_FREE; - break; - case T5: - c->c_state = S5_LOGGED_IN; - if (strncmp(c->c_sess->s_i_name, - "iqn.1991-05.com.microsoft", - strlen("iqn.1991-05.com.microsoft")) == 0) - c->c_sess->s_cmdsn++; - break; - } - break; - - case S5_LOGGED_IN: - switch (t) { - case T8: - c->c_state = S1_FREE; - queue_message_set(c->c_sessq, 0, msg_shutdown, - (void *)c); - break; - case T9: - queue_message_set(c->c_sessq, 0, msg_shutdown, - (void *)c); - c->c_state = S6_IN_LOGOUT; - break; - case T11: - c->c_state = S7_LOGOUT_REQUESTED; - /* - * need to unlock here conn_state may get - * call again, which can create deadlock - */ - (void) pthread_mutex_unlock(&c->c_state_mutex); - lock = False; - send_async_logout(c); - break; - case T15: - c->c_state = S8_CLEANUP_WAIT; - break; - } - break; - - case S6_IN_LOGOUT: - switch (t) { - case T13: - if (c->c_last_pkg) { - iscsi_logout_rsp_hdr_t *rsp = - (iscsi_logout_rsp_hdr_t *)c->c_last_pkg; - assert(rsp->opcode == ISCSI_OP_LOGOUT_RSP); - - if (ISCSI_LOGOUT_RESPONSE_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_target_addr = - &c->c_target_sockaddr; - info.uip_initiator_addr = - &c->c_initiator_sockaddr; - info.uip_target = &nil; - - info.uip_initiator = - c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = rsp->itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(rsp->expcmdsn); - info.uip_statsn = ntohl(rsp->statsn); - info.uip_datasn = 0; - - info.uip_datalen = ntoh24(rsp->dlength); - info.uip_flags = rsp->flags; - - ISCSI_LOGOUT_RESPONSE(&info); - } - - /* - * need to unlock here conn_state may get - * call again, which can create deadlock - */ - (void) pthread_mutex_unlock(&c->c_state_mutex); - lock = False; - send_iscsi_pkt(c, c->c_last_pkg, NULL); - free(c->c_last_pkg); - } - c->c_state = S1_FREE; - break; - case T17: - c->c_state = S8_CLEANUP_WAIT; - break; - } - break; - - case S7_LOGOUT_REQUESTED: - switch (t) { - case T18: - c->c_state = S1_FREE; - queue_message_set(c->c_sessq, 0, msg_shutdown, - (void *)c); - break; - case T10: - queue_message_set(c->c_sessq, 0, msg_shutdown, - (void *)c); - c->c_state = S6_IN_LOGOUT; - break; - case T12: - c->c_state = S7_LOGOUT_REQUESTED; - break; - case T16: - c->c_state = S8_CLEANUP_WAIT; - break; - } - break; - - case S8_CLEANUP_WAIT: - default: - break; - } - queue_prt(c->c_mgmtq, Q_CONN_NONIO, "CON%x ---- %s(%s) -> %s\n", - c->c_num, state_to_str(old_state), event_to_str(t), - state_to_str(c->c_state)); - if (lock) - (void) pthread_mutex_unlock(&c->c_state_mutex); -} - -/* - * []---- - * | send_iscsi_pkt -- output PDU header, data, and alignment bytes if needed - * | - * | NOTE: This routine may be called with the connection mutex held. This - * | is done to prevent a state change being made to a command pointer. This - * | routine is currently written so that it doesn't need to have this mutex - * | held or calls a routine which needs it to be held. - * []---- - */ -void -send_iscsi_pkt(iscsi_conn_t *c, iscsi_hdr_t *h, char *opt_text) -{ - int dlen = ntoh24(h->dlength); - int pad_len; - uint32_t crc; - -#ifdef ETHEREAL_DEBUG - uint32_t alen; - char *abuf; - - /* - * For ethereal to correctly show the entire PDU and data everything - * must be written once else the Solaris TCP stack will send this - * out in multiple packets. Normally this isn't a problem, but when - * attempting to debug certain interactions between an initiator - * and this target is extremely benefical to have ethereal correctly - * decode the SCSI payload for non I/O type packets. - */ - if (dlen < 512) { - /* - * Find out how many pad bytes we need to send out. - */ - pad_len = (ISCSI_PAD_WORD_LEN - - (dlen & (ISCSI_PAD_WORD_LEN - 1))) & - (ISCSI_PAD_WORD_LEN - 1); - alen = sizeof (*h) + dlen + pad_len; - if ((abuf = malloc(alen)) == NULL) { - conn_state(c, T8); - return; - } - bzero(abuf, alen); - bcopy(h, abuf, sizeof (*h)); - if (opt_text) - bcopy(opt_text, abuf + sizeof (*h), dlen); - if (write(c->c_fd, abuf, alen) != alen) { - conn_state(c, T8); - free(abuf); - return; - } - free(abuf); -#ifdef FULL_DEBUG - queue_prt(c->c_mgmtq, Q_CONN_IO, - "CON%x Response(0x%x), Data: len=0x%x addr=0x%llx\n", - c->c_num, h->opcode, dlen, opt_text); -#endif - return; - } -#endif - - /* - * Sanity check. If there's a length in the header we must - * have text to send or if the length is zero there better not - * be any text. - */ - if (((dlen == 0) && (opt_text != NULL)) || - ((dlen != 0) && (opt_text == NULL))) - return; - - if (write(c->c_fd, h, sizeof (*h)) < 0) { - if (errno == EPIPE) { - - /* - * For some reason the initiator has closed the - * socket on us. This is most likely caused because - * of some network related condition - * (e.g. broken cable). We'll shutdown our side and - * wait for a reconnect from the initiator. - */ - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x iscsi_pkt -- initiator closed socket\n", - c->c_num); - } else { - - /* - * This is not good. - */ - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x iscsi_pkt write failed, errno %d\n", - c->c_num, errno); - } - conn_state(c, T8); - return; - } - - /* - * Only start generating digest values once we've completed the - * login phase. If the state is not checked here and during login - * header or data digests have been enabled we would generate - * a digest value during the Login RSP PDU which the initiator - * is not expecting. - */ - if ((c->c_state == S5_LOGGED_IN) && (c->c_header_digest == True)) { - crc = iscsi_crc32c((void *)h, sizeof (*h)); - if (write(c->c_fd, &crc, sizeof (crc)) != sizeof (crc)) { - conn_state(c, T8); - return; - } - } - - if (dlen) { - if (write(c->c_fd, opt_text, dlen) != dlen) { - conn_state(c, T8); - return; - } - - /* - * Find out how many pad bytes we need to send out. - */ - pad_len = (ISCSI_PAD_WORD_LEN - - (dlen & (ISCSI_PAD_WORD_LEN - 1))) & - (ISCSI_PAD_WORD_LEN - 1); - if (pad_len) { - if (write(c->c_fd, pad_text, pad_len) != pad_len) { - conn_state(c, T8); - return; - } - } - - if ((c->c_state == S5_LOGGED_IN) && - (c->c_data_digest == True)) { - - crc = iscsi_crc32c((void *)opt_text, - (unsigned long)dlen); - - /* - * Include the pad information in the calculation of - * the CRC for the data. - */ - crc = iscsi_crc32c_continued((void *)pad_text, - (unsigned long)pad_len, crc); - - if (write(c->c_fd, &crc, sizeof (crc)) != - sizeof (crc)) { - conn_state(c, T8); - return; - } - } - } -#ifdef FULL_DEBUG - if (dlen != 0) { - queue_prt(c->c_mgmtq, Q_CONN_IO, - "CON%x Response(0x%x), Data: len=0x%x addr=0x%llx\n", - c->c_num, h->opcode, dlen, opt_text); - } -#endif -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_conn.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_conn.h deleted file mode 100644 index 851757200d..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_conn.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _TARGET_CONN_H -#define _TARGET_CONN_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/iscsi_protocol.h> -#include <sys/socket.h> -#include "queue.h" -#include "iscsi_sess.h" -#include "iscsi_cmd.h" - -#define LBUFSIZE 80 - -#define TARGET_LOCATION "targets" -/* - * Currently I'm having some problems with network reads/write when the - * data size is larger than 8k. To work around this problem I set the - * various negotiation parameters during login to limit things to 8k. - */ - -#define NETWORK_SNDRCV 65536 -#define NETWORK_SNDRCV_STR "65536" - -typedef enum iscsi_state { - S1_FREE, - /* S2_XPT_WAIT, Not possible for target */ - S3_XPT_UP, - S4_IN_LOGIN, - S5_LOGGED_IN, - S6_IN_LOGOUT, - S7_LOGOUT_REQUESTED, - S8_CLEANUP_WAIT -} iscsi_state_t; - -typedef enum iscsi_transition { - T3, T4, T5, T6, T7, T8, - T9, T10, T11, T12, T13, T15, - T16, T17, T18 -} iscsi_transition_t; - -/* - * When grabbing mutex's make sure to grab c_mutex before c_mutex_state - * if you need to grab both. - */ -typedef struct iscsi_conn { - int c_fd; - - /* - * This is a linked list of all connections. Not just the connections - * associated with a particular session. - */ - struct iscsi_conn *c_next, - *c_prev; - - target_queue_t *c_mgmtq; - - /* - * Time as reported by time(2) when this connection was started. - */ - time_t c_up_at; - - /* - * This queue is used to accept notification that incoming packets - * are available and command completion status from Session. - */ - target_queue_t *c_dataq; - - /* - * Messages are sent to Session, and from there onto STE, using - * this queue. - */ - target_queue_t *c_sessq; - - iscsi_sess_t *c_sess; - - pthread_mutex_t c_state_mutex; - iscsi_state_t c_state; - - /* - * Protected by c_mutex - */ - int c_statsn; - - int c_cid; - - /* - * Pointer to data buffer used to store text messages which have - * the 'C' bit set. Since the text data separates name/value pairs - * with a '\0' strlen can't be used to determine the amount of space - * used so we keep the length in c_text_len; - */ - char *c_text_area; - int c_text_len; - int c_text_sent; - - sema_t c_datain; - pthread_t c_thr_id_poller, - c_thr_id_process; - - pthread_mutex_t c_mutex; - iscsi_cmd_t *c_cmd_head; - iscsi_cmd_t *c_cmd_tail; - - struct sockaddr_storage c_initiator_sockaddr; - struct sockaddr_storage c_target_sockaddr; - - int c_num; - - int c_auth_pass : 1; - - int c_cmds_active; - - /* - * A performance issue has been found when the backing store - * is UFS. Because of the indirect blocks used by UFS large files - * (many GBs in size) perform poorly. This in turn can cause the - * initiator to issue commands which don't complete in time. So, - * we'll monitor the completion times for commands if if it's - * increasing the command window will be reduced. - * The avg_sum is in nanoseconds. This will wrap once every 584 - * years. - */ - uint64_t c_cmds_avg_cnt; - hrtime_t c_cmds_avg_sum; - - /* - * During an orderly shutdown the logout response is created when - * we receive the logout request. We must however wait for all I/O - * to complete before processing the data else we'll loose data - * which the initiator believes was successfully transferred. - * Once the STE and sessions have closed they will send a shutdown - * complete message. At that point the transmit side of the connection - * will set the state to T13 which pushes this message out. - * Unfortunately we need information from the Logout Request PDU - * to create the Logout Response PDU. Otherwise the response could - * be generated on the fly in the T13 state handler. By creating - * the response PDU and saving a pointer gives us some flexibility - * in the future if the final outgoing packet needs to change. - * Otherwise, storing that one bit of information from the request - * PDU might become dated. - */ - iscsi_hdr_t *c_last_pkg; - - /* - * Connection parameters - */ - Boolean_t c_header_digest, - c_data_digest, - c_ifmarker, - c_ofmarker, - c_initialR2T, - c_immediate_data, - c_data_pdu_in_order, - c_data_sequence_in_order; - int c_tpgt, - c_maxcmdsn, - c_max_recv_data, - c_default_time_2_wait, - c_default_time_2_retain, - c_erl, - c_max_burst_len, - c_first_burst_len, - c_max_outstanding_r2t, - c_max_connections; - char *c_targ_alias, - *auth_text; - int auth_text_length; - -} iscsi_conn_t; - -void *conn_process(void *v); -void conn_state(iscsi_conn_t *c, iscsi_transition_t t); -void send_iscsi_pkt(iscsi_conn_t *c, iscsi_hdr_t *h, char *opt_text); -int read_retry(int fd, char *buf, int count); -void iscsi_inventory_change(char *targ_name); -void iscsi_capacity_change(char *targ_name, int lun); - -#ifdef __cplusplus -} -#endif - -#endif /* _TARGET_CONN_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_crc.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_crc.c deleted file mode 100644 index ba5736f294..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_crc.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * 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 2000 by Cisco Systems, Inc. All rights reserved. - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * This file contains CRC-32C code use to verify - * iSCSI HeaderDigests and DataDigests. - */ - -#include <sys/types.h> /* standard types */ -#include <sys/iscsi_protocol.h> /* contains prototypes */ -#include <hd_crc.h> - -/* - * This is the CRC-32C table - * Generated with: - * width = 32 bits - * poly = 0x1EDC6F41 - * reflect input bytes = true - * reflect output bytes = true - */ - -uint32_t iscsi_crc32c_table[256] = -{ - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, - 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, - 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, - 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, - 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, - 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, - 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, - 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, - 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, - 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, - 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, - 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, - 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, - 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, - 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, - 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, - 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, - 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, - 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, - 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, - 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, - 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, - 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, - 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, - 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, - 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, - 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, - 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, - 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, - 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, - 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, - 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, - 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 -}; - -/* - * -1 - uninitialized - * 0 - applicable - * others - NA - */ -static int iscsi_crc32_hd = -1; - -/* - * iscsi_crc32c - Steps through buffer one byte at at time, calculates - * reflected crc using table. - */ -uint32_t -iscsi_crc32c(void *address, unsigned long length) -{ - uint8_t *buffer = address; - uint32_t crc = 0xffffffff, result; -#ifdef _BIG_ENDIAN - uint8_t byte0, byte1, byte2, byte3; -#endif - - if (iscsi_crc32_hd == -1) { - if (hd_crc32_avail((uint32_t *)iscsi_crc32c_table) == B_TRUE) { - iscsi_crc32_hd = 0; - } else { - iscsi_crc32_hd = 1; - } - } - if (iscsi_crc32_hd == 0) - return (HW_CRC32(buffer, length, crc)); - - while (length--) { - crc = iscsi_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^ - (crc >> 8); - } - result = crc ^ 0xffffffff; - -#ifdef _BIG_ENDIAN - byte0 = (uint8_t)(result & 0xFF); - byte1 = (uint8_t)((result >> 8) & 0xFF); - byte2 = (uint8_t)((result >> 16) & 0xFF); - byte3 = (uint8_t)((result >> 24) & 0xFF); - result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); -#endif /* _BIG_ENDIAN */ - - return (result); -} - - -/* - * iscsi_crc32c_continued - Continues stepping through buffer one - * byte at at time, calculates reflected crc using table. - */ -uint32_t -iscsi_crc32c_continued(void *address, unsigned long length, uint32_t crc) -{ - uint8_t *buffer = address; - uint32_t result; -#ifdef _BIG_ENDIAN - uint8_t byte0, byte1, byte2, byte3; -#endif - - if (iscsi_crc32_hd == -1) { - if (hd_crc32_avail((uint32_t *)iscsi_crc32c_table) == B_TRUE) { - iscsi_crc32_hd = 0; - } else { - iscsi_crc32_hd = 1; - } - } - if (iscsi_crc32_hd == 0) - return (HW_CRC32_CONT(buffer, length, crc)); - -#ifdef _BIG_ENDIAN - byte0 = (uint8_t)((crc >> 24) & 0xFF); - byte1 = (uint8_t)((crc >> 16) & 0xFF); - byte2 = (uint8_t)((crc >> 8) & 0xFF); - byte3 = (uint8_t)(crc & 0xFF); - crc = ((byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0); -#endif - - crc = crc ^ 0xffffffff; - while (length--) { - crc = iscsi_crc32c_table[(crc ^ *buffer++) & 0xFFL] ^ - (crc >> 8); - } - result = crc ^ 0xffffffff; - -#ifdef _BIG_ENDIAN - byte0 = (uint8_t)(result & 0xFF); - byte1 = (uint8_t)((result >> 8) & 0xFF); - byte2 = (uint8_t)((result >> 16) & 0xFF); - byte3 = (uint8_t)((result >> 24) & 0xFF); - result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); -#endif - return (result); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_ffp.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_ffp.c deleted file mode 100644 index 92387b2c7c..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_ffp.c +++ /dev/null @@ -1,1129 +0,0 @@ -/* - * 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. - */ - -/* - * This file contains methods to handle the iSCSI Full Feature Phase aspects - * of the protocol. - */ - -#include <unistd.h> -#include <poll.h> -#include <strings.h> -#include <stdlib.h> -#include <sys/types.h> -#include <assert.h> -#include <stdio.h> -#include <errno.h> -#include <utility.h> -#include <netinet/in.h> -#include <inttypes.h> -#include <sys/socket.h> -#include <sys/iscsi_protocol.h> - -#include <arpa/inet.h> - -#include "iscsi_ffp.h" -#include "iscsi_cmd.h" -#include "t10_spc.h" -#include "utility.h" -#include "iscsi_provider_impl.h" - -static Boolean_t handle_text_msg(iscsi_conn_t *, iscsi_hdr_t *, char *, int); -static Boolean_t handle_logout_msg(iscsi_conn_t *, iscsi_hdr_t *, char *, int); -static Boolean_t handle_scsi_cmd(iscsi_conn_t *, iscsi_hdr_t *, char *, int); -static Boolean_t handle_noop_cmd(iscsi_conn_t *, iscsi_hdr_t *, char *, int); -static Boolean_t handle_scsi_data(iscsi_conn_t *, iscsi_hdr_t *, char *, int); -static Boolean_t handle_task_mgt(iscsi_conn_t *, iscsi_hdr_t *, char *, int); -static Boolean_t dataout_delayed(iscsi_cmd_t *cmd, msg_type_t type); -void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer); - -Boolean_t -iscsi_full_feature(iscsi_conn_t *c) -{ - iscsi_hdr_t h; - Boolean_t rval = False; - char debug[128]; - char *ahs = NULL; - int cc; - int ahslen; - - if ((cc = recv(c->c_fd, &h, sizeof (h), MSG_WAITALL)) != sizeof (h)) { - if (errno == ECONNRESET) { - (void) snprintf(debug, sizeof (debug), - "CON%x full_feature -- initiator reset socket\n", - c->c_num); - } else { - (void) snprintf(debug, sizeof (debug), - "CON%x full_feature(got-%d, expect-%d), errno=%d\n", - c->c_num, cc, sizeof (h), errno); - } - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T8); - return (False); - } - - /* - * Look to see if there's an Additional Header Segment available. - * If so, read it in. - */ - if ((ahslen = (h.hlength * sizeof (uint32_t))) != 0) { - if ((ahs = malloc(ahslen)) == NULL) - return (False); - if (recv(c->c_fd, ahs, ahslen, MSG_WAITALL) != ahslen) { - (void) snprintf(debug, sizeof (debug), - "CON%x Failed to read in AHS", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - free(ahs); - return (False); - } - } - - (void) pthread_mutex_lock(&c->c_state_mutex); - if (c->c_state != S5_LOGGED_IN && c->c_state != S7_LOGOUT_REQUESTED) { - (void) snprintf(debug, sizeof (debug), - "CON%x full_feature -- not in S5_LOGGED_IN state\n", - c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - if (ahs != NULL) - free(ahs); - (void) pthread_mutex_unlock(&c->c_state_mutex); - return (False); - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - - if (c->c_header_digest == True) { - uint32_t crc_actual; - uint32_t crc_calculated; - - (void) recv(c->c_fd, (char *)&crc_actual, - sizeof (crc_actual), MSG_WAITALL); - crc_calculated = iscsi_crc32c((void *)&h, sizeof (h)); - if (ahslen) - crc_calculated = iscsi_crc32c_continued(ahs, - ahslen, crc_calculated); - if (crc_actual != crc_calculated) { - (void) snprintf(debug, sizeof (debug), - "CON%x CRC error: actual 0x%x v. calc 0x%x", - c->c_num, crc_actual, crc_calculated); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - if (ahs != NULL) - free(ahs); - return (False); - } - } - - if (c->c_sess->s_type == SessionDiscovery) { - switch (h.opcode & ISCSI_OPCODE_MASK) { - default: - /* - * Need to handle the error case here. - */ - (void) snprintf(debug, sizeof (debug), - "CON%x Wrong opcode for Discovery, %d", - c->c_num, h.opcode & ISCSI_OPCODE_MASK); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - rval = False; - break; - - case ISCSI_OP_LOGOUT_CMD: - /* - * This will transition from S5_LOGGED_IN - * to S6_IN_LOGOUT to S1_FREE; - */ - rval = handle_logout_msg(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_TEXT_CMD: - rval = handle_text_msg(c, &h, ahs, ahslen); - break; - } - } else { - iscsi_cmd_remove(c, ntohl(h.expstatsn)); - switch (h.opcode & ISCSI_OPCODE_MASK) { - case ISCSI_OP_NOOP_OUT: - rval = handle_noop_cmd(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_SCSI_CMD: - rval = handle_scsi_cmd(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_SCSI_TASK_MGT_MSG: - rval = handle_task_mgt(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_LOGIN_CMD: - /* - * This is an illegal state transition. Should - * we drop the connection? - */ - break; - - case ISCSI_OP_TEXT_CMD: - rval = handle_text_msg(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_SCSI_DATA: - rval = handle_scsi_data(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_LOGOUT_CMD: - /* - * This will transition from S5_LOGGED_IN - * to S6_IN_LOGOUT. - */ - rval = handle_logout_msg(c, &h, ahs, ahslen); - break; - - case ISCSI_OP_SNACK_CMD: - default: - (void) snprintf(debug, sizeof (debug), - "CON%x Opcode: %d not handled", - c->c_num, h.opcode & ISCSI_OPCODE_MASK); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T8); - rval = True; - break; - } - } - - if (ahs != NULL) - free(ahs); - return (rval); -} - -/*ARGSUSED*/ -static Boolean_t -handle_task_mgt(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen) -{ - iscsi_scsi_task_mgt_hdr_t *hp = (iscsi_scsi_task_mgt_hdr_t *)p; - iscsi_scsi_task_mgt_rsp_hdr_t *rsp; - iscsi_cmd_t *cmd; - uint32_t lun; - Boolean_t lu_reset = False; - - if (spc_decode_lu_addr(&hp->lun[0], 8, &lun) == False) - return (False); - - if (ISCSI_TASK_COMMAND_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = lun; - - info.uip_itt = hp->itt; - info.uip_ttt = hp->itt; - - info.uip_cmdsn = ntohl(hp->cmdsn); - info.uip_statsn = ntohl(hp->expstatsn); - info.uip_datasn = ntohl(hp->expdatasn); - - info.uip_datalen = ntoh24(hp->dlength); - info.uip_flags = 0; - - ISCSI_TASK_COMMAND(&info); - } - - if ((rsp = calloc(1, sizeof (*rsp))) == NULL) - return (False); - - rsp->opcode = ISCSI_OP_SCSI_TASK_MGT_RSP; - rsp->flags = ISCSI_FLAG_FINAL; - rsp->itt = hp->itt; - - (void) pthread_mutex_lock(&c->c_mutex); - rsp->statsn = htonl(c->c_statsn++); - (void) pthread_mutex_unlock(&c->c_mutex); - - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn) - c->c_sess->s_seencmdsn = ntohl(hp->cmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, - "CON%x PDU(Task Mgt): %s, cmdsn 0x%x\n", - c->c_num, - task_to_str(hp->function & ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK), - ntohl(hp->cmdsn)); - - switch (hp->function & ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK) { - case ISCSI_TM_FUNC_ABORT_TASK: - queue_prt(c->c_mgmtq, Q_CONN_NONIO, - "CON%x Abort ITT 0x%x\n", c->c_num, hp->rtt); - if ((cmd = iscsi_cmd_find(c, hp->rtt, FindITT)) == NULL) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x Invalid AbortTask rtt 0x%x\n", - c->c_num, hp->rtt); - rsp->response = SCSI_TCP_TM_RESP_NO_TASK; - } else { - (void) pthread_mutex_lock(&c->c_mutex); - iscsi_cmd_cancel(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - rsp->response = SCSI_TCP_TM_RESP_COMPLETE; - } - break; - - case ISCSI_TM_FUNC_ABORT_TASK_SET: - /* ---- This is actually "Function not support" ---- */ - rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS; - break; - - case ISCSI_TM_FUNC_CLEAR_ACA: - /* ---- This is actually "Function not support" ---- */ - rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS; - break; - - case ISCSI_TM_FUNC_CLEAR_TASK_SET: - /* ---- This is actually "Function not support" ---- */ - rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS; - break; - - case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: - lu_reset = True; - /*FALLTHRU*/ - case ISCSI_TM_FUNC_TARGET_WARM_RESET: - (void) pthread_mutex_lock(&c->c_mutex); - for (cmd = c->c_cmd_head; cmd; cmd = cmd->c_next) { - if (((hp->function & - ISCSI_FLAG_TASK_MGMT_FUNCTION_MASK) == - ISCSI_TM_FUNC_TARGET_WARM_RESET) || - (lun == cmd->c_lun)) { - iscsi_cmd_cancel(c, cmd); - - } - } - (void) pthread_mutex_unlock(&c->c_mutex); - - if (lu_reset == True) - queue_message_set(c->c_sessq, 0, msg_reset_lu, - (void *)(uintptr_t)lun); - else - queue_message_set(c->c_sessq, 0, msg_reset_targ, 0); - rsp->response = SCSI_TCP_TM_RESP_COMPLETE; - break; - - case ISCSI_TM_FUNC_TARGET_COLD_RESET: - /* - * According to the specification a cold reset should - * close *all* connections on the target, not just those - * for this current session. - */ - queue_message_set(c->c_sessq, 0, msg_reset_targ, (void *)1); - conn_state(c, T8); - break; - - case ISCSI_TM_FUNC_TASK_REASSIGN: - default: - /* ---- This is actually "Function not support" ---- */ - rsp->response = SCSI_TCP_TM_RESP_IN_PRGRESS; - break; - } - - (void) pthread_mutex_lock(&c->c_state_mutex); - if (c->c_state == S5_LOGGED_IN) - queue_message_set(c->c_dataq, - hp->opcode & ISCSI_OP_IMMEDIATE ? Q_HIGH : 0, - msg_send_pkt, rsp); - (void) pthread_mutex_unlock(&c->c_state_mutex); - return (True); -} - -/*ARGSUSED*/ -static Boolean_t -handle_noop_cmd(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen) -{ - iscsi_nop_out_hdr_t *hp = (iscsi_nop_out_hdr_t *)p; - iscsi_nop_in_hdr_t *in; - - if (ISCSI_NOP_RECEIVE_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = hp->itt; - info.uip_ttt = hp->ttt; - - info.uip_cmdsn = ntohl(hp->cmdsn); - info.uip_statsn = ntohl(hp->expstatsn); - info.uip_datasn = 0; - - info.uip_datalen = ntoh24(hp->dlength); - info.uip_flags = hp->flags; - - ISCSI_NOP_RECEIVE(&info); - } - - /* - * Just an answer to our ping - */ - if (hp->ttt != ISCSI_RSVD_TASK_TAG) - return (True); - - if ((in = calloc(1, sizeof (*in))) == NULL) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x NopIn -- failed to malloc space for header", - c->c_num); - return (False); - } - - in->opcode = ISCSI_OP_NOOP_IN; - in->flags = ISCSI_FLAG_FINAL; - /* - * Need to handle possible data associated with NOP-Out - */ - bcopy(hp->lun, in->lun, 8); - in->itt = hp->itt; - in->ttt = ISCSI_RSVD_TASK_TAG; - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn) - c->c_sess->s_seencmdsn = ntohl(hp->cmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - - (void) pthread_mutex_lock(&c->c_state_mutex); - if (c->c_state == S5_LOGGED_IN) - queue_message_set(c->c_dataq, - hp->opcode & ISCSI_OP_IMMEDIATE ? Q_HIGH : 0, - msg_send_pkt, in); - (void) pthread_mutex_unlock(&c->c_state_mutex); - return (True); -} - -/*ARGSUSED*/ -static Boolean_t -handle_scsi_data(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen) -{ - iscsi_data_hdr_t *hp = (iscsi_data_hdr_t *)p; - int dlen = ntoh24(hp->dlength); - iscsi_cmd_t *cmd; - - if (ISCSI_DATA_RECEIVE_ENABLED()) { - uiscsiproto_t info; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = hp->itt; - info.uip_ttt = hp->itt; - - info.uip_cmdsn = 0; - info.uip_statsn = ntohl(hp->expstatsn); - info.uip_datasn = ntohl(hp->datasn); - - info.uip_datalen = dlen; - info.uip_flags = hp->flags; - - ISCSI_DATA_RECEIVE(&info); - } - - if ((cmd = iscsi_cmd_find(c, hp->ttt, FindTTT)) == NULL) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x failed to find ttt 0x%x\n", c->c_num, hp->ttt); - /* - * Need to handle error case. - */ - return (False); - } - cmd->c_opcode = hp->opcode & ISCSI_OPCODE_MASK; - - /* - * assert(cmd->c_lun == hp->lun[1]); - * Previously this check was done, but is caused a problem with - * the RedHat initiator. There was a discussion on the IPS alias - * around this very topic. Even though section 10.7.4 states: - * "If the Target Transfer Tag is provided, then the LUN field - * MUST hold a valid value and be consistent with whatever was - * specified with the command; otherwise, the LUN field is - * reserved." - * Everyone agreed though that for a DataOut command the LUN field - * wasn't required to be valid because the TTT gives the Target - * enough information to complete the command. - */ - assert(cmd->c_allegiance == c); - assert(cmd->c_itt == hp->itt); - - cmd->c_offset_out = ntohl(hp->offset); - cmd->c_data_len = dlen; - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_state_mutex); - if (c->c_state == S5_LOGGED_IN) { - if (cmd->c_state != CmdCanceled) { - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T4); - } - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - -#ifdef FULL_DEBUG - queue_prt(c->c_mgmtq, Q_CONN_IO, - "CON%x PDU(DataOut) TTT 0x%x, offset=0x%x, len=0x%x\n", - c->c_num, cmd->c_ttt, cmd->c_t10_cmd->c_offset, dlen); -#endif - - return (dataout_delayed(cmd, msg_cmd_data_out)); -} - -static Boolean_t -handle_scsi_cmd(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen) -{ - iscsi_scsi_cmd_hdr_t *hp = (iscsi_scsi_cmd_hdr_t *)p; - int dlen = ntoh24(hp->dlength); - iscsi_cmd_t *cmd; - - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn) - c->c_sess->s_seencmdsn = ntohl(hp->cmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - - if ((cmd = iscsi_cmd_alloc(c, hp->opcode & ISCSI_OPCODE_MASK)) == NULL) - return (False); - - bcopy(hp->scb, cmd->c_scb_default, sizeof (cmd->c_scb_default)); - cmd->c_scb = cmd->c_scb_default; - cmd->c_scb_len = sizeof (cmd->c_scb_default); - cmd->c_data_len = dlen; - - if (ahslen) { - - /* - * Additional Header Section ---- - * - * For Object Storage Devices the SCB is quite large. On - * the order of 140 bytes which means the data must be - * found in the AHS. - */ - uint16_t hslen; - uint16_t next_seg; - uint8_t hstyp; - - do { - /* - * Find this header segment's length and type - */ - bcopy(ahs, &hslen, sizeof (hslen)); - hslen = ntohs(hslen); - hstyp = ahs[2]; - - switch (hstyp) { - /* ---- Extended CDB ---- */ - case 1: - /* - * The hslen accounts for the reserved - * data byte in the segment. So the first - * sixteen bytes are in hp->scb with the - * remainder here. By only adding 15 bytes - * we allocate the correct amount of space - */ - cmd->c_scb_extended = malloc(hslen + 15); - cmd->c_scb_len = hslen + 15; - if (cmd->c_scb_extended == NULL) - return (False); - - /* - * First 16 bytes of extended SCB are - * found in the normal location. - */ - bcopy(hp->scb, cmd->c_scb_extended, 16); - bcopy(&ahs[4], &cmd->c_scb_extended[16], - hslen - 16); - cmd->c_scb = cmd->c_scb_extended; - break; - - /* ---- Expected bidirectional read data len ---- */ - case 2: - /* - * We shouldn't need this since we're - * not prealloc'ing resources. If that should - * change or the need for error checking - * here's the spot to locate the data. - */ - break; - } - - /* - * hslen contains the effective length in bytes of - * segment, excluding type and length (not including - * padding). Each segment is padded to a 4 byte - * boundary. - */ - next_seg = ((hslen + sizeof (hslen) + - sizeof (hstyp) + 3) & ~3); - ahs += next_seg; - ahslen -= next_seg; - - } while (ahslen); - } - - /* - * XXX Need to handle error case better. - */ - if (spc_decode_lu_addr(&hp->lun[0], sizeof (hp->lun), &cmd->c_lun) == - False) { - return (False); - } - - if (ISCSI_SCSI_COMMAND_ENABLED()) { - uiscsiproto_t info; - uiscsicmd_t uc; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = cmd->c_lun; - - info.uip_itt = hp->itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(hp->cmdsn); - info.uip_statsn = ntohl(hp->expstatsn); - info.uip_datasn = 0; - - info.uip_datalen = dlen; - info.uip_flags = hp->flags; - - uc.uic_len = cmd->c_scb_len; - uc.uic_cdb = cmd->c_scb; - - ISCSI_SCSI_COMMAND(&info, &uc); - } - - cmd->c_itt = hp->itt; - cmd->c_cmdsn = ntohl(hp->cmdsn); - cmd->c_dlen_expected = ntohl(hp->data_length); - cmd->c_writeop = hp->flags & ISCSI_FLAG_CMD_WRITE ? - True : False; - -#ifdef FULL_DEBUG - queue_prt(c->c_mgmtq, Q_CONN_IO, - "CON%x PDU(SCSI Cmd, TA=%d) CmdSN 0x%x ITT 0x%x TTT 0x%x " - "LUN[%02x] id=%p\n", c->c_num, - hp->flags & ISCSI_FLAG_CMD_ATTR_MASK, cmd->c_cmdsn, cmd->c_itt, - cmd->c_ttt, cmd->c_lun, cmd); -#endif - - if (dlen && (hp->flags & ISCSI_FLAG_CMD_WRITE)) { - /* - * NOTE: This should only occur if ImmediateData==Yes. - * We can handle this even if the initiator violates - * the specification so no need to worry. Use the rule - * of "Be strict in what is sent, but lenient in what - * is accepted." - */ - return (dataout_delayed(cmd, msg_cmd_send)); - } else { - (void) pthread_mutex_lock(&c->c_state_mutex); - if (c->c_state == S5_LOGGED_IN) - queue_message_set(c->c_sessq, 0, - msg_cmd_send, (void *)cmd); - (void) pthread_mutex_unlock(&c->c_state_mutex); - return (True); - } -} - -/* - * []---- - * | handle_text_msg -- process incoming test parameters - * | - * | NOTE: Need to handle continuation packets sent by the initiator. - * []---- - */ -/*ARGSUSED*/ -static Boolean_t -handle_text_msg(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen) -{ - iscsi_text_rsp_hdr_t rsp; - iscsi_text_hdr_t *hp = (iscsi_text_hdr_t *)p; - char *text = NULL; - int text_length = 0; - Boolean_t release_at_end = False; - int dlen = ntoh24(hp->dlength); - - if (ISCSI_TEXT_COMMAND_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_initiator = c->c_sess->s_i_name; - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_target = &nil; - info.uip_lun = 0; - - info.uip_itt = hp->itt; - info.uip_ttt = hp->ttt; - - info.uip_cmdsn = ntohl(hp->cmdsn); - info.uip_statsn = ntohl(hp->expstatsn); - info.uip_datasn = 0; - - info.uip_datalen = dlen; - info.uip_flags = hp->flags; - - ISCSI_TEXT_COMMAND(&info); - } - - bzero(&rsp, sizeof (rsp)); - rsp.opcode = ISCSI_OP_TEXT_RSP; - rsp.itt = hp->itt; - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, "CON%x PDU(Text Message)\n", - c->c_num); - - /* - * Need to determine if this incoming text PDU is an initial message - * or a continuation. - */ - if (hp->ttt == ISCSI_RSVD_TASK_TAG) { - - /* ---- Initial text PDU, so parse the incoming data ---- */ - if (parse_text(c, dlen, &text, &text_length, NULL) == False) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "Failed to parse Text\n"); - if (text) { - /* - * It's possible that we started to create - * a response, but yet an error occurred. - * Release the partial text response if that - * occurred. - */ - free(text); - } - return (False); - } - - /* - * 10.11.4 -- - * When the target receives a Text Request with the Target - * Transfer Tag set to the reserved value of 0xffffffff, it - * resets its internal information (resets state) associated - * with the given Initiator Task Tag (restarts the negotiation). - */ - if (c->c_text_area != NULL) - free(c->c_text_area); - - c->c_text_area = text; - if (text_length > c->c_max_recv_data) { - - /* - * Too much data to send at once, break it up into - * multiple transfers. - */ - rsp.flags = ISCSI_FLAG_TEXT_CONTINUE; - rsp.ttt = 1; - c->c_text_len = text_length; - text_length = c->c_max_recv_data; - c->c_text_sent = text_length; - } else { - rsp.flags = ISCSI_FLAG_FINAL; - rsp.ttt = ISCSI_RSVD_TASK_TAG; - release_at_end = True; - } - } else { - - /* ---- Continuation of previous text request ---- */ - text_length = c->c_text_len - c->c_text_sent; - text = c->c_text_area + c->c_text_sent; - if (text_length > c->c_max_recv_data) { - rsp.flags = ISCSI_FLAG_TEXT_CONTINUE; - rsp.ttt = 1; - text_length = c->c_max_recv_data; - c->c_text_sent += text_length; - } else { - rsp.flags = ISCSI_FLAG_FINAL; - rsp.ttt = ISCSI_RSVD_TASK_TAG; - release_at_end = True; - } - } - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, - "CON%x Text PDU: flags=0x%02x, ttt=0x%08x, len=%d\n", - c->c_num, rsp.flags, rsp.ttt, text_length); - - hton24(rsp.dlength, text_length); - (void) pthread_mutex_lock(&c->c_mutex); - rsp.statsn = htonl(c->c_statsn++); - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - if (ntohl(hp->cmdsn) > c->c_sess->s_seencmdsn) - c->c_sess->s_seencmdsn = ntohl(hp->cmdsn); - rsp.maxcmdsn = htonl(iscsi_cmd_window(c) + c->c_sess->s_seencmdsn); - rsp.expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - if (ISCSI_TEXT_RESPONSE_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_target = &nil; - info.uip_lun = 0; - - info.uip_itt = rsp.itt; - info.uip_ttt = rsp.ttt; - - info.uip_cmdsn = ntohl(rsp.expcmdsn); - info.uip_statsn = ntohl(rsp.statsn); - info.uip_datasn = 0; - - info.uip_datalen = text_length; - info.uip_flags = rsp.flags; - - ISCSI_TEXT_RESPONSE(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)&rsp, text); - - if (release_at_end == True) { - free(c->c_text_area); - c->c_text_area = NULL; - } - return (True); -} - -/*ARGSUSED*/ -static Boolean_t -handle_logout_msg(iscsi_conn_t *c, iscsi_hdr_t *p, char *ahs, int ahslen) -{ - iscsi_logout_rsp_hdr_t *rsp; - iscsi_logout_hdr_t *hp = (iscsi_logout_hdr_t *)p; - char debug[80]; - - if (ISCSI_LOGOUT_COMMAND_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = c->c_sess->s_t_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_target = &nil; - info.uip_lun = 0; - - info.uip_itt = hp->itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(hp->cmdsn); - info.uip_statsn = ntohl(hp->expstatsn); - info.uip_datasn = 0; - - info.uip_datalen = ntoh24(hp->dlength); - info.uip_flags = hp->flags; - - ISCSI_LOGOUT_COMMAND(&info); - } - - if ((rsp = calloc(1, sizeof (*rsp))) == NULL) - return (False); - - (void) snprintf(debug, sizeof (debug), - "CON%x PDU(Logout Request)", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_NONIO, msg_log, debug); - - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - if (hp->cmdsn > c->c_sess->s_seencmdsn) - c->c_sess->s_seencmdsn = htonl(hp->cmdsn); - rsp->expcmdsn = htonl(c->c_sess->s_seencmdsn + 1); - rsp->maxcmdsn = htonl(iscsi_cmd_window(c) + - c->c_sess->s_seencmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - rsp->opcode = ISCSI_OP_LOGOUT_RSP; - rsp->flags = ISCSI_FLAG_FINAL; - rsp->itt = hp->itt; - (void) pthread_mutex_lock(&c->c_mutex); - rsp->statsn = htonl(c->c_statsn++); - (void) pthread_mutex_unlock(&c->c_mutex); - - c->c_last_pkg = (iscsi_hdr_t *)rsp; - - /* - * Call the state transition last. This will send out - * an asynchronous message to shutdown the session and STE. - * Once that's complete a shutdown reply will be sent to - * the transmit connection thread. That will cause another - * transition to T13 which expects to send out this logout - * response. - */ - if (c->c_state == S7_LOGOUT_REQUESTED) - conn_state(c, T10); - else - conn_state(c, T9); - - return (True); -} - -/* - * dataout_delayed -- possibly copy data from initiator - * - * If DataDigests are enabled copy the data from the socket into a buffer - * and perform the CRC check now. - * - * If MaxConnections==1 don't copy the data now and wait until the STE is - * ready to copy the data directly from the socket to it's final location. - * This is extremely beneficial when using mmap'd data. - * NOTE: - * (1) For this to work we must not use the queues and instead - * call the STE functions directly. If the queues are used - * this routine must pause until STE processes the data to - * prevent this thread from attempting to read data from - * the socket as if it's the next PDU header. - * (2) Currently we don't call STE directly. To prevent a performance - * issue we'll have the code in place to support calling - * STE directly, but any time MaxConnections is greater than 0 - * we'll copy the buffer. This will be removed at some future - * point. - */ -static Boolean_t -dataout_delayed(iscsi_cmd_t *cmd, msg_type_t type) -{ - iscsi_conn_t *c = cmd->c_allegiance; - int dlen = cmd->c_data_len; - int cc; - uint32_t crc_calc; - uint32_t crc_actual; - char pad_buf[ISCSI_PAD_WORD_LEN - 1]; - char pad_len; - char debug[80]; - - cmd->c_dataout_cb = dataout_callback; - - if (cmd->c_data == NULL) { - if ((cmd->c_data = (char *)malloc(dlen)) == NULL) { - (void) pthread_mutex_lock(&c->c_mutex); - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - return (False); - } - cmd->c_data_alloc = True; - } - - if ((cc = recv(c->c_fd, cmd->c_data, dlen, MSG_WAITALL)) != dlen) { - if (errno == ECONNRESET) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x dataout_delayed -- " - "initiator reset socket\n", c->c_num); - } else { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x recv(got-%d, expect-%d), errno=%d\n", - c->c_num, cc, dlen, errno); - } - - (void) pthread_mutex_lock(&c->c_mutex); - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - conn_state(c, T8); - return (True); - } - - pad_len = ((ISCSI_PAD_WORD_LEN - - (dlen & (ISCSI_PAD_WORD_LEN - 1))) & (ISCSI_PAD_WORD_LEN - 1)); - - if (pad_len) { - if (recv(c->c_fd, pad_buf, pad_len, MSG_WAITALL) != pad_len) { - if (errno == ECONNRESET) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x dataout_delayed -- " - "initiator reset socket\n", c->c_num); - } else { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x Pad Word read errno=%d\n", c->c_num, - errno); - } - - (void) pthread_mutex_lock(&c->c_mutex); - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - conn_state(c, T8); - return (True); - } - } - - if (c->c_data_digest == True) { - if (recv(c->c_fd, (char *)&crc_actual, sizeof (crc_actual), - MSG_WAITALL) != sizeof (crc_actual)) { - if (errno == ECONNRESET) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x dataout_delayed -- " - "initiator reset socket\n", c->c_num); - } else { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x CRC32 read errno=%d\n", c->c_num, - errno); - } - - (void) pthread_mutex_lock(&c->c_mutex); - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - conn_state(c, T8); - return (True); - } - crc_calc = iscsi_crc32c((void *)cmd->c_data, dlen); - if (crc_calc != crc_actual) { - - (void) snprintf(debug, sizeof (debug), - "CON%x CRC Error: actual %x vs. calc 0x%x", - c->c_num, crc_actual, crc_calc); - - /* - * NOTE: Need to think about this one some more. - * Just because we get a data error doesn't mean - * we should drop the connection. Look at the - * spec and determine what's the appropriate - * error recovery for this issue. - */ - (void) pthread_mutex_lock(&c->c_mutex); - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - iscsi_cmd_free(c, cmd); - (void) pthread_mutex_unlock(&c->c_mutex); - conn_state(c, T8); - return (True); - } - } - - /* - * We'll update the offset with the amount of data that - * has been received. During a SCSI response PDU this value - * will be used to determine if there's an overrun condition. - */ - cmd->c_offset_out += dlen; - - (void) pthread_mutex_lock(&c->c_mutex); - (void) pthread_mutex_lock(&c->c_state_mutex); - if (c->c_state == S5_LOGGED_IN) { - if ((cmd->c_state == CmdCanceled) && - (type == msg_cmd_data_out)) - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - else - queue_message_set(c->c_sessq, 0, type, (void *)cmd); - } else if (cmd->c_state == CmdCanceled) { - t10_cmd_shoot_event(cmd->c_t10_cmd, T10_Cmd_T5); - } - (void) pthread_mutex_unlock(&c->c_state_mutex); - (void) pthread_mutex_unlock(&c->c_mutex); - - /* - * The else case here is if we're calling STE directly and the data - * will be read from the socket when STE is ready for it. - */ - - return (True); -} - -/* - * []---- - * | dataout_callback -- copy data from socket to emulation buffer - * []---- - */ -void -dataout_callback(t10_cmd_t *t, char *data, size_t *xfer) -{ - iscsi_cmd_t *cmd = (iscsi_cmd_t *)T10_TRANS_ID(t); - iscsi_conn_t *c = cmd->c_allegiance; - int dlen = cmd->c_data_len; - int cc; - char pad_buf[ISCSI_PAD_WORD_LEN - 1]; - char pad_len = 0; - - pad_len = ((ISCSI_PAD_WORD_LEN - - (dlen & (ISCSI_PAD_WORD_LEN - 1))) & - (ISCSI_PAD_WORD_LEN - 1)); - - - if (T10_DATA(t) != NULL) { - assert(T10_DATA(t) == cmd->c_data); - assert(cmd->c_data_alloc == True); - free(T10_DATA(t)); - T10_DATA(t) = NULL; - cmd->c_data = NULL; - cmd->c_data_alloc = False; - return; - } - - if ((cc = recv(c->c_fd, data, dlen, MSG_WAITALL)) != dlen) { - if (errno == ECONNRESET) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x data_callback -- initiator reset socket\n", - c->c_num); - } else { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x recv(got-%d, expect-%d) errno=%d", - c->c_num, cc, dlen, errno); - } - - conn_state(c, T8); - goto finish; - } - - if (pad_len) { - if (recv(c->c_fd, pad_buf, pad_len, MSG_WAITALL) != pad_len) { - if (errno == ECONNRESET) { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x data_callback -- " - "initiator reset socket\n", c->c_num); - } else { - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x data_callback -- " - "pad read errno=%d\n", c->c_num, errno); - } - conn_state(c, T8); - goto finish; - } - } - -finish: - *xfer = cc; - /* ---- Send msg that receive side of the connection can go ---- */ - (void) sema_post(&c->c_datain); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_ffp.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_ffp.h deleted file mode 100644 index 3b17fd3e9c..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_ffp.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 _FEATURE_H -#define _FEATURE_H - -#include <sys/types.h> -#include "iscsi_conn.h" - -/* - * The number of seconds that an initiator has to respond to our - * asynchronous logout request before we just drop the connection. - */ -#define ASYNC_LOGOUT_TIMEOUT 10 - -Boolean_t iscsi_full_feature(iscsi_conn_t *c); - -uint32_t iscsi_crc32c(void *address, unsigned long length); -uint32_t iscsi_crc32c_continued(void *address, unsigned long length, - uint32_t crc); - -#endif /* _FEATURE_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.c deleted file mode 100644 index 1ca201fc40..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <strings.h> -#include <sys/types.h> -#include <stdlib.h> -#include <unistd.h> -#include <syslog.h> -#include <sys/iscsi_protocol.h> -#include <arpa/inet.h> -#include <iscsitgt_impl.h> -#include "queue.h" -#include "iscsi_conn.h" -#include "iscsi_sess.h" -#include "iscsi_login.h" -#include "iscsi_provider_impl.h" -#include "utility.h" -#include "target.h" -#include "isns_client.h" - -typedef enum auth_action { - LOGIN_NO_AUTH, - LOGIN_AUTH, - LOGIN_DROP -} auth_action_t; - -/* - * Forward declarations - */ -static iscsi_login_rsp_hdr_t *make_login_response(iscsi_conn_t *c, - iscsi_login_hdr_t *lhp); -static void send_login_reject(iscsi_conn_t *c, iscsi_login_hdr_t *lhp, - int err_code); -static Boolean_t check_for_valid_I_T(iscsi_conn_t *c); -static auth_action_t login_set_auth(iscsi_sess_t *s); - -/* - * iscsi_null_callback - This callback may be used under certain - * conditions when authenticating a target, but I'm not sure what - * we need to do here. - */ -/* ARGSUSED */ -static void -iscsi_null_callback(void *user_handle, void *message_handle, int auth_status) -{ -} - -/* - * iscsi_find_key_value - - */ -static int -iscsi_find_key_value(char *param, char *ihp, char *pdu_end, - char **value_start, char **value_end) -{ - char *str = param; - char *text = ihp; - char *value = NULL; - - if (value_start) - *value_start = NULL; - if (value_end) - *value_end = NULL; - - /* - * make sure they contain the same bytes - */ - while (*str) { - if (text >= pdu_end) { - return (0); - } - if (*text == '\0') { - return (0); - } - if (*str != *text) { - return (0); - } - str++; - text++; - } - - if ((text >= pdu_end) || - (*text == '\0') || - (*text != ISCSI_TEXT_SEPARATOR)) { - return (0); - } - - /* - * find the value - */ - value = text + 1; - - /* - * find the end of the value - */ - while ((text < pdu_end) && (*text)) - text++; - - if (value_start) - *value_start = value; - if (value_end) - *value_end = text; - - return (1); -} - -Boolean_t -iscsi_handle_login_pkt(iscsi_conn_t *c) -{ - iscsi_login_hdr_t lh; - iscsi_login_rsp_hdr_t *rsp = NULL; - Boolean_t rval = False; - IscsiAuthClient *auth_client = NULL; - char *text = NULL; - char *end = NULL; - char *text_rsp = NULL; - char debug[128]; - int debug_status = 0; - int errcode = 0; - int text_length = 0; - int keytype = 0; - int transit = 0; - int rc = 0; - auth_action_t auth_action = LOGIN_DROP; - tgt_node_t *tnode = NULL; - - if (read(c->c_fd, &lh, sizeof (lh)) != sizeof (lh)) { - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, - "Header to small"); - return (False); - } - - if ((lh.opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD) { - (void) snprintf(debug, sizeof (debug), - "CON%x Wrong OP code for state (Got 0x%x, Expected 0x%x)", - c->c_num, lh.opcode, ISCSI_OP_LOGIN_CMD); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_INVALID_REQUEST); - conn_state(c, T7); - return (True); - } - - if (ISCSI_LOGIN_COMMAND_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = &nil; - info.uip_initiator = &nil; - info.uip_lun = 0; - - info.uip_itt = lh.itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(lh.cmdsn); - info.uip_statsn = ntohl(lh.expstatsn); - info.uip_datasn = 0; - - info.uip_datalen = ntoh24(lh.dlength); - info.uip_flags = lh.flags; - - ISCSI_LOGIN_COMMAND(&info); - } - - if ((rval = session_alloc(c, lh.isid)) == False) { - conn_state(c, T7); - return (True); - } - - connection_parameters_default(c); - - c->c_cid = ntohl(lh.cid); - c->c_statsn = ntohl(lh.expstatsn); - - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - c->c_sess->s_cmdsn = ntohl(lh.cmdsn); - c->c_sess->s_seencmdsn = ntohl(lh.cmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - - /* - * Is this a new session or an attempt to add a connection to - * an existing session. - */ - if (ntohs(lh.tsid) != 0) { - - /* Multiple connections per session not handled right now */ - conn_state(c, T7); - return (True); - } - - if ((rsp = make_login_response(c, &lh)) == NULL) { - (void) snprintf(debug, sizeof (debug), - "CON%x Failed make_login_response", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - return (False); - } - /* default is ISCSI_FLAG_LOGIN_TRANSIT, not good for login */ - rsp->flags = 0; - - if ((rsp->active_version < lh.min_version) || - (rsp->active_version > lh.max_version)) { - (void) snprintf(debug, sizeof (debug), - "CON%x Version: Active %d, min %d, max %d", c->c_num, - rsp->active_version, lh.min_version, lh.max_version); - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_NO_VERSION); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - free(rsp); - return (True); - } - - if (lh.flags & ISCSI_FLAG_LOGIN_CONTINUE) { - (void) snprintf(debug, sizeof (debug), - "CON%x Continuation pkt", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_LOGIN, msg_log, debug); - } - - auth_client = - (c->c_sess->sess_auth.auth_buffers && - c->c_sess->sess_auth.num_auth_buffers) ? - (IscsiAuthClient *) c->c_sess->sess_auth.auth_buffers[0].address : - NULL; - - if (c->auth_text != NULL) - free(c->auth_text); - c->auth_text_length = 0; - - transit = lh.flags & ISCSI_FLAG_LOGIN_TRANSIT; - - switch (ISCSI_LOGIN_CURRENT_STAGE(lh.flags)) { - case ISCSI_SECURITY_NEGOTIATION_STAGE: - - /* - * Grab the parameters and create the response - * text. - */ - rval = parse_text(c, ntoh24(lh.dlength), - &text_rsp, &text_length, &errcode); - if (rval == False) { - send_login_reject(c, &lh, errcode); - (void) snprintf(debug, sizeof (debug), - "CON%x SecurityNegotiation: parse_text" - " failed", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - break; - } - - if ((rval = check_for_valid_I_T(c)) == False) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_INIT_ERR); - (void) snprintf(debug, sizeof (debug), - "CON%x SecurityNegotiation: invalid I " - "or T", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - break; - } - - auth_action = login_set_auth(c->c_sess); - - if (auth_action == LOGIN_NO_AUTH) { - rsp->flags |= ISCSI_FLAG_LOGIN_TRANSIT; - rsp->flags |= ISCSI_OP_PARMS_NEGOTIATION_STAGE; - rval = add_text(&text_rsp, &text_length, "AuthMethod", - "None"); - if (rval == False) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | - ISCSI_LOGIN_STATUS_TARGET_ERROR); - (void) snprintf(debug, sizeof (debug), - "CON%x Norm: Failed to add AuthMethod=None", - c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, - debug); - conn_state(c, T7); - } - break; - } - - if (auth_action == LOGIN_DROP) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_TGT_FORBIDDEN); - (void) snprintf(debug, sizeof (debug), - "CON%x SecurityNegotiation: access denied", - c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - rval = False; - break; - } - - if (iscsiAuthClientRecvBegin(auth_client) != - iscsiAuthStatusNoError) { - (void) snprintf(debug, sizeof (debug), "CON%x " - "login failed - authentication receive failed", - c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - break; - } - - if (iscsiAuthClientRecvTransitBit(auth_client, - transit) != iscsiAuthStatusNoError) { - (void) snprintf(debug, sizeof (debug), - "iscsi connection(%u) login failed - " - "authentication transmit failed", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - break; - } - - /* - * scan the text data - */ - text = c->auth_text; - end = text + c->auth_text_length; -more_text: - while (text && (text < end)) { - char *value = NULL; - char *value_end = NULL; - keytype = iscsiAuthKeyTypeNone; - - /* - * skip any NULs separating each text key=value pair - */ - while ((text < end) && (*text == '\0')) { - text++; - } - if (text >= end) { - break; - } - - while (iscsiAuthClientGetNextKeyType(&keytype) == - iscsiAuthStatusNoError) { - char *key = - (char *)iscsiAuthClientGetKeyName(keytype); - if ((key) && - (iscsi_find_key_value(key, text, end, - &value, &value_end))) { - (void) snprintf(debug, sizeof (debug), - "%s=%s", key, value); - queue_str(c->c_mgmtq, Q_CONN_ERRS, - msg_log, debug); - if (iscsiAuthClientRecvKeyValue( - auth_client, keytype, value) - != iscsiAuthStatusNoError) { - (void) snprintf(debug, - sizeof (debug), - "iscsi connection(%u) login" - "failed - can't accept " - "%s in security stage", - c->c_num, text); - queue_str(c->c_mgmtq, - Q_CONN_ERRS, - msg_log, debug); - } - text = value_end; - goto more_text; - } - } - } - - switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback, - (void *)c->c_sess, NULL)) { - case iscsiAuthStatusContinue: - /* - * continue sending PDUs - */ - break; - - case iscsiAuthStatusPass: - c->c_auth_pass = 1; - break; - - case iscsiAuthStatusInProgress: - /* - * this should only occur if we were authenticating the - * target, which we don't do yet, so treat this as an - * error. - */ - case iscsiAuthStatusNoError: - /* - * treat this as an error, since we should get a - * different code - */ - case iscsiAuthStatusError: - case iscsiAuthStatusFail: - default: - debug_status = 0; - - (void) iscsiAuthClientGetDebugStatus(auth_client, - &debug_status); - (void) snprintf(debug, sizeof (debug), - "iscsi connection(%u) authentication failed (%s)", - c->c_num, iscsiAuthClientDebugStatusToText( - debug_status)); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_AUTH_FAILED); - conn_state(c, T7); - rval = False; - break; - } - - if (rval == False) - break; - - keytype = iscsiAuthKeyTypeNone; - rc = iscsiAuthClientSendTransitBit(auth_client, &transit); - - /* - * see if we're ready for a stage change - */ - if (rc == iscsiAuthStatusNoError) { - if (transit) { - rsp->flags = lh.flags; - } - - } else { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_AUTH_FAILED); - (void) snprintf(debug, sizeof (debug), - "CON%x SecurityNegotiation: wants", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - rval = False; - } - - /* - * enumerate all the keys the auth code might want to send - */ - while (iscsiAuthClientGetNextKeyType(&keytype) == - iscsiAuthStatusNoError) { - int present = 0; - char *key = (char *)iscsiAuthClientGetKeyName(keytype); - int key_length = key ? strlen(key) : 0; - int pdu_length = ntoh24(rsp->dlength); - char *auth_value = NULL; - unsigned int max_length = ISCSI_DEFAULT_MAX_XMIT_SEG_LEN - - (pdu_length + key_length + 1); /* FIXME: check */ - - /* - * add the key/value pairs the auth code wants to - * send directly to the PDU, since they could in - * theory be large. - */ - if ((auth_value = (char *)malloc(max_length)) == - NULL) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | - ISCSI_LOGIN_STATUS_TARGET_ERROR); - - (void) snprintf(debug, sizeof (debug), - "CON%x Norm: Failed alloc auth_key %S=%s", - c->c_num, key, auth_value); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, - debug); - conn_state(c, T7); - rval = False; - break; - } - rc = iscsiAuthClientSendKeyValue(auth_client, keytype, - &present, auth_value, max_length); - if ((rc == iscsiAuthStatusNoError) && present) { - (void) snprintf(debug, sizeof (debug), - "key:%s, auth_value:%s\n", key, auth_value); - queue_str(c->c_mgmtq, Q_CONN_LOGIN, msg_log, - debug); - - rval = add_text(&text_rsp, &text_length, - key, auth_value); - if (rval == False) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_TARGET_ERR << - 8) | - ISCSI_LOGIN_STATUS_TARGET_ERROR); - (void) snprintf(debug, sizeof (debug), - "CON%x Norm: Failed to add %S=%s", - c->c_num, key, auth_value); - queue_str(c->c_mgmtq, Q_CONN_ERRS, - msg_log, debug); - conn_state(c, T7); - } - } - if (auth_value != NULL) - free(auth_value); - } - - break; - - case ISCSI_OP_PARMS_NEGOTIATION_STAGE: - - /* - * Gather up the parameters sent across and build a response - * based on any selection required. - */ - if ((rval = parse_text(c, ntoh24(lh.dlength), &text_rsp, - &text_length, &errcode)) == False) { - - send_login_reject(c, &lh, errcode); - (void) snprintf(debug, sizeof (debug), - "CON%x Norm: parse_text failed", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - break; - } - - /* - * If the connection hasn't passed authentication and - * it's a normal session see if this connection MUST - * have gone through authentication first. If the - * initiator has a CHAP secret stored that means we - * want to validate. - */ - if ((c->c_auth_pass == 0) && - (c->c_sess->s_type == SessionNormal)) { - if ((tnode = find_target_node(c->c_sess->s_t_name)) == - NULL) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | - ISCSI_LOGIN_STATUS_TARGET_ERROR); - (void) snprintf(debug, sizeof (debug), - "CON%x No target node in login", - c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, - debug); - conn_state(c, T7); - } - - /* - * check_access will return True if the initiator - * is required to use CHAP authentication. So if - * true and we're here it means that the initiator - * is trying to skip the authentication step. - */ - if (check_access(tnode, c->c_sess->s_i_name, True) == - False) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_AUTH_FAILED); - (void) snprintf(debug, sizeof (debug), - "CON%x Authentication required for %s", - c->c_num, c->c_sess->s_i_name); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, - debug); - conn_state(c, T7); - } - } - - if ((rval = check_for_valid_I_T(c)) == False) { - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_INIT_ERR); - - (void) snprintf(debug, sizeof (debug), - "CON%x Norm: bad I or T", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - conn_state(c, T7); - break; - } - - /* - * We accept transition and stage information as is - * and echo it back because at this point there's no need - * to send a parameter to the Initiator and expect a - * reply. - */ - rsp->flags = lh.flags; - - break; - - case ISCSI_FULL_FEATURE_PHASE: - /* can't jump directly to full feature phase */ - (void) snprintf(debug, sizeof (debug), - "CON%x Protocol error: wrong stage", c->c_num); - queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug); - send_login_reject(c, &lh, - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_INIT_ERR); - conn_state(c, T7); - rval = False; - break; - - default: - /* just drop the connection since we don't know what's up */ - rval = False; - break; - } - - hton24(rsp->dlength, text_length); - if ((rval == True) && (session_validate(c->c_sess) == True)) { - - if (ISCSI_LOGIN_RESPONSE_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = &nil; - info.uip_initiator = c->c_sess->s_i_name; - info.uip_lun = 0; - - info.uip_itt = rsp->itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(rsp->expcmdsn); - info.uip_statsn = ntohl(rsp->statsn); - info.uip_datasn = 0; - - info.uip_datalen = text_length; - info.uip_flags = rsp->flags; - - ISCSI_LOGIN_RESPONSE(&info); - } - - send_iscsi_pkt(c, (iscsi_hdr_t *)rsp, text_rsp); - - if ((lh.flags & ISCSI_FLAG_LOGIN_TRANSIT) && - (ISCSI_LOGIN_NEXT_STAGE(lh.flags) == - ISCSI_FULL_FEATURE_PHASE)) { - - conn_state(c, T5); - - /* - * At this point we've completed the negotiation - * of all login parameters. Now we need to perform - * some quick boundary checks and then send a couple - * pieces of information to STE for it's use. - */ - c->c_max_burst_len = MIN(c->c_max_burst_len, - c->c_max_recv_data); - } - } - - if (text_rsp != NULL) - free(text_rsp); - if (rsp != NULL) - free(rsp); - - return (rval); -} - -/* - * check_for_valid_I_T -- check to see if we have valid names - * - * This routine checks to see if we have received a valid InitiatorName - * and TargetName which is the bare minimum which an Initiator must send - * across during the login phase. - */ -static Boolean_t -check_for_valid_I_T(iscsi_conn_t *c) -{ - iscsi_sess_t *s = c->c_sess; - if (s->s_type == SessionDiscovery) - return (s->s_i_name == NULL || strlen(s->s_i_name) == 0) ? - False : True; - else - return (s->s_t_name == NULL || strlen(s->s_t_name) == 0) || - (s->s_i_name == NULL || strlen(s->s_i_name) == 0) ? - False : True; -} - -static iscsi_login_rsp_hdr_t * -make_login_response(iscsi_conn_t *c, iscsi_login_hdr_t *lhp) -{ - iscsi_login_rsp_hdr_t *r; - - if (lhp->tsid != 0) - /* don't except existing sessions for now */ - return (NULL); - - r = (iscsi_login_rsp_hdr_t *)calloc(sizeof (*r), sizeof (char)); - if (r == NULL) - return (NULL); - - bcopy(lhp->isid, r->isid, 6); /* 6 is defined by protocol */ - r->opcode = ISCSI_OP_LOGIN_RSP; - r->flags = ISCSI_FLAG_LOGIN_TRANSIT; - r->max_version = ISCSI_MAX_VERSION; - r->active_version = ISCSI_MIN_VERSION; - r->itt = lhp->itt; - - /* - * As per section 10.13.3 of iSCSI RFC (3720), For a new session, - * the target MUST generate a non-zero TSIH and ONLY return it - * in the Login Final-Response - */ - if ((lhp->flags & ISCSI_FLAG_LOGIN_TRANSIT) && - (ISCSI_LOGIN_NEXT_STAGE(lhp->flags) == - ISCSI_FULL_FEATURE_PHASE)) - /* - * If this is the final Login Response, send the target - * calculated TSIH - */ - r->tsid = htons(c->c_sess->s_tsid); - else - /* - * If this is not the final Login Response, send the TSIH value - * provided by the initiator. - */ - r->tsid = lhp->tsid; - - (void) pthread_mutex_lock(&c->c_mutex); - r->statsn = htonl(c->c_statsn++); - (void) pthread_mutex_unlock(&c->c_mutex); - if (c->c_sess != NULL) { - (void) pthread_mutex_lock(&c->c_sess->s_mutex); - /* ---- cmdsn is not advanced during login ---- */ - r->expcmdsn = htonl(c->c_sess->s_seencmdsn); - r->maxcmdsn = htonl(CMD_MAXOUTSTANDING + - c->c_sess->s_seencmdsn); - (void) pthread_mutex_unlock(&c->c_sess->s_mutex); - } - - return (r); -} - -static void -send_login_reject(iscsi_conn_t *c, iscsi_login_hdr_t *lhp, int err_code) -{ - iscsi_login_rsp_hdr_t *r; - - if ((r = make_login_response(c, lhp)) == NULL) - return; - - r->status_class = (err_code >> 8) & 0xff; - r->status_detail = err_code & 0xff; - - if (ISCSI_LOGIN_RESPONSE_ENABLED()) { - uiscsiproto_t info; - char nil = '\0'; - - info.uip_target_addr = &c->c_target_sockaddr; - info.uip_initiator_addr = &c->c_initiator_sockaddr; - - info.uip_target = &nil; - info.uip_initiator = &nil; - info.uip_lun = 0; - - info.uip_itt = r->itt; - info.uip_ttt = ISCSI_RSVD_TASK_TAG; - - info.uip_cmdsn = ntohl(r->expcmdsn); - info.uip_statsn = ntohl(r->statsn); - info.uip_datasn = 0; - - info.uip_datalen = ntoh24(r->dlength); - info.uip_flags = r->flags; - - ISCSI_LOGIN_RESPONSE(&info); - } - - (void) write(c->c_fd, r, sizeof (*r)); - free(r); -} - -static auth_action_t -login_set_auth(iscsi_sess_t *s) -{ - tgt_node_t *xnInitiator = NULL; - tgt_node_t *xnTarget = NULL; - tgt_node_t *xnAcl = NULL; - char *szIniAlias = NULL; - char *szIscsiName = NULL; - char *szChapName = NULL; - char *szChapSecret = NULL; - char *possible = NULL; - iscsi_auth_t *sess_auth = &(s->sess_auth); - int comp = 0; - int username_len = 0; - - bzero(sess_auth->username_in, sizeof (sess_auth->username_in)); - bzero(sess_auth->password_in, sizeof (sess_auth->password_in)); - sess_auth->password_length_in = 0; - - /* Load alias, iscsi-name, chap-name, chap-secret from config file */ - while ((xnInitiator = tgt_node_next_child(main_config, XML_ELEMENT_INIT, - xnInitiator)) != NULL) { - - (void) tgt_find_value_str(xnInitiator, XML_ELEMENT_INIT, - &szIniAlias); - - if (tgt_find_value_str(xnInitiator, XML_ELEMENT_INAME, - &szIscsiName) == True) { - - comp = strcmp(s->s_i_name, szIscsiName); - free(szIscsiName); - szIscsiName = NULL; - - if (comp == 0) { - - if (tgt_find_value_str(xnInitiator, - XML_ELEMENT_CHAPNAME, - &szChapName) == True) { - /*CSTYLED*/ - (void) strcpy( - (char *)sess_auth->username_in, - szChapName); - username_len = strlen(szChapName); - free(szChapName); - } - - if (tgt_find_value_str(xnInitiator, - XML_ELEMENT_CHAPSECRET, - &szChapSecret) == True) { - /*CSTYLED*/ - (void) strcpy( - (char *)sess_auth->password_in, - szChapSecret); - sess_auth->password_length_in = - strlen(szChapSecret); - free(szChapSecret); - } - break; - } - } - } - - if (s->s_type == SessionDiscovery) { - return (LOGIN_NO_AUTH); - } - - if (s->s_t_name == NULL) { - /* - * Should not happen for non-discovery session - */ - return (LOGIN_DROP); - } - - /* - * If iSNS enabled set LOGIN_AUTH - */ - if (isns_enabled() == True) { - if (username_len == 0) - return (LOGIN_NO_AUTH); - return (LOGIN_AUTH); - } - - /* - * If no acc_list for current target - * If no CHAP secret for the initiator, transit. - * If CHAP secret exists for the initiator, it must be authed. - * If acc_list exists for the target, and - * If the initiator not in the list, drop it. - * If the initiator in the list, and - * If no CHAP name for the initiator, transit. - * If a CHAP name exists for the initiator, it must be authed. - */ - - while ((xnTarget = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - xnTarget)) != NULL) { - - if ((tgt_find_value_str(xnTarget, XML_ELEMENT_INAME, - &szIscsiName) == False) || (szIscsiName == NULL)) { - return (LOGIN_DROP); - } - - comp = strcmp(szIscsiName, s->s_t_name); - free(szIscsiName); - szIscsiName = NULL; - - if (comp == 0) { - - if ((xnAcl = tgt_node_next(xnTarget, - XML_ELEMENT_ACLLIST, 0)) == NULL) { - /* - * No acl_list found, return auth or no auth - */ - if (username_len == 0) - return (LOGIN_NO_AUTH); - return (LOGIN_AUTH); - } - - /* - * This target has an access_list. Now compare - * those entries against the initiator who started - * this session. - */ - xnInitiator = NULL; - while ((xnInitiator = tgt_node_next(xnAcl, - XML_ELEMENT_INIT, xnInitiator)) != NULL) { - - if ((tgt_find_value_str(xnInitiator, - XML_ELEMENT_INIT, &possible) == False) || - (possible == NULL)) - continue; - - if (strcmp(szIniAlias, possible) == 0) { - /* - * Found the initiator in acl-list, - * authentication needed - */ - free(possible); - if (username_len == 0) - return (LOGIN_NO_AUTH); - else - return (LOGIN_AUTH); - } - - free(possible); - possible = NULL; - } - /* - * Acl-list exists, while the initiator is not found in - * the list, we should drop the connection - */ - return (LOGIN_DROP); - } - } - - /* False means Need authentication */ - return (LOGIN_AUTH); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.h deleted file mode 100644 index 846b23521e..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _LOGIN_H -#define _LOGIN_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -Boolean_t iscsi_handle_login_pkt(iscsi_conn_t *c); - -#ifdef __cplusplus -} -#endif - -#endif /* _LOGIN_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_provider.d b/usr/src/cmd/iscsi/iscsitgtd/iscsi_provider.d deleted file mode 100644 index 66eeaa03e2..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_provider.d +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -typedef struct uiscsiproto { - int dummy; -} uiscsiproto_t; - -typedef struct conninfo { - int dummy; -} conninfo_t; - -typedef struct iscsiinfo { - int dummy; -} iscsiinfo_t; - -translator conninfo_t < uiscsiproto_t *P > { - dummy = P->dummy; -}; - -translator iscsiinfo_t < uiscsiproto_t *P > { - dummy = P->dummy; -}; - -typedef struct uiscsicmd { - int dummy; -} uiscsicmd_t; - -typedef struct iscsicmd { - int dummy; -} iscsicmd_t; - -translator iscsicmd_t < uiscsicmd_t *P > { - dummy = P->dummy; -}; - -provider iscsi { - probe async__send(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe login__command(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe login__response(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe logout__command(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe logout__response(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe data__receive(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe data__request(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe data__send(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe nop__receive(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe nop__send(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe scsi__command(uiscsiproto_t *i, uiscsicmd_t *c) : - (conninfo_t *i, iscsiinfo_t *i, iscsicmd_t *c); - probe scsi__response(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe task__command(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe task__response(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - - probe text__command(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); - probe text__response(uiscsiproto_t *i) : - (conninfo_t *i, iscsiinfo_t *i); -}; - -#pragma D attributes Evolving/Evolving/ISA provider iscsi provider -#pragma D attributes Private/Private/Unknown provider iscsi module -#pragma D attributes Private/Private/Unknown provider iscsi function -#pragma D attributes Private/Private/ISA provider iscsi name -#pragma D attributes Evolving/Evolving/ISA provider iscsi args diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_provider_impl.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_provider_impl.h deleted file mode 100644 index c7e41d68cd..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_provider_impl.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _ISCSI_PROVIDER_IMPL_H -#define _ISCSI_PROVIDER_IMPL_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/socket_impl.h> -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct sockaddr_storage uiscsicn_t; - -typedef struct uiscsiproto { - struct sockaddr_storage *uip_target_addr; /* target address */ - struct sockaddr_storage *uip_initiator_addr; /* initiator address */ - char *uip_target; /* target IQN */ - char *uip_initiator; /* initiator IQN */ - uint64_t uip_lun; /* target logical unit number */ - - uint32_t uip_itt; /* initiator task tag */ - uint32_t uip_ttt; /* target transfer tag */ - - uint32_t uip_cmdsn; /* command sequence number */ - uint32_t uip_statsn; /* status sequence number */ - uint32_t uip_datasn; /* data sequence number */ - - uint32_t uip_datalen; /* length of data payload */ - uint32_t uip_flags; /* probe-specific flags */ -} uiscsiproto_t; - -typedef struct uiscsicmd { - uint64_t uic_len; /* CDB length */ - uint8_t *uic_cdb; /* CDB data */ -} uiscsicmd_t; - -#ifdef __cplusplus -} -#endif - -#include "iscsi_provider.h" - -#endif /* _ISCSI_PROVIDER_IMPL_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c deleted file mode 100644 index 63a14288c8..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - * 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. - */ - -#include <stdio.h> -#include <assert.h> -#include <sys/types.h> -#include <stdlib.h> -#include <strings.h> -#include <syslog.h> - -#include <iscsitgt_impl.h> -#include "iscsi_conn.h" -#include "iscsi_sess.h" -#include "t10.h" -#include "utility.h" -#include "target.h" - -pthread_mutex_t sess_mutex; -/* - * This value is used as the TSIH which must be non-zero. - */ -int sess_num = 1; -iscsi_sess_t *sess_head; - -static void session_free(struct iscsi_sess *s); -static void sess_set_auth(iscsi_sess_t *isp); -static void *sess_from_t10(void *v); -static void *sess_process(void *v); - -/* - * []---- - * | session_init -- initialize global variables and mutexs - * []---- - */ -void -session_init() -{ - (void) pthread_mutex_init(&sess_mutex, NULL); -} - -/* - * []---- - * | session_alloc -- create a new session attached to the lead connection - * []---- - */ -Boolean_t -session_alloc(iscsi_conn_t *c, uint8_t *isid) -{ - iscsi_sess_t *s, *n; - - if (c->c_sess != NULL) - return (True); - - s = (iscsi_sess_t *)calloc(sizeof (iscsi_sess_t), 1); - if (s == NULL) - return (False); - - bcopy(isid, s->s_isid, 6); - - (void) pthread_mutex_init(&s->s_mutex, NULL); - c->c_sess = s; - s->s_conn_head = c; - s->s_sessq = queue_alloc(); - s->s_t10q = queue_alloc(); - c->c_sessq = s->s_sessq; - s->s_mgmtq = c->c_mgmtq; - s->s_type = SessionNormal; - - sess_set_auth(s); - - (void) pthread_mutex_lock(&sess_mutex); - s->s_num = sess_num++; - s->s_tsid = s->s_num; - s->s_state = SS_STARTED; - - if (sess_head == NULL) - sess_head = s; - else { - for (n = sess_head; n->s_next; n = n->s_next) - ; - n->s_next = s; - } - (void) pthread_mutex_unlock(&sess_mutex); - - (void) pthread_create(&s->s_thr_id_t10, NULL, sess_from_t10, s); - (void) pthread_create(&s->s_thr_id_conn, NULL, sess_process, s); - - util_title(s->s_mgmtq, Q_SESS_LOGIN, s->s_num, "Start Session"); - - return (True); -} - -/* - * []---- - * | session_free -- remove connection from session - * []---- - */ -static void -session_free(iscsi_sess_t *s) -{ - iscsi_sess_t *n; - - /* - * Early errors in connection setup can still call this routine - * which means the session hasn't been called. - */ - if (s == NULL) - return; - - (void) pthread_mutex_lock(&sess_mutex); - if (s->s_i_name) - free(s->s_i_name); - if (s->s_t_name) - free(s->s_t_name); - if (s->s_i_alias) - free(s->s_i_alias); - - if (sess_head == s) - sess_head = s->s_next; - else { - for (n = sess_head; n; n = n->s_next) { - if (n->s_next == s) { - n->s_next = s->s_next; - break; - } - } - if (n == NULL) { - queue_prt(s->s_mgmtq, Q_SESS_ERRS, - "SES%x NOT IN SESSION LIST!\n", s->s_num); - } - } - (void) pthread_mutex_unlock(&sess_mutex); -} - -/* - * []---- - * | session_remove_connection -- removes conn from sess list - * | - * | Returns True if this was the last connection which is always the case - * | for now. In the future with multiple connections per session it'll be - * | different. - * []---- - */ -/*ARGSUSED*/ -static Boolean_t -session_remove_connection(iscsi_sess_t *s, iscsi_conn_t *c) -{ - bzero(s->s_isid, 6); - return (True); -} - -/* - * []---- - * | convert_i_local -- Return a local name for the initiator if avilable. - * | - * | NOTE: If this routine returns true, it's the callers responsibility - * | to free the memory. - * []---- - */ -Boolean_t -convert_i_local(char *ip, char **rtn) -{ - tgt_node_t *inode = NULL; - char *iname, *name; - - while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, - inode)) != NULL) { - if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &iname) == - False) { - continue; - } - if (strcmp(iname, ip) == 0) { - if (tgt_find_value_str(inode, XML_ELEMENT_INIT, - &name) == False) { - free(iname); - return (False); - } else - free(iname); - *rtn = name; - return (True); - } else - free(iname); - } - return (False); -} - -/* - * []---- - * | sess_from_t10 -- handle messages from the T10 layer - * []---- - */ -void * -sess_from_t10(void *v) -{ - iscsi_sess_t *s = (iscsi_sess_t *)v; - msg_t *m; - Boolean_t process = True; - t10_conn_shutdown_t t_c_s; - Boolean_t sent_wait_for_destroy = False; - - t_c_s.t10_to_conn_q = NULL; - t_c_s.conn_to_t10_q = NULL; - - while (process == True) { - m = queue_message_get(s->s_t10q); - switch (m->msg_type) { - case msg_cmd_data_rqst: - queue_message_set(s->s_conn_head->c_dataq, 0, - msg_cmd_data_rqst, m->msg_data); - break; - - case msg_cmd_data_in: - queue_message_set(s->s_conn_head->c_dataq, 0, - msg_cmd_data_in, m->msg_data); - break; - - case msg_cmd_cmplt: - queue_message_set(s->s_conn_head->c_dataq, 0, - msg_cmd_cmplt, m->msg_data); - break; - - case msg_shutdown_rsp: - - if (s->s_t10) { - if (!sent_wait_for_destroy) { - if (t_c_s.t10_to_conn_q == NULL) { - t_c_s.t10_to_conn_q = - queue_alloc(); - if (t_c_s.t10_to_conn_q - == NULL) { - queue_message_set( - s->s_t10q, 0, - msg_shutdown_rsp, - m->msg_data); - break; - } - } - if (t_c_s.conn_to_t10_q == NULL) { - t_c_s.conn_to_t10_q = - queue_alloc(); - if (t_c_s.conn_to_t10_q == - NULL) { - queue_message_set( - s->s_t10q, 0, - msg_shutdown_rsp, - m->msg_data); - break; - } - } - queue_message_set( - s->s_conn_head->c_dataq, 0, - msg_wait_for_destroy, - (void *)&t_c_s); - queue_message_free(queue_message_get( - t_c_s.conn_to_t10_q)); - sent_wait_for_destroy = True; - } - - if (t10_handle_destroy(s->s_t10, False) != 0) { - /* - * Destroy couldn't complete, - * put the message back on our - * own queue to be picked up - * later and tried again. - */ - queue_message_set(s->s_t10q, 0, - msg_shutdown_rsp, - m->msg_data); - break; - } - s->s_t10 = NULL; - queue_message_set(t_c_s.t10_to_conn_q, - 0, 1, (void *)NULL); - queue_message_free(queue_message_get( - t_c_s.conn_to_t10_q)); - queue_free(t_c_s.t10_to_conn_q, NULL); - queue_free(t_c_s.conn_to_t10_q, NULL); - sent_wait_for_destroy = False; - } - - (void) pthread_mutex_lock(&s->s_mutex); - s->s_state = SS_SHUTDOWN_CMPLT; - (void) pthread_mutex_unlock(&s->s_mutex); - - session_free(s); - - /* - * Let the connection, which is the last, know - * about our completion of the shutdown. - */ - queue_message_set(s->s_conn_head->c_dataq, 0, - msg_shutdown_rsp, (void *)True); - process = False; - s->s_state = SS_FREE; - break; - - default: - queue_prt(s->s_mgmtq, Q_SESS_ERRS, - "SES%x Unknown msg type (%d) from T10\n", - s->s_num, m->msg_type); - queue_message_set(s->s_conn_head->c_dataq, 0, - m->msg_type, m->msg_data); - break; - } - queue_message_free(m); - } - queue_message_set(s->s_mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - queue_free(s->s_t10q, NULL); - util_title(s->s_mgmtq, Q_SESS_LOGIN, s->s_num, "End Session"); - free(s); - return (NULL); -} - -/* - * []---- - * | sess_process -- handle messages from the connection(s) - * []---- - */ -static void * -sess_process(void *v) -{ - iscsi_sess_t *s = (iscsi_sess_t *)v; - iscsi_conn_t *c; - iscsi_cmd_t *cmd; - msg_t *m; - Boolean_t process = True; - mgmt_request_t *mgmt; - name_request_t *nr; - t10_cmd_t *t10_cmd; - char **buf, local_buf[16]; - int lun; - extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer); - - (void) pthread_mutex_lock(&s->s_mutex); - s->s_state = SS_RUNNING; - (void) pthread_mutex_unlock(&s->s_mutex); - do { - m = queue_message_get(s->s_sessq); - switch (m->msg_type) { - case msg_cmd_send: - cmd = (iscsi_cmd_t *)m->msg_data; - if (s->s_t10 == NULL) { - - /* - * The value of 0x960 comes from T10. - * See SPC-4, revision 1a, section 6.4.2, - * table 87 - * - * XXX Need to rethink how I should do - * the callback. - */ - s->s_t10 = t10_handle_create( - s->s_t_name, s->s_i_name, T10_TRANS_ISCSI, - s->s_conn_head->c_tpgt, - s->s_conn_head->c_max_burst_len, - s->s_t10q, dataout_callback); - } - if (t10_cmd_create(s->s_t10, cmd->c_lun, cmd->c_scb, - cmd->c_scb_len, (transport_t)cmd, - &t10_cmd) == False) { - - /* - * If the command create failed, the T10 layer - * will attempt to create a sense buffer - * telling the initiator what went wrong. If - * that layer was unable to accomplish that - * things are really bad and we need to just - * close the connection. - */ - if (t10_cmd != NULL) { - queue_message_set( - cmd->c_allegiance->c_dataq, - 0, msg_cmd_cmplt, t10_cmd); - } else { - queue_prt(s->s_mgmtq, Q_SESS_ERRS, - "SES%x FAILED to create cmd\n", - s->s_num); - conn_state(cmd->c_allegiance, T11); - } - } else { - (void) pthread_mutex_lock( - &cmd->c_allegiance->c_mutex); - if (cmd->c_state != CmdCanceled) { - cmd->c_t10_cmd = t10_cmd; - (void) t10_cmd_send(s->s_t10, - cmd->c_t10_cmd, cmd->c_data, - cmd->c_data_len); - } else { - t10_cmd_shoot_event(t10_cmd, - T10_Cmd_T6); - } - (void) pthread_mutex_unlock( - &cmd->c_allegiance->c_mutex); - } - break; - - case msg_cmd_data_out: - cmd = (iscsi_cmd_t *)m->msg_data; - if (s->s_t10 != NULL) - (void) t10_cmd_data(s->s_t10, cmd->c_t10_cmd, - cmd->c_offset_out, cmd->c_data, - cmd->c_data_len); - break; - - case msg_targ_inventory_change: - if (s->s_t10 != NULL) - (void) t10_task_mgmt(s->s_t10, InventoryChange, - 0, 0); - break; - - case msg_lu_capacity_change: - lun = (int)(uintptr_t)m->msg_data; - if (s->s_t10 != NULL) - (void) t10_task_mgmt(s->s_t10, CapacityChange, - lun, 0); - break; - - case msg_reset_targ: - if (s->s_t10 != NULL) - (void) t10_task_mgmt(s->s_t10, ResetTarget, - 0, 0); - break; - - case msg_reset_lu: - if (s->s_t10 != NULL) - (void) t10_task_mgmt(s->s_t10, ResetLun, - (int)(uintptr_t)m->msg_data, 0); - break; - - case msg_shutdown: - (void) pthread_mutex_lock(&s->s_mutex); - s->s_state = SS_SHUTDOWN_START; - (void) pthread_mutex_unlock(&s->s_mutex); - - /* - * Shutdown rquest comming from a connection. Only - * shutdown the STE if this is the last connection - * for this session. - */ - c = (iscsi_conn_t *)m->msg_data; - if (session_remove_connection(s, c) == True) { - queue_prt(s->s_mgmtq, Q_SESS_NONIO, - "SES%x Starting shutdown\n", s->s_num); - - /* - * If this is the last connection for this - * session send a message to the SAM-3 layer to - * shutdown. - */ - if (s->s_t10 != NULL) { - t10_handle_disable(s->s_t10); - } - /* - * Do all work using the session pointer before - * sending the shutdown response msg. The - * session struct can get freed by the thread - * that picks up and handles the shutdown - * response. - */ - queue_message_set(s->s_mgmtq, 0, - msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - queue_message_set(s->s_t10q, 0, - msg_shutdown_rsp, 0); - process = False; - } else { - - /* - * Since this isn't the last connection for - * the session, acknowledge the connection - * request now since it's references from - * this session have been removed. - */ - queue_message_set(c->c_dataq, 0, - msg_shutdown_rsp, (void *)False); - } - break; - - case msg_initiator_name: - nr = (name_request_t *)m->msg_data; - s->s_i_name = strdup(nr->nr_name); - - /* - * Acknowledge the request by sending back an empty - * message. - */ - queue_message_set(nr->nr_q, 0, msg_initiator_name, 0); - break; - - case msg_initiator_alias: - nr = (name_request_t *)m->msg_data; - s->s_i_alias = strdup(nr->nr_name); - - /* - * Acknowledge the request by sending back an empty - * message. - */ - queue_message_set(nr->nr_q, 0, msg_initiator_alias, 0); - break; - - case msg_target_name: - nr = (name_request_t *)m->msg_data; - s->s_t_name = strdup(nr->nr_name); - - /* - * Acknowledge the request by sending back an empty - * message. - */ - queue_message_set(nr->nr_q, 0, msg_target_name, 0); - break; - - case msg_mgmt_rqst: - mgmt = (mgmt_request_t *)m->msg_data; - m->msg_data = NULL; - - (void) pthread_mutex_lock(&mgmt->m_resp_mutex); - buf = mgmt->m_u.m_resp; - - if ((s->s_type == SessionNormal) && - (mgmt->m_request == mgmt_full_phase_statistics) && - (strcmp(s->s_t_name, mgmt->m_targ_name) == 0)) { - - tgt_buf_add_tag(buf, XML_ELEMENT_CONN, - Tag_Start); - tgt_buf_add_tag(buf, s->s_i_name, Tag_String); - if (s->s_i_alias != NULL) { - tgt_buf_add(buf, XML_ELEMENT_ALIAS, - s->s_i_alias); - } - - /* - * Need to loop through the connections - * and create one time_connected tag for - * each. This will be needed once MC/S support - * is added. - */ - (void) snprintf(local_buf, sizeof (local_buf), - "%d", - mgmt->m_time - s->s_conn_head->c_up_at); - tgt_buf_add(buf, XML_ELEMENT_TIMECON, - local_buf); - - tgt_buf_add_tag(buf, XML_ELEMENT_STATS, - Tag_Start); - - t10_targ_stat(s->s_t10, buf); - - tgt_buf_add_tag(buf, XML_ELEMENT_STATS, - Tag_End); - tgt_buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End); - } - - (void) pthread_mutex_unlock(&mgmt->m_resp_mutex); - - queue_message_set(mgmt->m_q, 0, msg_mgmt_rply, 0); - - break; - - default: - queue_prt(s->s_mgmtq, Q_SESS_ERRS, - "SES%x Unknown msg type (%d) from Connection\n", - s->s_num, m->msg_type); - break; - } - queue_message_free(m); - } while (process == True); - - queue_message_set(mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - return (NULL); -} - -/* - * []---- - * | session_validate -- do what the name says - * | - * | At this point the connection has processed the login command so that - * | we have InitiatorName and ISID at a minimum. Check to see if there - * | are other sessions which match. If so, log that one out and proceed with - * | this session. If nothing matches, then link this into a global list. - * | - * | Once we support multiple connections per session need to scan list - * | to see if other connection have the same CID. If so, log out that - * | connection. - * []---- - */ -Boolean_t -session_validate(iscsi_sess_t *s) -{ - iscsi_sess_t *check; - - queue_prt(s->s_mgmtq, Q_SESS_NONIO, - "SES%x %s ISID[%02x%02x%02x%02x%02x%02x]\n", - s->s_num, s->s_i_alias == NULL ? s->s_i_name : s->s_i_alias, - s->s_isid[0], s->s_isid[1], s->s_isid[2], - s->s_isid[3], s->s_isid[4], s->s_isid[5]); - - - /* - * SessionType=Discovery which means no target name and therefore - * this is okay. - */ - if (s->s_t_name == NULL) - return (True); - - (void) pthread_mutex_lock(&sess_mutex); - for (check = sess_head; check; check = check->s_next) { - /* - * Ignore ourselves in this check. - */ - if (check == s) - continue; - if ((check->s_t_name == NULL) || - (strcmp(check->s_t_name, s->s_t_name) != 0)) - continue; - if (strcmp(check->s_i_name, s->s_i_name) != 0) - continue; - if (check->s_conn_head->c_tpgt != s->s_conn_head->c_tpgt) - continue; - /* - * Section 5.3.5 - * Session reinstatement is the process of the initiator - * logging in with an ISID that is possible active from - * the target's perspective. Thus implicitly logging out - * the session that corresponds to the ISID and - * reinstating a new iSCSI session in its place (with the - * same ISID). - */ - if (bcmp(check->s_isid, s->s_isid, 6) == 0) { - queue_prt(s->s_mgmtq, Q_SESS_NONIO, - "SES%x Implicit shutdown\n", check->s_num); - if (check->s_conn_head->c_state == S5_LOGGED_IN) - conn_state(check->s_conn_head, T8); - else - conn_state(check->s_conn_head, T7); - break; - } - } - (void) pthread_mutex_unlock(&sess_mutex); - - return (True); -} - -/* - * []---- - * | static iscsi_sess_set_auth - - * []---- - */ -static void -sess_set_auth(iscsi_sess_t *isp) -{ - IscsiAuthClient *auth_client = NULL; - tgt_node_t *node = NULL; - - if (isp == (iscsi_sess_t *)NULL) - return; - - /* Zero out the session authentication structure */ - bzero(&isp->sess_auth, sizeof (iscsi_auth_t)); - isp->sess_auth.auth_enabled = B_TRUE; - - /* Load CHAP name */ - node = tgt_node_next_child(main_config, XML_ELEMENT_CHAPNAME, NULL); - if (node != NULL && node->x_value != NULL) { - (void) strcpy(isp->sess_auth.username, node->x_value); - } - - /* Load CHAP secret */ - node = tgt_node_next_child(main_config, XML_ELEMENT_CHAPSECRET, NULL); - if (node != NULL && node->x_value != NULL) { - (void) strcpy((char *)isp->sess_auth.password, node->x_value); - isp->sess_auth.password_length = strlen(node->x_value); - } - - /* - * Set up authentication buffers always. We don't know if - * initiator will request CHAP until later. - */ - isp->sess_auth.num_auth_buffers = 5; - isp->sess_auth.auth_buffers[0].address = - &(isp->sess_auth.auth_client_block); - isp->sess_auth.auth_buffers[0].length = - sizeof (isp->sess_auth.auth_client_block); - isp->sess_auth.auth_buffers[1].address = - &(isp->sess_auth.auth_recv_string_block); - isp->sess_auth.auth_buffers[1].length = - sizeof (isp->sess_auth.auth_recv_string_block); - isp->sess_auth.auth_buffers[2].address = - &(isp->sess_auth.auth_send_string_block); - isp->sess_auth.auth_buffers[2].length = - sizeof (isp->sess_auth.auth_send_string_block); - isp->sess_auth.auth_buffers[3].address = - &(isp->sess_auth.auth_recv_binary_block); - isp->sess_auth.auth_buffers[3].length = - sizeof (isp->sess_auth.auth_recv_binary_block); - isp->sess_auth.auth_buffers[4].address = - &(isp->sess_auth.auth_send_binary_block); - isp->sess_auth.auth_buffers[4].length = - sizeof (isp->sess_auth.auth_send_binary_block); - - if (isp->sess_auth.auth_buffers && - isp->sess_auth.num_auth_buffers) { - - auth_client = (IscsiAuthClient *)isp-> - sess_auth.auth_buffers[0].address; - - /* - * prepare for authentication - */ - if (iscsiAuthClientInit(iscsiAuthNodeTypeTarget, - isp->sess_auth.num_auth_buffers, - isp->sess_auth.auth_buffers) != - iscsiAuthStatusNoError) { - syslog(LOG_ERR, "iscsi connection login failed - " - "unable to initialize authentication\n"); - return; - } - - if (iscsiAuthClientSetVersion(auth_client, - iscsiAuthVersionRfc) != iscsiAuthStatusNoError) { - syslog(LOG_ERR, "iscsi connection login failed - " - "unable to set version\n"); - return; - } - - if (isp->sess_auth.username && - (iscsiAuthClientSetUsername(auth_client, - isp->sess_auth.username) != - iscsiAuthStatusNoError)) { - syslog(LOG_ERR, "iscsi connection login failed - " - "unable to set username\n"); - return; - } - - if (isp->sess_auth.password && - (iscsiAuthClientSetPassword(auth_client, - isp->sess_auth.password, isp->sess_auth.password_length) != - iscsiAuthStatusNoError)) { - syslog(LOG_ERR, "iscsi connection login failed - " - "unable to set password\n"); - return; - } - - /* - * FIXME: we disable the minimum size check for now - */ - if (iscsiAuthClientSetIpSec(auth_client, 1) != - iscsiAuthStatusNoError) { - syslog(LOG_ERR, "iscsi connection login failed - " - "unable to set ipsec\n"); - return; - } - - if (iscsiAuthClientSetAuthRemote(auth_client, - isp->sess_auth.auth_enabled) != iscsiAuthStatusNoError) { - syslog(LOG_ERR, "iscsi connection login failed - " - "unable to set remote authentication\n"); - return; - } - } -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h b/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h deleted file mode 100644 index 4426046117..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_sess.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SESSION_H -#define _SESSION_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/types.h> -#include <sys/iscsi_authclient.h> -#include "iscsi_cmd.h" -#include "t10.h" - -/* - * iSCSI Auth Information - */ -typedef struct iscsi_auth { - IscsiAuthStringBlock auth_recv_string_block; - IscsiAuthStringBlock auth_send_string_block; - IscsiAuthLargeBinary auth_recv_binary_block; - IscsiAuthLargeBinary auth_send_binary_block; - IscsiAuthClient auth_client_block; - int num_auth_buffers; - IscsiAuthBufferDesc auth_buffers[5]; - - /* - * To indicate if authentication is enabled. - * 0 means authentication disabled. - * 1 means authentication enabled. - */ - int auth_enabled; - - /* Initiator's authentication information. */ - char username[iscsiAuthStringMaxLength]; - uint8_t password[iscsiAuthStringMaxLength]; - int password_length; - - /* Target's authentication information. */ - char username_in[iscsiAuthStringMaxLength]; - uint8_t password_in[iscsiAuthStringMaxLength]; - int password_length_in; -} iscsi_auth_t; - -typedef enum iscsi_session_type { - SessionDiscovery, SessionNormal -} iscsi_session_type_t; - -typedef enum iscsi_session_state { - SS_FREE, SS_STARTED, SS_RUNNING, SS_SHUTDOWN_START, SS_SHUTDOWN_CMPLT -} iscsi_sess_state_t; - -typedef struct iscsi_sess { - struct iscsi_sess *s_next; - - iscsi_sess_state_t s_state; - - /* - * Set during login - * mutex isn't held. - */ - char *s_i_name, - *s_i_alias, - *s_t_name; - uint8_t s_isid[6]; - /* - * This is the highest packet number we've seen and is - * used during replies. - */ - int s_seencmdsn; - - /* - * To keep the correct order of PDU's submitted to the SCSI - * layer we check that the incoming cmdsn matches this value. - * Otherwise, we're missing a packet and need to wait. This - * is particularly important with multiple connections per - * session. - */ - int s_cmdsn; - - iscsi_session_type_t s_type; - - /* - * Set during allocation of this struct and only referenced - */ - int s_tsid; - - target_queue_t *s_sessq, - *s_t10q, - *s_mgmtq; - - t10_targ_handle_t s_t10; - - struct iscsi_conn *s_conn_head; - - int s_num; - - pthread_mutex_t s_mutex; - iscsi_auth_t sess_auth; - pthread_t s_thr_id_conn, - s_thr_id_t10; -} iscsi_sess_t; - -void session_init(); -Boolean_t session_alloc(struct iscsi_conn *c, uint8_t *isid); -Boolean_t session_validate(struct iscsi_sess *s); - -#ifdef __cplusplus -} -#endif - -#endif /* _SESSION_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/iscsi_target.xml b/usr/src/cmd/iscsi/iscsitgtd/iscsi_target.xml deleted file mode 100644 index b594134b5b..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_target.xml +++ /dev/null @@ -1,116 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> -<!-- - Copyright 2007 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. - - 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 - - ident "%Z%%M% %I% %E% SMI" - - - NOTE: This service manifest is not editable; its contents will - be overwritten by package or patch operations, including - operating system upgrade. Make customizations in a different - file. ---> - -<service_bundle type='manifest' name='SUNWiscsitgtu:iscsitgt'> - -<service - name='system/iscsitgt' - type='service' - version='1'> - - <create_default_instance enabled='false' /> - - <single_instance/> - - <!-- We need name resolution and full filesystem access --> - <dependency - name='milestone' - grouping='require_all' - restart_on='none' - type='service'> - <service_fmri value='svc:/milestone/multi-user' /> - </dependency> - - - <exec_method - type='method' - name='start' - exec='/lib/svc/method/svc-iscsitgt %m' - timeout_seconds='60'> - <method_context> - <method_credential - user='root' - group='sys' - privileges='basic,sys_config,net_rawaccess,sys_mount,file_dac_write,sys_devices,proc_setid' /> - </method_context> - </exec_method> - - <exec_method - type='method' - name='stop' - exec='/lib/svc/method/svc-iscsitgt %m %{restarter/contract}' - timeout_seconds='60'> - <method_context> - <method_credential - user='root' - group='sys' - privileges='basic,sys_config,net_rawaccess,sys_mount,file_dac_write,sys_devices,proc_setid' /> - </method_context> - </exec_method> - - <property_group name='general' type='framework'> - <propval name='action_authorization' type='astring' - value='solaris.smf.manage.iscsitgt' /> - <!-- To read and modify protected properties --> - <propval name='read_authorization' type='astring' - value='solaris.smf.read.iscsitgt' /> - <propval name='value_authorization' type='astring' - value='solaris.smf.value.iscsitgt' /> - <propval name='modify_authorization' type='astring' - value='solaris.smf.modify.iscsitgt' /> - </property_group> - - <property_group name='application' type='framework'> - <stability value='Unstable' /> - <propval name='auto_enable' type='boolean' value='true' /> - </property_group> - - <stability value='Unstable' /> - - <template> - <common_name> - <loctext xml:lang='C'> - iSCSI Target - </loctext> - </common_name> - <documentation> - <manpage title='iscsitgtd' section='1M' - manpath='/usr/share/man' /> - <manpage title='iscsitadm' section='1M' - manpath='/usr/share/man' /> - </documentation> - </template> -</service> - -</service_bundle> diff --git a/usr/src/cmd/iscsi/iscsitgtd/isns.c b/usr/src/cmd/iscsi/iscsitgtd/isns.c deleted file mode 100644 index c5548f4ac1..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/isns.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <syslog.h> -#include <ctype.h> -#include <pthread.h> -#include <netdb.h> -#include <libintl.h> -#include <errno.h> -#include <assert.h> -#include <fcntl.h> -#include <sys/byteorder.h> - -#include "isns_protocol.h" -#include "isns_client.h" -#include "queue.h" - -extern target_queue_t *mgmtq; - -static uint16_t xid = 0; -static pthread_mutex_t xid_lock = PTHREAD_MUTEX_INITIALIZER; - -/* - * more than 1 processes can accessing get_xid - */ -static uint16_t -get_xid() -{ - uint16_t tmp; - - (void) pthread_mutex_lock(&xid_lock); - tmp = xid++; - (void) pthread_mutex_unlock(&xid_lock); - return (tmp); -} - -void -ntoh_tlv(isns_tlv_t *tlv) -{ - uint32_t val; - - tlv->attr_id = ntohl(tlv->attr_id); - tlv->attr_len = ntohl(tlv->attr_len); - - switch (tlv->attr_id) { - case ISNS_DELIMITER_ATTR_ID: - break; - case ISNS_ISCSI_NAME_ATTR_ID: - case ISNS_EID_ATTR_ID: - case ISNS_ISCSI_ALIAS_ATTR_ID: - case ISNS_PORTAL_NAME_ATTR_ID: - case ISNS_PG_ISCSI_NAME_ATTR_ID: - break; - - case ISNS_PORTAL_IP_ADDR_ATTR_ID: - case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: - bcopy(tlv->attr_value, &val, 4); - *tlv->attr_value = ntohl(val); - break; - - default: - switch (tlv->attr_len) { - case 4: - val = ntohl( - (uint32_t)(*tlv->attr_value)); - bcopy(&val, tlv->attr_value, 4); - break; - default: - break; - } - break; - } -} - -/* - * print_ntoh_tlv print network byte order tag-length-value attribute - */ -void -print_ntoh_tlv(isns_tlv_t *tlv) -{ - uint32_t tag, len, val, pf_type; - char buf[256]; - struct sockaddr_in6 sin6; - - tag = ntohl(tlv->attr_id); - len = ntohl(tlv->attr_len); - - if (len == 0) { - queue_prt(mgmtq, Q_ISNS_DBG, "Zero length tag: %d\n", tag); - return; - } - - switch (tag) { - case ISNS_DELIMITER_ATTR_ID: - break; - case ISNS_ISCSI_NAME_ATTR_ID: - case ISNS_EID_ATTR_ID: - case ISNS_ISCSI_ALIAS_ATTR_ID: - case ISNS_PORTAL_NAME_ATTR_ID: - case ISNS_PG_ISCSI_NAME_ATTR_ID: - queue_prt(mgmtq, Q_ISNS_DBG, - "Tag %d: Value: %s\n", tag, tlv->attr_value); - break; - - case ISNS_PORTAL_IP_ADDR_ATTR_ID: - case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: - bcopy(tlv->attr_value, &pf_type, 4); - pf_type = ntohl(pf_type); - pf_type = (pf_type == sizeof (in6_addr_t)) - ? PF_INET6 : PF_INET; - switch (pf_type) { - case PF_INET: - /* RFC2372 IPv4 mapped IPv6 address */ - if (inet_ntop(pf_type, - (void *)&tlv->attr_value[12], - buf, 256) == NULL) { - syslog(LOG_ERR, - "inet_ntop failed"); - break; - } - queue_prt(mgmtq, Q_ISNS_DBG, - "IP_ADDR %s\n", buf); - break; - case PF_INET6: - bcopy(tlv->attr_value, &sin6, - sizeof (struct sockaddr_in6)); - (void) inet_ntop(pf_type, - (void *)&sin6.sin6_addr, - buf, 256); - break; - default: - queue_prt(mgmtq, Q_ISNS_DBG, - "unknown pf_type\n"); - break; - } - break; - - default: - switch (len) { - case 4: - bcopy(tlv->attr_value, &val, 4); - val = ntohl(val); - queue_prt(mgmtq, Q_ISNS_DBG, - "Tag: %d Value: %ld\n", tag, val); - break; - default: - break; - } - break; - } -} - -void -print_attr(isns_tlv_t *attr, void *pval, uint32_t ival) -{ - uint32_t tag = ntohl(attr->attr_id); - uint32_t len = ntohl(attr->attr_len); - uint32_t pf_type; - char buf[256]; - - queue_prt(mgmtq, Q_ISNS_DBG, "Tag: %d Length: %d\n", tag, len); - switch (tag) { - case ISNS_DELIMITER_ATTR_ID: - break; - - case ISNS_ISCSI_NAME_ATTR_ID: - case ISNS_EID_ATTR_ID: - case ISNS_ISCSI_ALIAS_ATTR_ID: - case ISNS_PORTAL_NAME_ATTR_ID: - case ISNS_PG_ISCSI_NAME_ATTR_ID: - if (len && pval != NULL) { - queue_prt(mgmtq, Q_ISNS_DBG, "Value: %s\n", - attr->attr_value); - } - break; - - case ISNS_PORTAL_IP_ADDR_ATTR_ID: - case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: - if (len) { - pf_type = (ival == sizeof (in6_addr_t)) - ? PF_INET6 : PF_INET; - (void) inet_ntop(pf_type, pval, buf, 256); - queue_prt(mgmtq, Q_ISNS_DBG, "IP_ADDR %s\n", - buf); - } - break; - - default: - switch (len) { - case 4: - queue_prt(mgmtq, Q_ISNS_DBG, - "Value: %d\n", - ntohl(*attr->attr_value)); - break; - default: - break; - } - break; - } -} - -void -print_isns_hdr(isns_hdr_t *hdr) -{ - queue_prt(mgmtq, Q_ISNS_DBG, "hdr->version %d\n", hdr->version); - queue_prt(mgmtq, Q_ISNS_DBG, "hdr->func_id %x\n", hdr->func_id); - queue_prt(mgmtq, Q_ISNS_DBG, "hdr->pdu_len %d\n", hdr->pdu_len); - queue_prt(mgmtq, Q_ISNS_DBG, "hdr->flags %x\n", hdr->flags); - queue_prt(mgmtq, Q_ISNS_DBG, "hdr->xid %d\n", hdr->xid); - queue_prt(mgmtq, Q_ISNS_DBG, "hdr->seqid %d\n", hdr->seqid); -} - -void -ntoh_isns_hdr(isns_hdr_t *hdr) -{ - hdr->version = ntohs(hdr->version); - hdr->func_id = ntohs(hdr->func_id); - hdr->pdu_len = ntohs(hdr->pdu_len); - hdr->flags = ntohs(hdr->flags); - hdr->xid = ntohs(hdr->xid); - hdr->seqid = ntohs(hdr->seqid); -} - -int -isns_append_attr(isns_pdu_t *pdu, uint32_t tag, uint32_t len, - void *pval, uint32_t ival) -{ - uint32_t val; - uint32_t pad_len; - uint16_t pdu_len; - isns_tlv_t *attr; - char *tlv; - - if (pdu == NULL) { - syslog(LOG_ALERT, "NULL PDU\n"); - return (-1); - } - - /* get current pdu payload length */ - pdu_len = ntohs(pdu->payload_len); - - /* pad 4 bytes alignment */ - pad_len = PAD4(len); - - if ((pdu_len + pad_len) > MAX_PDU_PAYLOAD_SZ) { - syslog(LOG_ALERT, "Exceeded PDU size\n"); - return (-1); - } - - if ((attr = (isns_tlv_t *)malloc(ISNS_ATTR_SZ(pad_len))) == NULL) { - syslog(LOG_ALERT, "Malloc error"); - return (-1); - } - bzero(attr, ISNS_ATTR_SZ(pad_len)); - attr->attr_id = htonl(tag); - attr->attr_len = htonl(pad_len); - - switch (tag) { - case ISNS_DELIMITER_ATTR_ID: - break; - - case ISNS_ISCSI_NAME_ATTR_ID: - case ISNS_EID_ATTR_ID: - case ISNS_ISCSI_ALIAS_ATTR_ID: - case ISNS_PORTAL_NAME_ATTR_ID: - case ISNS_PG_ISCSI_NAME_ATTR_ID: - if (len && pval != NULL) { - bcopy(pval, attr->attr_value, len); - } - break; - - case ISNS_PORTAL_IP_ADDR_ATTR_ID: - case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: - if (len && ival == sizeof (in_addr_t)) { - /* IPv4 */ - attr->attr_value[10] = 0xFF; - attr->attr_value[11] = 0xFF; - bcopy(pval, ((attr->attr_value) + 12), ival); - } else if (len && ival == sizeof (in6_addr_t)) { - /* IPv6 */ - bcopy(pval, attr->attr_value, ival); - } - break; - - default: - switch (len) { - case 4: - val = htonl(ival); - bcopy(&val, attr->attr_value, 4); - break; - default: - break; - } - break; - } - - /* copy attribute to pdu */ - tlv = (char *)pdu + ISNSP_HEADER_SIZE + pdu_len; - bcopy(attr, tlv, ISNS_ATTR_SZ(pad_len)); - pdu->payload_len = htons(pdu_len + ISNS_ATTR_SZ(pad_len)); - - /* debug only */ - print_ntoh_tlv(attr); - - free(attr); - return (0); -} - -int -isns_create_pdu(uint16_t func_id, uint32_t flags, isns_pdu_t **pdu) -{ - size_t pdu_sz = MAX_PDU_SZ; - - if ((*pdu = (isns_pdu_t *)malloc(pdu_sz)) == NULL) { - syslog(LOG_ERR, "isns_create_pdu malloc failure"); - return (-1); - } - - bzero(*pdu, pdu_sz); - (*pdu)->payload_len = 0; - (*pdu)->seq = 0; - (*pdu)->xid = htons(get_xid()); - (*pdu)->version = htons((uint16_t)ISNSP_VERSION); - (*pdu)->func_id = htons((uint16_t)(func_id)); - (*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT | - ISNS_FLAG_FIRST_PDU | ISNS_FLAG_LAST_PDU)); - return (0); -} - -void -isns_free_pdu(void *pdu) -{ - free(pdu); -} - -/* - * Desc: Open connection to the isns server - * Args: isns server name or isns server ip-addr - * Return: -1 if open failed, descriptor to socket if open succeeded - */ -int -isns_open(char *server) -{ - struct addrinfo hints, *ai, *aip; - struct sockaddr *sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - size_t sa_len; - int so; - int ret; - fd_set rfdset; - fd_set wfdset; - fd_set errfdset; - struct timeval timeout; - Boolean_t shouldsockblock = False; - int socket_ready = 0; - timeout.tv_sec = 5; /* 5 Secs Timeout */ - timeout.tv_usec = 0; /* 0 uSecs Timeout */ - - if (server == NULL) { - syslog(LOG_ERR, "ISNS server ID required"); - return (-1); - } - - bzero(&hints, sizeof (struct addrinfo)); - hints.ai_family = AF_UNSPEC; - if ((ret = getaddrinfo(server, NULL, NULL, &ai)) != 0) { - syslog(LOG_ALERT, "getaddrinfo failed on server %s: %s", server, - gai_strerror(ret)); - return (-1); - } - - aip = ai; - do { - so = socket(aip->ai_family, SOCK_STREAM, 0); - if (so != -1) { - - /* set it to non blocking so connect wont hang */ - if (setsocknonblocking(so) == -1) { - (void) close(so); - continue; - } - - sa_len = aip->ai_addrlen; - switch (aip->ai_family) { - case PF_INET: - bzero(&sin, - sizeof (struct sockaddr_in)); - sa = (struct sockaddr *)&sin; - bcopy(aip->ai_addr, sa, sa_len); - sin.sin_port = htons( - ISNS_DEFAULT_SERVER_PORT); - break; - case PF_INET6: - bzero(&sin6, - sizeof (struct sockaddr_in6)); - sa = (struct sockaddr *)&sin6; - bcopy(aip->ai_addr, sa, sa_len); - sin6.sin6_port = - htons(ISNS_DEFAULT_SERVER_PORT); - break; - default: - syslog(LOG_ALERT, "Bad protocol"); - (void) close(so); - continue; - } - - ret = connect(so, sa, sa_len); - if (ret == 0) { - /* - * connection succeeded with out - * blocking - */ - shouldsockblock = True; - } - - if (ret < 0) { - if (errno == EINPROGRESS) { - FD_ZERO(&rfdset); - FD_ZERO(&wfdset); - FD_ZERO(&errfdset); - FD_SET(so, &rfdset); - FD_SET(so, &wfdset); - FD_SET(so, &errfdset); - socket_ready = - select(so + 1, &rfdset, &wfdset, - &errfdset, &timeout); - if (socket_ready < 0) { - syslog(LOG_ALERT, - "failed to connect with" - " isns, err=%d", errno); - (void) close(so); - } else if (socket_ready == 0) { - syslog(LOG_ALERT, - "time out failed" - " to connect with isns"); - (void) close(so); - } else { /* Socket is ready */ - /* - * Check if socket is ready - */ - if (is_socket_ready(so, - &rfdset, &wfdset, - &errfdset) == True) - shouldsockblock = True; - else - (void) close(so); - } - } else { - syslog(LOG_WARNING, - "Connect failed no progress"); - (void) close(so); - } - } - - if (shouldsockblock == True) { - if (-1 == setsockblocking(so)) { - (void) close(so); - shouldsockblock = False; - } else { - freeaddrinfo(ai); - return (so); - } - } - - } - } while ((aip = aip->ai_next) != NULL); - - if (ai != NULL) - freeaddrinfo(ai); - return (-1); -} - -/* - * According to: - * UNIX Network Programming Volume 1, Third Edition: - * The Sockets Networking APIBOOK: - * - * When the connection completes successfully, the descriptor becomes - * writable (p. 531 of TCPv2). - * When the connection establishment encounters an error, the descriptor - * becomes both readable and writable (p. 530 of TCPv2). - */ -Boolean_t -is_socket_ready(int so, fd_set *rfdset, fd_set *wfdset, - fd_set *errfdset) -{ - if ((FD_ISSET(so, wfdset) && - FD_ISSET(so, rfdset)) || - FD_ISSET(so, errfdset)) { - return (False); - } else { - return (True); - } -} - -int -setsocknonblocking(int so) -{ - int flags; - /* set it to non blocking */ - if (-1 == (flags = fcntl(so, F_GETFL, 0))) { - syslog(LOG_WARNING, - "Failed to get socket flags. Blocking.."); - return (-1); - } - - if (fcntl(so, F_SETFL, flags | O_NONBLOCK) == -1) { - syslog(LOG_WARNING, - "Failed to set socket in non blocking mode"); - return (-1); - } - return (0); -} - -int -setsockblocking(int so) -{ - int flags; - /* set it to non blocking */ - if (-1 == (flags = fcntl(so, F_GETFL, 0))) { - syslog(LOG_WARNING, " Failed to get flags on socket.."); - return (-1); - } - - flags &= ~O_NONBLOCK; - if (fcntl(so, F_SETFL, flags) == -1) { - syslog(LOG_WARNING, " failed to set socket to blocking"); - return (-1); - } - return (0); -} - - -void -isns_close(int so) -{ - if (so) { - (void) close(so); - } -} - -/* - * isns_send allocated pdu, caller needs to free pdu when done processing - */ -int -isns_send(int so, isns_pdu_t *pdu) -{ - size_t len; - - assert(pdu != NULL); - - len = ISNSP_HEADER_SIZE + ntohs(pdu->payload_len); - if (send(so, pdu, len, 0) == -1) { - syslog(LOG_ALERT, "isns_send failure"); - return (-1); - } - return (0); -} - -/* - * Desc: isns_recv malloc memory for the isns response message, user needs - * to isns_free() memory after process the response message. The - * isns header is converted to host byte order, the remaining TLV - * attributes can be converted using ntoh_tlv() - */ -int -isns_recv(int so, isns_rsp_t **pdu) -{ - isns_hdr_t hdr, hdr1; - isns_rsp_t *rsp; - uint8_t *ptr; - size_t total_pdu_len; - int len; - uint16_t xid_x, func_id_x, seqid_x; - boolean_t done; - - *pdu = NULL; - total_pdu_len = 0; - seqid_x = 0; - done = FALSE; - - do { - /* read pdu header 1st */ - do { - len = recv(so, &hdr1, ISNSP_HEADER_SIZE, MSG_WAITALL); - } while ((len == -1) && (errno == EINTR)); - - if (len != ISNSP_HEADER_SIZE) { - syslog(LOG_ALERT, "isns_recv fail to read header"); - return (-1); - } - - /* normalize the pdu header for processing */ - bcopy(&hdr1, &hdr, sizeof (isns_hdr_t)); - ntoh_isns_hdr(&hdr); - - if (IS_1ST_PDU(hdr.flags)) { - if (hdr.seqid != 0) { - syslog(LOG_ALERT, "ISNS out of sequence"); - return (-1); - } - xid_x = hdr.xid; - func_id_x = hdr.func_id; - } - - if (IS_LAST_PDU(hdr.flags)) { - done = TRUE; - } - - /* verify seq, xid, func_id */ - if (seqid_x != hdr.seqid) { - syslog(LOG_ALERT, "ISNS out of sequence"); - return (-1); - } - if (xid_x != hdr.xid || func_id_x != hdr.func_id) { - syslog(LOG_ALERT, "Non matching xid or func_id"); - return (-1); - } - - ++seqid_x; /* next expected seqid */ - - /* malloc size + previous payload length */ - if ((ptr = malloc(ISNSP_HEADER_SIZE + hdr.pdu_len - + total_pdu_len)) == NULL) { - syslog(LOG_ALERT, "Malloc failure"); - return (-1); - } - bzero(ptr, ISNSP_HEADER_SIZE + hdr.pdu_len); - - if (hdr.seqid == 0) { - *pdu = (void *)ptr; - bcopy(&hdr1, ptr, ISNSP_HEADER_SIZE); - ptr += ISNSP_HEADER_SIZE; - if ((len = recv(so, ptr, hdr.pdu_len, MSG_WAITALL)) - != hdr.pdu_len) { - syslog(LOG_ERR, - "isns_recv fail to read 1st payload"); - free(*pdu); - *pdu = NULL; - return (-1); - } - } else { - /* merge the pdu */ - bcopy(*pdu, ptr, ISNSP_HEADER_SIZE + total_pdu_len); - free(*pdu); - *pdu = (void *)ptr; - ptr += (ISNSP_HEADER_SIZE + total_pdu_len); - if (recv(so, ptr, hdr.pdu_len, MSG_WAITALL) - != hdr.pdu_len) { - syslog(LOG_ERR, - "isns_recv fail to read payload"); - free(*pdu); - *pdu = NULL; - return (-1); - } - } - total_pdu_len += hdr.pdu_len; - - } while (done == FALSE); - - /* normalize the response status */ - rsp = (isns_rsp_t *)*pdu; - rsp->pdu_len = htons(total_pdu_len); - ntoh_isns_hdr((isns_hdr_t *)rsp); - - return (0); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/isns_client.c b/usr/src/cmd/iscsi/iscsitgtd/isns_client.c deleted file mode 100644 index 02b5da645b..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/isns_client.c +++ /dev/null @@ -1,1830 +0,0 @@ -/* - * 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. - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <strings.h> -#include <syslog.h> -#include <netdb.h> -#include <pthread.h> -#include <signal.h> -#include <errno.h> -#include <netinet/in.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> - -#include <iscsitgt_impl.h> - -#include "isns_protocol.h" -#include "isns_client.h" -#include "target.h" -#include "queue.h" - - -typedef struct { - uint32_t pf_family; - uint32_t ip_len; - uint32_t ai_addrlen; - union { - in_addr_t in; - in6_addr_t in6; - } ip_adr; -} ip_t; - -#define ISNS_TGT_LOGOUT 54321 - -extern target_queue_t *mgmtq; - -/* - * Global - * Parameters for ESI/SCN processing. - * scn_port: ESI/SCN port to receive ISNS_ESI & ISNS_SCN messages - * isns_args: - * eid_ip: Entity IP info - */ -static int scn_port = 0; -static esi_scn_arg_t isns_args = {{0}, {0}, 0}; -static ip_t eid_ip; -static int num_reg = 0; -static pthread_t scn_tid = 0; -static pthread_t isns_tid = 0; -static Boolean_t isns_shutdown = True; -static Boolean_t connection_thr_bail_out = False; -static int ISNS_SLEEP_SECS = 20; -Boolean_t isns_server_connection_thr_running = False; -target_queue_t *mgmtq = NULL; - -static int get_ip_addr(char *node, ip_t *sa); -static int isns_op_all(uint16_t); -static int append_tpgt(tgt_node_t *, isns_pdu_t *); -static void process_esi(int, isns_pdu_t *); -static void process_scn(int, isns_pdu_t *); -static void *esi_scn_thr(void *); -static int process_rsp(isns_pdu_t *, isns_rsp_t *); -static int isns_dev_attr_reg(int, tgt_node_t *, char *, char *); -static int isns_dev_attr_dereg(int, char *); -static int isns_scn_reg(int, char *); -static int isns_scn_dereg(int so, char *node); -static tgt_node_t *find_tgt_by_name(char *, char **); -static tgt_node_t *find_next_tgt(tgt_node_t *, char **); -static int isns_populate_and_update_server_info(Boolean_t state); -static int get_addr_family(char *node); - -/* - * find_tgt_by_name searches DB by iscsi name or local name, if found - * returns tgt_node_t. iname needs to be free by caller. - */ -static tgt_node_t * -find_tgt_by_name(char *targ, char **iname) -{ - tgt_node_t *tgt = NULL; - - while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - tgt)) != NULL) { - if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname) - == FALSE) { - syslog(LOG_ALERT, "ISNS: Missing iscsi name\n"); - break; - } - /* match either iscsi name or local name */ - if (strcmp(targ, tgt->x_value) == 0 || - strcmp(targ, *iname) == 0) { - return (tgt); - } - free(*iname); - } - return (NULL); -} - -static tgt_node_t * -find_next_tgt(tgt_node_t *tgt, char **iname) -{ - while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - tgt)) != NULL) { - if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname) - == FALSE) { - continue; - } - return (tgt); - } - return (NULL); -} - -/* - * Find ip-addr associated with TPGT, don't send if no ip-addr is - * found for a TPGT - */ -static int -append_tpgt(tgt_node_t *tgt, isns_pdu_t *cmd) -{ - tgt_node_t *t, *x; - tgt_node_t *pgt = NULL; - tgt_node_t *iplist = NULL; - tgt_node_t *tpgt = NULL; - ip_t eid; - - /* Always add the default TPGT (1) */ - (void) isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL, - 1); - if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, - eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, - eid_ip.ip_len) != 0) { - return (-1); - } - if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, iscsi_port) != 0) { - return (-1); - } - - /* Get the remainning TPGT-LIST */ - if ((t = tgt_node_next(tgt, XML_ELEMENT_TPGTLIST, NULL)) - != NULL) { - /* find tgpt from tpgt-list */ - while ((pgt = tgt_node_next(t, XML_ELEMENT_TPGT, pgt)) - != NULL) { - /* update isns only if TPGT contains ip_addr */ - while ((tpgt = tgt_node_next_child(main_config, - XML_ELEMENT_TPGT, tpgt)) != NULL) { - if (strcmp(pgt->x_value, tpgt->x_value) != 0) - continue; - if ((iplist = tgt_node_next(tpgt, - XML_ELEMENT_IPADDRLIST, NULL)) != NULL) - break; - } - if (tpgt == NULL || iplist == NULL) - continue; - if (isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, - ISNS_PG_TAG_SZ, NULL, - strtol(pgt->x_value, NULL, 0)) != 0) { - return (-1); - } - - /* get ip-addr & port */ - for (x = iplist->x_child; x; x = x->x_sibling) { - if (get_ip_addr(x->x_value, &eid) < 0) - continue; - if (isns_append_attr(cmd, - ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, - eid.ai_addrlen, (void *)&eid.ip_adr, - eid.ip_len) != 0) { - return (-1); - } - if (isns_append_attr(cmd, - ISNS_PG_PORTAL_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, iscsi_port) != 0) { - return (-1); - } - } - } - } - - return (0); -} - -/* - * process_scn() - * -Added/Updated object: nop, initiator is verified during connect - * - * -Removed object: logout_targ if still connected - * - * RFC 4171 section 5.6.5.9 - * destination attribute is always the 1st attribute in the SCN message, - * then follows by SCN_BITMAP(35) & Source_Attribute(32) - */ -static void -process_scn(int so, isns_pdu_t *scn) -{ - uint8_t *ptr = scn->payload; - isns_tlv_t *tlv; - uint16_t cnt = 0; - uint32_t got_dest = 0; - uint32_t got_source = 0; - uint32_t bitmap = 0; - uint32_t got_bitmap = 0; - char dest[MAXNAMELEN]; - char source[MAXNAMELEN]; - - queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u\n", - scn->payload_len); - - if (scn->payload_len < TAG_LEN_SZ) { - syslog(LOG_ALERT, "ISNS SCN message error\n"); - return; - } - - while (cnt < scn->payload_len) { - /* LINTED */ - tlv = (isns_tlv_t *)ptr; - tlv->attr_id = ntohl(tlv->attr_id); - tlv->attr_len = ntohl(tlv->attr_len); - queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u %u\n", - tlv->attr_id, tlv->attr_len); - /* - * devAttrQry the source attribute, process if node_type - * is initiator - */ - switch (tlv->attr_id) { - case ISNS_ISCSI_NAME_ATTR_ID: - if (got_dest == 0) { - bcopy(tlv->attr_value, dest, - tlv->attr_len); - queue_prt(mgmtq, Q_ISNS_DBG, - "PROCESS_SCN dest %s\n", dest); - got_dest = 1; - } else { - bcopy(tlv->attr_value, source, - tlv->attr_len); - queue_prt(mgmtq, Q_ISNS_DBG, - "PROCESS_SCN source %s\n", source); - got_source = 1; - } - break; - case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: - bcopy(tlv->attr_value, &bitmap, tlv->attr_len); - bitmap = ntohl(bitmap); - queue_prt(mgmtq, Q_ISNS_DBG, - "PROCESS_SCN bitmap %u\n", bitmap); - got_bitmap = 1; - break; - default: - queue_prt(mgmtq, Q_ISNS_DBG, - "PROCESS_SCN DEFAULT\n"); - break; - } - - if (got_source && !got_bitmap) { - queue_prt(mgmtq, Q_ISNS_DBG, - "process_scn: message out-of-order\n"); - return; - } - - if (got_source && got_bitmap) { - switch (bitmap) { - case ISNS_OBJ_ADDED: - case ISNS_OBJ_UPDATED: - queue_prt(mgmtq, Q_ISNS_DBG, - "PROCESS_SCN OBJ ADDED"); - (void) isns_update(); - break; - case ISNS_OBJ_REMOVED: - queue_prt(mgmtq, Q_ISNS_DBG, - "PROCESS_SCN OBJ REMOVED"); - /* logout target */ - if (got_dest == 0) { - syslog(LOG_ALERT, - "ISNS protocol error\n"); - continue; - } - logout_targ(dest); - break; - default: - break; - } - - /* clear got_xxx */ - got_source = 0; - got_bitmap = 1; - } - - /* next attribute */ - cnt += ISNS_ATTR_SZ(tlv->attr_len); - ptr += ISNS_ATTR_SZ(tlv->attr_len); - } - queue_prt(mgmtq, Q_ISNS_DBG, "DONE PROCESS_SCN\n"); -} - -/* - * Process ESI requires a success response only - */ -static void -process_esi(int so, isns_pdu_t *esi) -{ - isns_rsp_t *cmd; - int pl_len; - - if (isns_create_pdu(ISNS_ESI_RSP, 0, (isns_pdu_t **)&cmd) != 0) { - return; - } - - pl_len = esi->payload_len + ISNS_STATUS_SZ; - if (pl_len > MAX_PDU_PAYLOAD_SZ) { - syslog(LOG_ALERT, "process_esi: payload size exceeded"); - isns_free_pdu(cmd); - return; - } - - /* change the xid to the request xid */ - cmd->xid = htons(esi->xid); - cmd->status = htonl(ISNS_RSP_SUCCESSFUL); - - /* copy original data */ - bcopy(esi->payload, cmd->data, esi->payload_len); - cmd->pdu_len = htons(pl_len); - - if (isns_send(so, (isns_pdu_t *)cmd) < 0) { - syslog(LOG_ALERT, "process_esi failed to isns_send"); - } - - isns_free_pdu(cmd); -} - -static int -is_isns_server_up(char *server) { - int so; - socklen_t len; - struct sockaddr sa; - - /* no server specified */ - if (server == NULL) { - return (-1); - } - /* - * open isns server connect and determine which PF_INET to use - */ - if ((so = isns_open(server)) < 0) { - syslog(LOG_ERR, - "isns server %s not found", - server); - return (-1); - } - len = sizeof (sa); - if (getsockname(so, &sa, &len) < 0) { - isns_close(so); - syslog(LOG_ALERT, - "isns getsockname failed"); - return (-1); - } - isns_close(so); - - if (sa.sa_family != PF_INET && - sa.sa_family != PF_INET6) { - syslog(LOG_ERR, - "isns unknown domain type"); - return (-1); - } - return (0); -} - -/* - * This thread sit's in a loop and ensures that it keeps checking for - * connection to isns_server. Once the connection works it registers - * with the isns and bails out. - * We expect the isns server to be fault taulerant and has persistence - * for the registered entries. - */ -static void * -isns_server_connection_thr(void *arg) -{ - Boolean_t registered_targets = False; - char server[MAXHOSTNAMELEN + 1] = {0}; - - while (isns_shutdown == False && - connection_thr_bail_out == False) { - /* current server */ - (void) strcpy(server, isns_args.server); - - if (is_isns_server_up(server) == 0) { - if (registered_targets == False) { - /* - * register all targets, what happens if - * no targets are created yet? this should - * not be a failure, when new target gets - * created, update gets call. what if SCN - * register fails? - */ - if (isns_reg_all() == 0) { - /* scn register all targets */ - if (isns_op_all(ISNS_SCN_REG) != 0) { - syslog(LOG_ERR, - "SCN registrations" - " failed\n"); - (void) isns_op_all( - ISNS_DEV_DEREG); - registered_targets = False; - } else { - registered_targets = True; - break; - } - } - } - } else { - syslog(LOG_INFO, - "isns server %s is not reachable", - server); - registered_targets = False; - } - (void) sleep(ISNS_SLEEP_SECS); - /* If isns was disabled, deregister and close the thread */ - if (isns_enabled() == False) { - syslog(LOG_INFO, - "isns server is disabled, dergister target"); - isns_fini(); - break; - } - - } - queue_message_set(mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - - return (NULL); -} - -/* - * esi_scn_thr() is the thread creates an end point to receive and process - * ESI & SCN messages. This thread is created when isns_access is enabled - * and for the duration of the iscsi daemon - */ -static void * -esi_scn_thr(void *arg) -{ - struct sockaddr sa, *ai; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - int so, fd, pf; - socklen_t len; - char strport[NI_MAXSERV]; - isns_pdu_t *scn = NULL; - struct timeval timeout; - fd_set fdset; - int socket_ready = 0; - - pf = get_addr_family(isns_args.entity); - if (pf == PF_INET) { - bzero(&sin, sizeof (sin)); - sin.sin_family = PF_INET; - sin.sin_port = htons(0); - sin.sin_addr.s_addr = INADDR_ANY; - ai = (struct sockaddr *)&sin; - len = sizeof (sin); - } else if (pf == PF_INET6) { - bzero(&sin6, sizeof (sin6)); - sin6.sin6_family = PF_INET6; - sin6.sin6_port = htons(0); - sin6.sin6_addr = in6addr_any; - ai = (struct sockaddr *)&sin6; - len = sizeof (sin6); - } else { - syslog(LOG_ERR, "Bad address family. Exit esi_scn_thr"); - return (NULL); - } - - /* - * create and bind SCN socket - * save the scn port info - */ - if ((so = socket(pf, SOCK_STREAM, 0)) == -1) { - syslog(LOG_ALERT, "create isns socket failed"); - return (NULL); - } - - (void) setsockopt(so, SOL_SOCKET, SO_REUSEADDR, 0, 0); - - if (bind(so, ai, len) < 0) { - syslog(LOG_ALERT, "esi_scn_thr: bind failed"); - (void) close(so); - return (NULL); - } - - /* get scn port info */ - len = sizeof (sa); - if (getsockname(so, &sa, &len) < 0) { - syslog(LOG_ALERT, "isns getsockname failed"); - (void) close(so); - return (NULL); - } - if (getnameinfo(&sa, len, NULL, 0, strport, NI_MAXSERV, - NI_NUMERICSERV) != 0) { - syslog(LOG_ALERT, "isns getnameinfo failed"); - (void) close(so); - return (NULL); - } - scn_port = atoi(strport); - - - if (listen(so, 5) < 0) { - syslog(LOG_ALERT, "esi_scn_thr: failed listen"); - (void) close(so); - return (NULL); - } - - /* listen for esi or scn messages */ - while (isns_shutdown == False) { - /* ISNS_ESI_INTERVAL_ATTR_ID is set to 10s */ - timeout.tv_sec = 10; - timeout.tv_usec = 0; - FD_ZERO(&fdset); - FD_SET(so, &fdset); - - socket_ready = select(so + 1, &fdset, NULL, NULL, &timeout); - - /* If disabled bail out, dont care about packets */ - if (isns_enabled() == False) { - syslog(LOG_INFO, - "isns server is disabled, dergister target"); - isns_fini(); - (void) close(so); - return (NULL); - } - - if (socket_ready < 0) { - syslog(LOG_ERR, - "esi_scn_thr: select failed, retrying."); - continue; - } else if (socket_ready == 0) { /* timeout */ - continue; - } else { - /* Socket is ready */ - if ((fd = accept(so, &sa, &len)) < 0) { - syslog(LOG_ALERT, "esi_scn_thr: failed accept"); - continue; - } - } - if (isns_recv(fd, (isns_rsp_t **)&scn) == 0) { - /* Just return success for ESI */ - switch (scn->func_id) { - case ISNS_ESI: - process_esi(fd, scn); - break; - case ISNS_SCN: - /* call the SCN process function */ - process_scn(fd, scn); - break; - default: - syslog(LOG_ERR, - "esi_scn_thr: Invalid funcid %d\n", - scn->func_id); - break; - } - /* free response resource */ - isns_free_pdu(scn); - } else { - syslog(LOG_ALERT, "esi_scn_thr fails isns_recv "); - } - - (void) close(fd); - } - (void) close(so); - return (NULL); -} - -/* - * Perform operation on all targets - */ -static int -isns_op_all(uint16_t op) -{ - int so; - tgt_node_t *tgt = NULL; - char *iname; - - if (isns_server_connection_thr_running == False) { - syslog(LOG_ERR, - "isns_op_all: iSNS discovery is not running." - " Check the previous iSNS initialization error."); - return (-1); - } - - if ((so = isns_open(isns_args.server)) == -1) { - syslog(LOG_ERR, "isns_op_all: failed to open isns server %s", - isns_args.server); - return (-1); - } - - while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - tgt)) != NULL) { - if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &iname) - == FALSE) { - continue; - } - - switch (op) { - case ISNS_DEV_DEREG: - if (isns_dev_attr_dereg(so, iname) == -1) { - syslog(LOG_ERR, - "ISNS de-register failed\n"); - } - num_reg = 0; - break; - case ISNS_SCN_DEREG: - if (isns_scn_dereg(so, iname) == -1) { - syslog(LOG_ERR, - "ISNS SCN de-register failed\n"); - } - break; - case ISNS_SCN_REG: - if (isns_scn_reg(so, iname) == -1) { - syslog(LOG_ERR, - "ISNS SCN register failed\n"); - } - break; - case ISNS_TGT_LOGOUT: - logout_targ(iname); - break; - default: - break; - } - - free(iname); - } - isns_close(so); - return (0); -} - -static int -isns_populate_and_update_server_info(Boolean_t update) { - char *isns_srv, *isns_port; - int retcode = 0; - - /* get isns server info */ - (void) tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, - &isns_srv); - if (isns_srv == NULL) { - syslog(LOG_INFO, - "The server has not been setup, " - "but enabling the isns access"); - retcode = -1; - return (retcode); - } - isns_port = strchr(isns_srv, ':'); - if (isns_port == NULL) { - isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT; - } else { - isns_args.isns_port = strtoul(isns_port + 1, NULL, 0); - if (isns_args.isns_port == 0) { - isns_args.isns_port = ISNS_DEFAULT_SERVER_PORT; - } - *isns_port = '\0'; - } - - if (update == True) { - /* isns_server changed */ - if (strcmp(isns_srv, isns_args.server) != 0) { - /* de-reg from old iSNS server if it is setup */ - syslog(LOG_INFO, - "Detected a new isns server, deregistering" - " %s", isns_args.server); - (void) isns_dereg_all(); - (void) strcpy(isns_args.server, isns_srv); - /* Register with the new server */ - if (isns_reg_all() == 0) { - /* scn register all targets */ - if (isns_op_all(ISNS_SCN_REG) != 0) { - syslog(LOG_ERR, - "SCN registrations failed\n"); - (void) isns_op_all(ISNS_DEV_DEREG); - retcode = -1; - } - } - } - } else { - (void) strcpy(isns_args.server, isns_srv); - } - free(isns_srv); - return (retcode); -} - -/* - * isns_init() needs to be call before all ISNS operations. - * Save the isns_server & entity name. - * Start esi_scn_thr to receive ESI & SCN messages - */ -int -isns_init(target_queue_t *q) -{ - if (q != NULL) - mgmtq = q; - - if (isns_enabled() == False) - return (0); - - /* get local hostname for entity usage */ - if ((gethostname(isns_args.entity, MAXHOSTNAMELEN) < 0) || - (get_ip_addr(isns_args.entity, &eid_ip) < 0)) { - syslog(LOG_ERR, "isns_init: failed to get host name or host ip" - " address for ENTITY properties"); - return (-1); - } - - isns_shutdown = False; - - (void) isns_populate_and_update_server_info(False); - if (pthread_create(&scn_tid, NULL, - esi_scn_thr, (void *)&isns_args) != - 0) { - syslog(LOG_ALERT, "isns_init failed to pthread_create"); - (void) pthread_kill(isns_tid, SIGKILL); - return (-1); - } - - if (pthread_create(&isns_tid, NULL, isns_server_connection_thr, - (void *)NULL) != 0) { - syslog(LOG_ALERT, - "isns_init failed to create the " - "isns connection thr"); - return (-1); - } - - isns_server_connection_thr_running = True; - return (0); -} - -/* - * isns_update gets call on modify_admin, this is changes to - * isns access and/or isns server - */ -int -isns_update() -{ - Boolean_t is_isns_enabled = isns_enabled(); - /* - * If the isns thread was not started before and we are going - * enabled from disabled start the threads. - */ - if (isns_server_connection_thr_running == False) { - if (is_isns_enabled == True) { - if (isns_init(NULL) != 0) { - return (-1); - } else { - return (0); - } - } else { - syslog(LOG_INFO, - "isns_update: isns is disabled"); - } - } else { - /* - * isns is disabled after enabled, - * log off all targets and fini isns service - */ - if (is_isns_enabled == False) { - isns_shutdown = True; - /* pthread_join for the isns thread */ - (void) pthread_join(isns_tid, NULL); - (void) pthread_join(scn_tid, NULL); - isns_server_connection_thr_running = False; - } else { - /* - * Incase the original thread is still running - * we should reap it - */ - connection_thr_bail_out = True; - (void) pthread_join(isns_tid, NULL); - connection_thr_bail_out = False; - - /* - * Read the configuration file incase the server - * has changed. - */ - if (isns_populate_and_update_server_info(True) == -1) { - return (-1); - } - } - } - return (0); -} - -/* - * isns_fini is called when isns access is disabled - */ -void -isns_fini() -{ - /* - * de-register all targets 1st, this prevents initiator from - * logging back in - */ - (void) isns_op_all(ISNS_SCN_DEREG); - (void) isns_op_all(ISNS_DEV_DEREG); - - /* log off all targets */ - (void) isns_op_all(ISNS_TGT_LOGOUT); -} - -static int -get_addr_family(char *node) { - struct addrinfo *ai = NULL; - int ret; - - if ((ret = getaddrinfo(node, NULL, NULL, &ai)) != 0) { - syslog(LOG_ALERT, "get_addr_family: server %s not found : %s", - node, gai_strerror(ret)); - return (-1); - } - ret = ai->ai_family; - freeaddrinfo(ai); - return (ret); -} - -static int -get_ip_addr(char *node, ip_t *sa) -{ - struct addrinfo *ai = NULL, *aip; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - int ret; - - if ((ret = getaddrinfo(node, NULL, NULL, &ai)) != 0) { - syslog(LOG_ALERT, "get_ip_addr: %s not found : %s", - node, gai_strerror(ret)); - return (-1); - } - - bzero(sa, sizeof (ip_t)); - aip = ai; - do { - sa->ai_addrlen = aip->ai_addrlen; - sa->pf_family = aip->ai_family; - switch (aip->ai_family) { - case PF_INET: - /* LINTED */ - sin = (struct sockaddr_in *)aip->ai_addr; - sa->ip_len = sizeof (in_addr_t); - bcopy(&sin->sin_addr, (void *)&sa->ip_adr.in, - sa->ip_len); - freeaddrinfo(ai); - return (0); - case PF_INET6: - /* LINTED */ - sin6 = (struct sockaddr_in6 *)aip->ai_addr; - sa->ip_len = sizeof (in6_addr_t); - bcopy(&sin6->sin6_addr, &sa->ip_adr.in6, - sa->ip_len); - freeaddrinfo(ai); - return (0); - default: - continue; - } - } while ((aip = aip->ai_next) != NULL); - - freeaddrinfo(ai); - return (-1); -} - -/* - * Process isns response, need to verify same transaction id, func_id - * as the isns command, the isns command is in network byte order, - * the isns response is in host byte order - */ -static int -process_rsp(isns_pdu_t *cmd, isns_rsp_t *rsp) -{ - queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_RSP"); - /* - * Process responses: - * -verify sucessful response - * -verify match xid - * -process operating attributes - * For DevAttrReg & DevAttrQry and most isns command, - * the response func_id is command_func_id | 0x8000. - */ - rsp->status = ntohl(rsp->status); - if (rsp->status != ISNS_RSP_SUCCESSFUL || - rsp->xid != ntohs(cmd->xid) || - rsp->func_id != (ntohs(cmd->func_id) | 0x8000)) { - queue_prt(mgmtq, Q_ISNS_DBG, - "cmd failed with: status= %d xid= %d %d "\ - "response attribute %x\n", rsp->status, rsp->xid,\ - ntohs(cmd->xid), rsp->func_id); - return (-1); - } - - return (0); -} - -/* - * DevAttrDereg - */ -static int -isns_dev_attr_dereg(int so, char *node) -{ - isns_pdu_t *cmd = NULL; - isns_rsp_t *rsp = NULL; - uint32_t flags = 0; - int ret = -1; - - queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_DEREG"); - - if (isns_create_pdu(ISNS_DEV_DEREG, flags, &cmd) != 0) { - return (-1); - } - - /* add source attribute */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) != 0) { - goto error; - } - - /* add delimiter */ - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { - goto error; - } - - /* add operation attributes */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) != 0) { - goto error; - } - - /* send pdu */ - if (isns_send(so, cmd) == -1) { - syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_send"); - goto error; - } - - /* get isns response */ - if (isns_recv(so, &rsp) == -1) { - syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_recv "); - goto error; - } - - /* process response */ - if (process_rsp(cmd, rsp) == 0) { - /* - * Keep the num_reg to a non-negative number. - * num_reg is used to keep track of whether there was - * any registration occurred or not. Deregstration should - * be followed by registration but in case dereg occurs - * and somehow it is succeeded keeping num_reg to 0 prevent - * any negative effect on subsequent registration. - */ - if (num_reg > 0) num_reg--; - ret = 0; - } - -error: - /* Free all resouces here */ - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - return (ret); -} - -/* - * Register a new node, need to find another node that is already registered - * DevAttrReg - * RFC 4171 Section 5.6.5.5 indicated SCN-port-tag (23) needed to be - * included in the registration - * Also need to register ESI-port-tag (20) see Section 6.3.5 - */ -static int -isns_dev_attr_reg(int so, tgt_node_t *tgt, char *node, char *alias) -{ - isns_pdu_t *cmd = NULL; - isns_rsp_t *rsp = NULL; - uint32_t flags = 0; - int ret = 0; - Boolean_t found = False; - tgt_node_t *src = NULL; - char *src_nm = NULL; - - queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_REG"); - - if ((so = isns_open(isns_args.server)) == -1) { - return (-1); - } - - if (num_reg == 0) { - flags |= ISNS_FLAG_REPLACE_REG; - } - - if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) { - return (-1); - } - - if (num_reg == 0) { - /* add new node to source attribute */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) != 0) { - goto error; - } - } else { - /* find a registered node to use */ - do { - src = find_next_tgt(src, &src_nm); - if (src == NULL) { - syslog(LOG_ALERT, "ISNS out of sync\n"); - goto error; - } - if (tgt == src) { - free(src_nm); - src_nm = NULL; - continue; - } else { - found = True; - } - } while (found == False); - - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(src_nm), src_nm, 0) != 0) { - goto error; - } - } - - /* add message key attribute */ - if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, - STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { - goto error; - } - - /* add delimiter */ - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { - goto error; - } - - /* add operation attributes */ - - /* entity id */ - if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, - STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { - goto error; - } - - /* entity type */ - if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID, - ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { - goto error; - } - - /* - * Register entity portal properties the 1st time - */ - if (num_reg == 0) { - /* portal ip-addr */ - if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID, - eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, - eid_ip.ip_len) != 0) { - goto error; - } - - /* portal port */ - if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, iscsi_port) != 0) { - goto error; - } - - /* ESI interval */ - if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID, - ISNS_ESI_TICK_SZ, NULL, 10) != 0) { - goto error; - } - - /* scn port */ - if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, scn_port) != 0) { - goto error; - } - - /* esi port */ - if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, scn_port) != 0) { - goto error; - } - } - - /* iscsi node name */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) != 0) { - goto error; - } - - /* iscsi node type */ - if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, - ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE) != 0) { - goto error; - } - - /* iscsi node alias */ - if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, - STRLEN(alias), alias, 0) != 0) { - goto error; - } - - /* PGT */ - if (append_tpgt(tgt, cmd) != 0) { - goto error; - } - - /* send pdu */ - if (isns_send(so, cmd) == -1) { - goto error; - } - - /* get isns response */ - if (isns_recv(so, &rsp) == -1) { - goto error; - } - - /* process response */ - if ((ret = process_rsp(cmd, rsp)) == 0) { - num_reg++; - } - -error: - /* Free all resouces here */ - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - if (src_nm) - free(src_nm); - return (ret); -} - -/* - * DevAttrQry for iscsi initiator - * See RFC 4171 Sect. 5.6.5.2 for query detail - */ -static int -isns_dev_attr_qry(int so, char *target, char *initiator) -{ - isns_pdu_t *cmd; - isns_rsp_t *rsp; - uint32_t flags = 0; - int ret = -1; - size_t remain; - isns_tlv_t *tlv; - uint8_t *ptr; - - queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_QRY"); - - if (isns_create_pdu(ISNS_DEV_ATTR_QRY, flags, &cmd) != 0) { - return (-1); - } - - /* source attribute */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(target), target, 0) == -1) { - goto error; - } - - /* message key attribute */ - /* iscsi initiator node type */ - if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, - ISNS_NODE_TYP_SZ, NULL, ISNS_INITIATOR_NODE_TYPE) == -1) { - goto error; - } - - /* delimiter */ - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) { - goto error; - } - - /* - * operating attributes - * Query Iscsi initiator with zero length TLV operating - * attribute - */ - - /* iscsi name */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - 0, NULL, 0) != 0) { - goto error; - } - - if (isns_send(so, cmd) == -1) { - syslog(LOG_ERR, "isns_dev_attr_qry fails isns_send"); - goto error; - } - - /* recv response */ - if (isns_recv(so, &rsp) == -1) { - syslog(LOG_ERR, "isns_dev_attr_qry fails isns_recv "); - goto error; - } - - /* process response */ - if ((ret = process_rsp(cmd, rsp)) == 0) { - /* compare initiator name to the response, success if found */ - /* subtract out status word */ - remain = rsp->pdu_len - ISNS_STATUS_SZ; - ptr = rsp->data; - - while (remain > 0) { - /* LINTED */ - tlv = (isns_tlv_t *)ptr; - - /* debug only */ - print_ntoh_tlv(tlv); - - /* process tag-len-value */ - ntoh_tlv(tlv); - /* - * let's process the data, only interested - * in iscsi name, skip everything else for - * now. - */ - if (tlv->attr_id == ISNS_ISCSI_NAME_ATTR_ID) { - if (strncmp((char *)tlv->attr_value, initiator, - tlv->attr_len) == 0) { - break; - } - } - /* next tlv */ - remain -= ISNS_ATTR_SZ(tlv->attr_len); - ptr += ISNS_ATTR_SZ(tlv->attr_len); - } - ret = (remain > 0) ? 1 : 0; - } - -error: - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - return (ret); -} - -/* - * SCNReg - * See RFC 4171 Section 5.6.5.5 - */ -static int -isns_scn_reg(int so, char *node) -{ - isns_pdu_t *cmd; - isns_rsp_t *rsp; - uint32_t flags = 0; - uint32_t bitmap = 0; - int ret = -1; - - queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_REG"); - - if (isns_create_pdu(ISNS_SCN_REG, flags, &cmd) != 0) { - return (-1); - } - - /* source attribute */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) == -1) { - goto error; - } - - /* message key attribute */ - /* iscsi initiator node name */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) != 0) { - goto error; - } - - /* delimiter */ - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) { - goto error; - } - - /* SCN bitmap */ - bitmap = ISNS_INIT_SELF_INFO_ONLY | ISNS_OBJ_REMOVED | - ISNS_OBJ_ADDED | ISNS_OBJ_UPDATED; - if (isns_append_attr(cmd, ISNS_ISCSI_SCN_BITMAP_ATTR_ID, - ISNS_SCN_BITMAP_SZ, NULL, bitmap) == -1) { - goto error; - } - - if (isns_send(so, cmd) == -1) { - syslog(LOG_ERR, "isns_scn_reg fails isns_send"); - goto error; - } - - if (isns_recv(so, &rsp) == -1) { - syslog(LOG_ERR, "isns_scn_reg fails isns_recv "); - goto error; - } - - /* process response */ - if (process_rsp(cmd, rsp) == 0) { - ret = 0; - } - -error: - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - return (ret); -} - - -/* - * SCNDereg - */ -static int -isns_scn_dereg(int so, char *node) -{ - isns_pdu_t *cmd = NULL; - isns_rsp_t *rsp = NULL; - uint32_t flags = 0; - int ret = -1; - - queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_SCN_DEREG"); - - if (isns_create_pdu(ISNS_SCN_DEREG, flags, &cmd) != 0) { - return (-1); - } - - /* source attribute */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) == -1) { - goto error; - } - - /* message key attribute */ - /* iscsi initiator node name */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(node), node, 0) != 0) { - goto error; - } - - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) == -1) { - goto error; - } - - if (isns_send(so, cmd) == -1) { - syslog(LOG_ERR, "isns_scn_reg fails isns_send"); - goto error; - } - - if (isns_recv(so, &rsp) == -1) { - syslog(LOG_ERR, "isns_scn_reg fails isns_recv "); - goto error; - } - - /* process response */ - if (process_rsp(cmd, rsp) == 0) { - ret = 0; - } - -error: - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - return (ret); -} - -/* - * isns_reg is called to register new target - */ -int -isns_reg(char *targ) -{ - int so; - tgt_node_t *tgt; - char *iqn = NULL; - - if (isns_server_connection_thr_running == False) { - syslog(LOG_ERR, - "isns_reg: iSNS discovery is not running." - " Check the previous iSNS initialization error."); - return (-1); - } - - if ((so = isns_open(isns_args.server)) == -1) { - syslog(LOG_ERR, "isns_reg failed with server: %s", - isns_args.server); - return (-1); - } - - /* - * Open targets_config and devAttrReg all nodes - */ - if ((tgt = find_tgt_by_name(targ, &iqn)) != NULL) { - if (isns_dev_attr_reg(so, tgt, iqn, tgt->x_value) != 0) { - syslog(LOG_ALERT, "ISNS registration failed %s\n", - tgt->x_value); - goto error; - } - if (isns_scn_reg(so, iqn) == -1) { - syslog(LOG_ERR, "ISNS SCN register failed\n"); - } - } - -error: - if (iqn) - free(iqn); - isns_close(so); - return (0); -} - - -/* - * Register all iscsi target nodes from the XML database - * Alway use the ISNS_FLAG_REPLACE_REG flag - */ -int -isns_reg_all() -{ - int so; - uint32_t flags = ISNS_FLAG_REPLACE_REG; - isns_pdu_t *cmd = NULL; - isns_rsp_t *rsp = NULL; - char *n = NULL; - char *a = NULL; - char alias[MAXNAMELEN]; - char iname[MAXNAMELEN]; - tgt_node_t *tgt = NULL; - int ret = -1; - int tgt_cnt = 0; - - if (isns_server_connection_thr_running == False) { - syslog(LOG_ERR, - "isns_reg_all: iSNS discovery is not running." - " Check the previous iSNS initialization error."); - return (-1); - } - - /* - * get the 1st target and use it for the source attribute - */ - if ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt)) - == NULL) { - return (0); - } - if (tgt->x_value == NULL) { - syslog(LOG_ALERT, "ISNS: target with NULL local name\n"); - return (-1); - } - if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n) - == FALSE) { - syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n"); - return (-1); - } - (void) strcpy(iname, n); - free(n); - if ((so = isns_open(isns_args.server)) == -1) { - syslog(LOG_ALERT, "ISNS: fails to connect to %s\n", - isns_args.server); - return (-1); - } - - if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) { - goto error; - } - - /* source attribute */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(iname), iname, 0) != 0) { - goto error; - } - - /* add message key attribute */ - if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, - STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { - goto error; - } - - /* add delimiter */ - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { - goto error; - } - - /* entity id */ - if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, - STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { - goto error; - } - - /* entity type */ - if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID, - ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { - goto error; - } - - /* portal ip-addr */ - if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID, - eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, - eid_ip.ip_len) != 0) { - goto error; - } - - /* portal port */ - if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, iscsi_port) != 0) { - goto error; - } - - /* ESI interval */ - if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID, - ISNS_ESI_TICK_SZ, NULL, 10) != 0) { - goto error; - } - - - /* scn port */ - if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, scn_port) != 0) { - goto error; - } - - /* esi port */ - if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID, - ISNS_PORT_SZ, NULL, scn_port) != 0) { - goto error; - } - - /* - * Open targets_config and devAttrReg all nodes - */ - tgt = NULL; - while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - tgt)) != NULL) { - if (tgt->x_value == NULL) { - syslog(LOG_ALERT, "ISNS: target with NULL name\n"); - continue; - } - /* use this value as alias if alias is not set */ - (void) strcpy(alias, tgt->x_value); - - if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n) - == FALSE) { - continue; - } - (void) strcpy(iname, n); - free(n); - - /* find alias */ - if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a) - == TRUE) { - (void) strcpy(alias, a); - free(a); - } - - tgt_cnt++; /* increment target count */ - - /* operation attributes */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(iname), iname, 0) != 0) { - goto error; - } - if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, - 4, NULL, ISNS_TARGET_NODE_TYPE) != 0) { - goto error; - } - if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, - STRLEN(alias), alias, 0) != 0) { - goto error; - } - - if (append_tpgt(tgt, cmd) != 0) { - goto error; - } - - } - - /* send pdu */ - if (isns_send(so, cmd) == -1) { - goto error; - } - - /* get isns response */ - if (isns_recv(so, &rsp) == -1) { - goto error; - } - - /* process response */ - if (process_rsp(cmd, rsp) == 0) { - ret = 0; - num_reg = tgt_cnt; - queue_prt(mgmtq, Q_ISNS_DBG, "DevAttrRegAll successful"); - } else { - syslog(LOG_ALERT, "DevAttrReg failed"); - } - -error: - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - isns_close(so); - return (ret); -} - -/* - * Deregister an iscsi target node - */ -int -isns_dereg(char *name) -{ - int so; - int ret; - - if (isns_server_connection_thr_running == False) { - syslog(LOG_ERR, - "isns_dereg: iSNS discovery is not running." - " Check the previous iSNS initialization error."); - return (-1); - } - - if ((so = isns_open(isns_args.server)) == -1) { - return (-1); - } - - ret = isns_dev_attr_dereg(so, name); - - isns_close(so); - return (ret); -} - -/* - * Update an existing iscsi target property - */ -int -isns_dev_update(char *targ, uint32_t mods) -{ - int so; - int flags = 0; /* update only */ - char *iname = NULL; - char *dummy = NULL; - char alias[MAXNAMELEN]; - tgt_node_t *tgt = NULL; - isns_pdu_t *cmd; - isns_rsp_t *rsp; - int ret = -1; - - if (mods == 0) - return (0); - - if (isns_server_connection_thr_running == False) { - syslog(LOG_ERR, - "isns_dev_update: iSNS discovery is not running." - " Check the previous iSNS initialization error."); - return (-1); - } - - if ((tgt = find_tgt_by_name(targ, &iname)) != NULL) { - if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &dummy) == - True) { - (void) strcpy(alias, dummy); - free(dummy); - } else - (void) strcpy(alias, tgt->x_value); - - if ((so = isns_open(isns_args.server)) < 0) { - goto error; - } - - if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd)) { - goto error; - } - /* source attr, msg key, delimiter */ - if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(iname), iname, 0) != 0) { - goto error; - } - if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, - STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { - goto error; - } - if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) - != 0) { - goto error; - } - - /* - * get current operating attributes, alias & portal group - * objects, these should be the only things that get change - */ - (void) isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, - STRLEN(iname), iname, 0); - (void) isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, - ISNS_NODE_TYP_SZ, NULL, ISNS_TARGET_NODE_TYPE); - - if (mods & ISNS_MOD_ALIAS) - if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, - STRLEN(alias), alias, 0) != 0) { - goto error; - } - - if (mods & ISNS_MOD_TPGT) - if (append_tpgt(tgt, cmd) != 0) { - goto error; - } - - if (isns_send(so, (isns_pdu_t *)cmd) < 0) { - goto error; - } - - if (isns_recv(so, &rsp) == -1) { - goto error; - } - - /* process response, if failed do a isns_reg_all */ - if ((ret = process_rsp(cmd, rsp)) == -1) { - if (isns_reg_all() != 0 || isns_scn_reg_all() != 0) { - syslog(LOG_ALERT, "ISNS register failed\n"); - goto error; - } - ret = 0; - } else { - if (isns_scn_reg(so, iname) == -1) { - syslog(LOG_ERR, "ISNS SCN register failed\n"); - goto error; - } - ret = 0; - } - } else { - syslog(LOG_ERR, "ISNS: fails to update target %s\n", alias); - } - -error: - if (cmd) - isns_free_pdu(cmd); - if (rsp) - isns_free_pdu(rsp); - if (iname) - free(iname); - isns_close(so); - return (ret); -} - - -/* - * Deregister all iscsi target nodes from the XML database - */ -int -isns_dereg_all() -{ - return (isns_op_all(ISNS_DEV_DEREG)); -} - -int -isns_scn_reg_all() -{ - return (isns_op_all(ISNS_SCN_REG)); -} - -int -isns_scn_dereg_all() -{ - return (isns_op_all(ISNS_SCN_DEREG)); -} - -/* - * Query an iscsi initiator node - */ -Boolean_t -isns_qry_initiator(char *target, char *initiator) -{ - int so; - int ret; - - if (isns_server_connection_thr_running == False) { - syslog(LOG_ERR, - "isns_qry_initiator: iSNS discovery is not running" - " Check the previous iSNS initialization error."); - return (-1); - } - - if ((so = isns_open(isns_args.server)) == -1) { - syslog(LOG_ERR, "isns_qry failed"); - return (-1); - } - - ret = isns_dev_attr_qry(so, target, initiator); - - isns_close(so); - return (ret == 1 ? True : False); -} - -Boolean_t -isns_enabled() -{ - Boolean_t isns_access = False; - char *isns_srv = NULL; - - (void) tgt_find_value_boolean(main_config, XML_ELEMENT_ISNS_ACCESS, - &isns_access); - /* get isns server info */ - if (isns_access == True) { - if (tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, - &isns_srv) == True) { - free(isns_srv); - return (True); - } - } - return (False); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/isns_client.h b/usr/src/cmd/iscsi/iscsitgtd/isns_client.h deleted file mode 100644 index 8affb91b0f..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/isns_client.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 _ISNS_CLIENT_H -#define _ISNS_CLIENT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <netdb.h> -#include "queue.h" - -#include "isns_protocol.h" - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/* isns update bitmap */ -#define ISNS_MOD_ALIAS 0x1 -#define ISNS_MOD_TPGT 0x2 - -/* iscsi isns protocol */ - -/* - * Attribute size - */ -#define ISNS_ISCSI_TYPE_SZ (4) -#define ISNS_SCN_BITMAP_SZ (4) -#define ISNS_PORT_SZ (4) -#define ISNS_ESI_TICK_SZ (4) -#define ISNS_PG_TAG_SZ (4) -#define ISNS_ENTITY_TYP_SZ (4) -#define ISNS_NODE_TYP_SZ (4) - -/* - * iSNS attribute length: See RFC 4171 Section 6.1 - * iSCSI Name = 4-224 - * iSCSI Alias = 4-256 - */ -#define ISCSI_MAX_NAME 224 -#define ISCSI_MAX_ALIAS 256 - -/* - * Default pdu payload size, this is derived from a typical DevAttrReg - * request, this should be sufficient for all requests. - */ -#define MAX_PDU_SZ (16384) -#define MAX_PDU_PAYLOAD_SZ (MAX_PDU_SZ - ISNSP_HEADER_SIZE) -#define TAG_LEN_SZ (8) - -/* various isns data size */ -#define ISNS_STATUS_SZ (4) -#define ISNS_ATTR_SZ(attr_len) (attr_len + TAG_LEN_SZ) - -/* - * PDU length is 4 bytes aligned. See RFC 4171 Section 5.1.3 - */ -#define PAD4(a) ((a%4) ? ((4-a%4)+a) : a) - -/* - * Macro to check 1st and last pdu - */ -#define IS_1ST_PDU(x) ((x & ISNS_FLAG_FIRST_PDU) ? 1 : 0) -#define IS_LAST_PDU(x) ((x & ISNS_FLAG_LAST_PDU) ? 1 : 0) - -/* RFC 4171 section 6 - null is included in strlen */ -#define STRLEN(x) (strlen(x) + 1) - -typedef struct esi_scn_arg { - char entity[MAXHOSTNAMELEN + 1]; /* iscsi target entity */ - char server[MAXHOSTNAMELEN + 1]; /* isns server */ - int isns_port; /* isns server port */ -} esi_scn_arg_t; - -/* - * ISNS message header - * See RFC 4171 Section 5.0 & 5.1 - */ -typedef struct isns_hdr { - uint16_t version; - uint16_t func_id; - uint16_t pdu_len; - uint16_t flags; - uint16_t xid; - uint16_t seqid; -} isns_hdr_t; - -/* - * ISNS attribute, the attribute is in Tag-Length_Value format - * attr_len: NULLs are included in the length - * attr_value: is variable size and it is 4 bytes aligned - */ -#if 0 -typedef struct isns_attr { - uint32_t tag; - uint32_t len; - uint8_t val[1]; -} isns_attr_t; -#endif - -typedef struct isns_rsp { - uint16_t version; - uint16_t func_id; - uint16_t pdu_len; - uint16_t flags; - uint16_t xid; - uint16_t seqid; - uint32_t status; - uint8_t data[1]; -} isns_rsp_t; - -/* Function prototype */ -int isns_init(target_queue_t *q); -int isns_update(); -void isns_fini(); -Boolean_t isns_qry_initiator(char *, char *); -int isns_reg(char *); -int isns_reg_all(); -int isns_dereg(char *); -int isns_dereg_all(); -int isns_scn_reg_all(); -int isns_scn_dereg_all(); -int isns_dev_update(char *, uint32_t); -Boolean_t isns_enabled(); -void isns_tpgt_update(); -int isns_open(char *); -void isns_close(int); -int isns_append_attr(isns_pdu_t *, uint32_t, uint32_t, void *, - uint32_t); -int isns_create_pdu(uint16_t, uint32_t, isns_pdu_t **); -void isns_free_pdu(void *); -int isns_send(int, isns_pdu_t *); -int isns_recv(int, isns_rsp_t **); -void ntoh_isns_hdr(isns_hdr_t *); -void ntoh_tlv(isns_tlv_t *); -void print_ntoh_tlv(isns_tlv_t *); -void print_attr(isns_tlv_t *attr, void *pval, uint32_t ival); -void print_isns_hdr(isns_hdr_t *); -int setsocknonblocking(int so); -int setsockblocking(int so); -Boolean_t is_socket_ready(int so, - fd_set *rfdset, fd_set *wfdset, fd_set *errfdset); - -#ifdef __cplusplus -} -#endif - -#endif /* _ISNS_CLIENT_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/isns_protocol.h b/usr/src/cmd/iscsi/iscsitgtd/isns_protocol.h deleted file mode 100644 index 1b8b0298d0..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/isns_protocol.h +++ /dev/null @@ -1,200 +0,0 @@ - -/* - * 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 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _ISNS_PROTOCOL_H -#define _ISNS_PROTOCOL_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/types.h> - -#define ISNSP_VERSION (0x01) - -#define ISNS_DEFAULT_SERVER_PORT (3205) - -#define ISNSP_HEADER_SIZE (12) -#define ISNSP_MAX_PAYLOAD_SIZE (65532) -#define ISNSP_MAX_PDU_SIZE (ISNSP_HEADER_SIZE + \ - ISNSP_MAX_PAYLOAD_SIZE) - -#define ISNS_TLV_ATTR_ID_LEN (4) -#define ISNS_TLV_ATTR_LEN_LEN (4) -#define MAX_ISNS_MESG_ATTR_ENTRIES (8) -#define MAX_ISNS_OPER_ATTR_ENTRIES (32) - -/* iSNS Entity Protocol, iSNS Draft - section 6.2.2. */ -#define ISNS_ENTITY_PROTOCOL_NO (1) -#define ISNS_ENTITY_PROTOCOL_ISCSI (2) -#define ISNS_ENTITY_PROTOCOL_FCP (3) - -/* iSNS Function IDs, iSNS Draft - section 4.1.3. */ -#define ISNS_DEV_ATTR_REG (0x0001) -#define ISNS_DEV_ATTR_QRY (0x0002) -#define ISNS_DEV_GET_NEXT (0x0003) -#define ISNS_DEV_DEREG (0x0004) -#define ISNS_SCN_REG (0x0005) -#define ISNS_SCN_DEREG (0x0006) -#define ISNS_SCN (0x0008) -#define ISNS_ESI (0x000D) -#define ISNS_HEARTBEAT (0x000E) -#define ISNS_DEV_ATTR_REG_RSP (0x8001) -#define ISNS_DEV_ATTR_QRY_RSP (0x8002) -#define ISNS_DEV_DEREG_RSP (0x8004) -#define ISNS_SCN_REG_RSP (0x8005) -#define ISNS_SCN_DEREG_RSP (0x8006) -#define ISNS_SCN_RSP (0x8008) -#define ISNS_ESI_RSP (0x800D) - -/* iSNS Flags, iSNS Draft - section 5.1.4. */ -#define ISNS_FLAG_FIRST_PDU (0x0400) -#define ISNS_FLAG_LAST_PDU (0x0800) -#define ISNS_FLAG_REPLACE_REG (0x1000) -#define ISNS_FLAG_AUTH_BLK_PRESENTED (0x2000) -#define ISNS_FLAG_SERVER (0x4000) -#define ISNS_FLAG_CLIENT (0x8000) - -/* iSNS Response Status, iSNS Draft - section 5.4 */ -#define ISNS_RSP_SUCCESSFUL (0x0000) -#define ISNS_RSP_UNKNOWN_ERROR (0x0001) -#define ISNS_RSP_MSG_FORMAT_ERROR (0x0002) -#define ISNS_RSP_INVALID_REGIS (0x0003) -#define ISNS_RSP_INVALID_QRY (0x0005) -#define ISNS_RSP_SRC_UNKNOWN (0x0006) -#define ISNS_RSP_SRC_ABSENT (0x0007) -#define ISNS_RSP_SRC_UNAUTHORIZED (0x0008) -#define ISNS_RSP_NO_SUCH_ENTRY (0x0009) -#define ISNS_RSP_VER_NOT_SUPPORTED (0X0010) -#define ISNS_RSP_INTERNAL_ERROR (0x0011) -#define ISNS_RSP_BUSY (0x0012) -#define ISNS_RSP_OPTION_NOT_UNDERSTOOD (0x0013) -#define ISNS_RSP_INVALID_UPDATE (0x0014) -#define ISNS_RSP_MSG_NOT_SUPPORTED (0x0015) -#define ISNS_RSP_SCN_EVENT_REJECTED (0X0016) -#define ISNS_RSP_SCN_REGIS_REJECTED (0x0017) -#define ISNS_RSP_ATTR_NOT_IMPL (0x0018) -#define ISNS_RSP_ESI_NOT_AVAILABLE (0x0021) -#define ISNS_RSP_INVALID_DEREGIS (0x0022) -#define ISNS_RSP_REGIS_NOT_SUPPORTED (0x0023) - -/* iSCSI Node Type, iSNS Draft - section 6.4.2. */ -#define ISNS_TARGET_NODE_TYPE (0x0001) -#define ISNS_INITIATOR_NODE_TYPE (0x0002) -#define ISNS_CONTROL_NODE_TYPE (0x0004) - -/* iSCSI Node SCN Bitmap, iSNS Draft - section 6.4.4. */ -#define ISNS_INIT_SELF_INFO_ONLY (0x0080) /* Bit 24 */ -#define ISNS_TARGET_SELF_INFO_ONLY (0x0040) /* Bit 25 */ -#define ISNS_MGMT_REG (0x0020) /* Bit 26 */ -#define ISNS_OBJ_REMOVED (0x0010) /* Bit 27 */ -#define ISNS_OBJ_ADDED (0x0008) /* Bit 28 */ -#define ISNS_OBJ_UPDATED (0x0004) /* Bit 29 */ -#define ISNS_OBJ_MEMBER_REMOVED (0x0002) /* Bit 30 */ -#define ISNS_OBJ_MEMBER_ADDED (0x0001) /* Bit 31 */ - -/* iSNS Attribute IDs, iSNS Draft - section 6.1. */ -#define ISNS_DELIMITER_ATTR_ID (0) -#define ISNS_EID_ATTR_ID (1) -#define ISNS_ENTITY_PROTOCOL_ATTR_ID (2) -#define ISNS_TIMESTAMP_ATTR_ID (4) -#define ISNS_PORTAL_IP_ADDR_ATTR_ID (16) -#define ISNS_PORTAL_PORT_ATTR_ID (17) -#define ISNS_PORTAL_NAME_ATTR_ID (18) -#define ISNS_ESI_INTERVAL_ATTR_ID (19) -#define ISNS_ESI_PORT_ATTR_ID (20) -#define ISNS_SCN_PORT_ATTR_ID (23) -#define ISNS_ISCSI_NAME_ATTR_ID (32) -#define ISNS_ISCSI_NODE_TYPE_ATTR_ID (33) -#define ISNS_ISCSI_ALIAS_ATTR_ID (34) -#define ISNS_ISCSI_SCN_BITMAP_ATTR_ID (35) -#define ISNS_PG_ISCSI_NAME_ATTR_ID (48) -#define ISNS_PG_PORTAL_IP_ADDR_ATTR_ID (49) -#define ISNS_PG_PORTAL_PORT_ATTR_ID (50) -#define ISNS_PG_TAG_ATTR_ID (51) -#define ISNS_PG_INDEX_ATTR_ID (52) - -/* iSNS Defaults */ -#define ISNS_DEFAULT_SERVER_PORT (3205) - -typedef struct isns_tlv { - uint32_t attr_id; - uint32_t attr_len; - uint8_t attr_value[1]; -} isns_tlv_t; - -typedef struct isns_packet_data { - uint16_t version; - uint16_t func_id; - uint16_t payload_len; - uint16_t flags; - uint16_t xid; - uint16_t seq; - - int num_of_tlvs; - isns_tlv_t tlvs[MAX_ISNS_OPER_ATTR_ENTRIES]; -} isns_packet_data_t; - -typedef struct isns_reg_mesg { - isns_tlv_t src_attr; - int num_of_mesg_attrs; - isns_tlv_t *mesg_attrs[MAX_ISNS_MESG_ATTR_ENTRIES]; - isns_tlv_t delimiter_attr; - isns_tlv_t *operating_attrs[MAX_ISNS_OPER_ATTR_ENTRIES]; -} isns_reg_mesg_t; - -typedef struct isns_resp_mesg { - uint8_t status[4]; - isns_tlv_t messages_attrs[MAX_ISNS_MESG_ATTR_ENTRIES]; - isns_tlv_t delimiter_attr; - isns_tlv_t operating_attrs[MAX_ISNS_OPER_ATTR_ENTRIES]; -} isns_resp_mesg_t; - -typedef struct isns_pdu { - uint16_t version; - uint16_t func_id; - uint16_t payload_len; - uint16_t flags; - uint16_t xid; - uint16_t seq; - uint8_t payload[1]; -} isns_pdu_t; - -typedef struct isns_resp { - uint32_t status; - uint8_t data[1]; -} isns_resp_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _ISNS_PROTOCOL_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/main.c b/usr/src/cmd/iscsi/iscsitgtd/main.c deleted file mode 100644 index caf8355ccf..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/main.c +++ /dev/null @@ -1,940 +0,0 @@ -/* - * 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. - */ - - -#define FD_SETSIZE 65536 -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <time.h> -#include <unistd.h> -#include <pthread.h> -#include <sys/conf.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <stdint.h> -#include <dirent.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <assert.h> -#include <errno.h> -#include <door.h> -#include <signal.h> -#include <siginfo.h> -#include <sys/ethernet.h> -#include <libscf.h> -#include <syslog.h> -#include <synch.h> -#include <libxml/xmlreader.h> -#include <sys/resource.h> -#include <syslog.h> -#include <sys/select.h> -#include <iscsitgt_impl.h> -#include <umem.h> - -#include "queue.h" -#include "port.h" -#include "iscsi_conn.h" -#include "target.h" -#include "utility.h" -#include "iscsi_ffp.h" -#include "errcode.h" -#include "t10.h" -#include "mgmt_scf.h" - -#include "isns_client.h" - -#define EMPTY_CONFIG "<config version='1.0'>\n</config>\n" - -/* ---- Forward declarations ---- */ -static void variable_handler(tgt_node_t *, target_queue_t *, target_queue_t *, - ucred_t *); - - -/* ---- Global configuration data. ---- */ -char *target_basedir = NULL; -char *target_log = DEFAULT_TARGET_LOG; -char *config_file = DEFAULT_CONFIG_LOCATION; -char *pgr_basedir = NULL; -int iscsi_port = 3260, /* defined by the spec */ - dbg_lvl = 0, - door_min_space; -tgt_node_t *main_config, - *targets_config; -Boolean_t enforce_strict_guid = True, - thin_provisioning = False, - disable_tpgs = False, - dbg_timestamps = False, - pgr_persist = True; -int targets_vers_maj, - targets_vers_min, - main_vers_maj, - main_vers_min; -pthread_rwlock_t targ_config_mutex; -umem_cache_t *iscsi_cmd_cache, - *t10_cmd_cache, - *queue_cache; - -typedef struct var_table { - char *v_name; - int *v_value; -} var_table_t; - -typedef struct cmd_table { - char *c_name; - void (*c_func)(tgt_node_t *, target_queue_t *, target_queue_t *, - ucred_t *); -} cmd_table_t; - -admin_table_t admin_prop_list[] = { - {XML_ELEMENT_BASEDIR, update_basedir, NULL}, - {XML_ELEMENT_CHAPSECRET, 0, NULL}, - {XML_ELEMENT_CHAPNAME, 0, NULL}, - {XML_ELEMENT_RAD_ACCESS, 0, NULL}, - {XML_ELEMENT_RAD_SERV, valid_radius_srv, NULL}, - {XML_ELEMENT_RAD_SECRET, 0, NULL}, - {XML_ELEMENT_ISNS_ACCESS, 0, NULL}, - {XML_ELEMENT_ISNS_SERV, valid_isns_srv, NULL}, - {XML_ELEMENT_FAST, 0, NULL}, - {XML_ELEMENT_DELETE_CHAPSECRET, 0, XML_ELEMENT_CHAPSECRET}, - {XML_ELEMENT_DELETE_CHAPNAME, 0, XML_ELEMENT_CHAPNAME}, - {XML_ELEMENT_DELETE_RAD_SECRET, 0, XML_ELEMENT_RAD_SECRET}, - {XML_ELEMENT_DELETE_RAD_SERV, 0, XML_ELEMENT_RAD_SERV}, - {0, 0} -}; - -/* - * Global variables which can be set via the management XML interface - * with the syntax of "<variable><dbg_lvl>0x033</dbg_lvl></variable>" - */ -var_table_t var_table[] = { - { "dbg_lvl", &dbg_lvl }, - { "qlog_lvl", &qlog_lvl }, - /* ---- End of Table marker ---- */ - { NULL, 0 } -}; - -/* - * Commands which are run via the management XML interface - */ -cmd_table_t cmd_table[] = { - { "variable", variable_handler }, - { "create", create_func }, - { "modify", modify_func }, - { "delete", remove_func }, - { "list", list_func }, - /* ---- End of Table marker ---- */ - { NULL, NULL } -}; - -/* - * []---- - * | process_config -- parse the main configuration file - * | - * | Everything in the configuratin file is optional. That's because - * | the management CLI can set the value to everything and update - * | the configuration. - * []---- - */ -static Boolean_t -process_config() -{ - tgt_node_t *node = NULL; - -#ifndef lint - LIBXML_TEST_VERSION; -#endif - - if (mgmt_get_main_config(&node) == False) { - return (False); - } - - main_vers_maj = XML_VERS_MAIN_MAJ; - main_vers_min = XML_VERS_MAIN_MIN; - if (validate_version(node, &main_vers_maj, &main_vers_min) == - False) { - syslog(LOG_ERR, "Target main config invalid"); - return (False); - } - - /* - * The base directory is optional in the sense that the daemon - * can start without it, but the daemon can't really do - * anything until the administrator sets the value. - */ - (void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR, - &target_basedir); - - /* - * These are optional settings for the target. Each of - * these has a default value which can be overwritten in - * the configuration. - */ - (void) tgt_find_value_str(node, XML_ELEMENT_TARGLOG, - &target_log); - (void) tgt_find_value_int(node, XML_ELEMENT_ISCSIPORT, - &iscsi_port); - (void) tgt_find_value_intchk(node, XML_ELEMENT_DBGLVL, &dbg_lvl); - (void) tgt_find_value_boolean(node, XML_ELEMENT_ENFORCE, - &enforce_strict_guid); - (void) tgt_find_value_boolean(node, XML_ELEMENT_THIN_PROVO, - &thin_provisioning); - (void) tgt_find_value_boolean(node, XML_ELEMENT_DISABLE_TPGS, - &disable_tpgs); - (void) tgt_find_value_boolean(node, XML_ELEMENT_TIMESTAMPS, - &dbg_timestamps); - (void) tgt_find_value_boolean(node, XML_ELEMENT_PGR_PERSIST, - &pgr_persist); - (void) tgt_find_value_str(node, XML_ELEMENT_PGR_BASEDIR, - &pgr_basedir); - if (tgt_find_value_intchk(node, XML_ELEMENT_LOGLVL, - &qlog_lvl) == True) - queue_log(True); - - main_config = node; - targets_config = node; - - return (True); -} - -/* - * []---- - * | logout_cleanup -- see if the initiator did what was requested - * | - * | When a target issues an asynchrouns event with the code set to - * | "logout requested" the initiator is supposed to respond with - * | a LogoutRequested PDU within a certain amount of time. If it - * | fails to do so, it's the targets responsibility to clean up. - * | We will check logout status in a 1 second interval, if the - * | initiators responded to the logout request then logout is - * | conpleted, if ASYNC_LOGOUT_TIMEOUT seconds (currently 10) - * | is reached then we will reissue the management request to - * | to logout which will cause the connections to close. - * []---- - */ -static void * -logout_cleanup(void *v) -{ - int msg_sent, i; - char *targ = (char *)v; - mgmt_request_t m; - iscsi_conn_t *conn; - extern pthread_mutex_t port_mutex; - Boolean_t logout = False; - - bzero(&m, sizeof (m)); - m.m_request = mgmt_logout; - m.m_q = queue_alloc(); - msg_sent = 0; - - /* - * The for loop is to manage the wait time for the - * logout request to complete, if logout completed - * before ASYNC_LOGOUT_TIMEOUT then done - */ - for (i = 0; i < ASYNC_LOGOUT_TIMEOUT; i++) { - logout = True; - (void) pthread_mutex_lock(&port_mutex); - for (conn = conn_head; conn; conn = conn->c_next) { - if ((conn->c_state == S7_LOGOUT_REQUESTED) && - (strcmp(conn->c_sess->s_t_name, targ) == 0)) { - logout = False; - break; - } - } - (void) pthread_mutex_unlock(&port_mutex); - if (logout) - break; - else - (void) sleep(1); - } - - /* - * Logout did not complete, queue message to shutdown - * connection. - */ - if (logout == False) { - (void) pthread_mutex_lock(&port_mutex); - for (conn = conn_head; conn; conn = conn->c_next) { - if ((conn->c_state == S7_LOGOUT_REQUESTED) && - (strcmp(conn->c_sess->s_t_name, targ) == 0)) { - queue_message_set(conn->c_dataq, 0, - msg_mgmt_rqst, &m); - msg_sent++; - } - } - (void) pthread_mutex_unlock(&port_mutex); - } - - /* - * Wait to see if they received the message. - */ - for (i = 0; i < msg_sent; i++) - queue_message_free(queue_message_get(m.m_q)); - queue_free(m.m_q, NULL); - free(targ); - - queue_message_set(mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - return ((void *)0); -} - -void -logout_targ(char *targ) -{ - mgmt_request_t m; - iscsi_conn_t *conn; - int i, msg_sent; - pthread_t junk; - extern pthread_mutex_t port_mutex; - - /* - * Now we look for connections to this target and issue - * a request to asynchronously logout. - */ - bzero(&m, sizeof (m)); - m.m_request = mgmt_logout; - m.m_q = queue_alloc(); - msg_sent = 0; - - (void) pthread_mutex_lock(&port_mutex); - for (conn = conn_head; conn; conn = conn->c_next) { - if (conn->c_state != S5_LOGGED_IN) - continue; - if (conn->c_sess->s_type == SessionDiscovery) - continue; - - if (strcmp(conn->c_sess->s_t_name, targ) == 0) { - queue_message_set(conn->c_dataq, 0, msg_mgmt_rqst, &m); - msg_sent++; - } - } - (void) pthread_mutex_unlock(&port_mutex); - - /* ---- Wait to see if they received the message. ---- */ - for (i = 0; i < msg_sent; i++) - queue_message_free(queue_message_get(m.m_q)); - - queue_free(m.m_q, NULL); - - /* ---- Start housecleaning thread ---- */ - (void) pthread_create(&junk, NULL, logout_cleanup, - (void *)strdup(targ)); -} - -/* - * [] ---- XML Management Handlers ---- [] - */ - -/* - * []---- - * | variable_handler -- used to set a couple of internal global variables - * []---- - */ -/*ARGSUSED*/ -void -variable_handler(tgt_node_t *x, target_queue_t *reply, target_queue_t *mgmt, - ucred_t *cred) -{ - char *reply_buf = NULL; - var_table_t *v; - tgt_node_t *c; - - if (check_auth_modify(cred) != True) { - xml_rtn_msg(&reply_buf, ERR_NO_PERMISSION); - queue_str(reply, 0, msg_mgmt_rply, reply_buf); - return; - } - for (c = x->x_child; c; c = c->x_sibling) { - - for (v = var_table; v->v_name; v++) { - if (strcmp(c->x_name, v->v_name) == 0) { - *v->v_value = strtol(c->x_value, NULL, 0); - if (strcmp(v->v_name, "qlog_lvl") == 0) - queue_log(True); - xml_rtn_msg(&reply_buf, ERR_SUCCESS); - break; - } - } - if (v->v_name == NULL) - xml_rtn_msg(&reply_buf, ERR_NO_MATCH); - - queue_str(reply, 0, msg_mgmt_rply, reply_buf); - } -} - -/* - * []---- - * | parse_xml -- incoming management requests are sent here for processing - * []---- - */ -static void -parse_xml(tgt_node_t *x, target_queue_t *reply, target_queue_t *mgmt, - ucred_t *cred) -{ - char *reply_msg = NULL; - cmd_table_t *c; - - if ((x->x_name == NULL) || (x->x_state == NodeFree)) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_EMPTY); - queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); - return; - } - - for (c = cmd_table; c->c_name != NULL; c++) - if (strcmp(c->c_name, x->x_name) == 0) - break; - if (c->c_name == NULL) { - xml_rtn_msg(&reply_msg, ERR_INVALID_COMMAND); - queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); - } else { - (c->c_func)(x, reply, mgmt, cred); - } -} - -/* - * space_message -- create a message indicating the amount of space needed. - * - * This code could have been inline in the server_for_door function, but - * at system startup we'll determine the minimum amount of space needed for - * a door call return pointer. This minimum amount of space will be either - * a "need more space" or a "success" message. So, have this code as a function - * reduces any duplication. - */ -static void -space_message(char **buf, int size) -{ - char lbuf[16]; - tgt_buf_add_tag_and_attr(buf, XML_ELEMENT_ERROR, "version='1.0'"); - (void) snprintf(lbuf, sizeof (lbuf), "%d", size); - tgt_buf_add(buf, XML_ELEMENT_MORESPACE, lbuf); - tgt_buf_add_tag(buf, XML_ELEMENT_ERROR, Tag_End); -} - -/*ARGSUSED*/ -static void -server_for_door(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, - uint_t n_desc) -{ - target_queue_t *mgmtq = (target_queue_t *)cookie; - mgmt_request_t m; - msg_t *msg = NULL; - tgt_node_t *node = NULL; - xmlTextReaderPtr r; - char *err_rply = NULL; - ucred_t *uc = NULL; - size_t cur_space; - - /* - * A well written application will always give us enough space - * to send either a "success" message or a "more space needed". - * If the minimum amount of space isn't given then just return - * with a NULL pointer. - */ - if (arg_size < door_min_space) { - (void) door_return(NULL, 0, NULL, 0); - return; - } - - /* - * Pick up the user credentials of the client application. Used to - * validate that the effective user ID is either root or the process - * has the privilege to complete the operation. - */ - if (door_ucred(&uc) != 0) { - xml_rtn_msg(&err_rply, ERR_BAD_CREDS); - (void) strlcpy(argp, err_rply, arg_size); - free(err_rply); - (void) door_return(argp, strlen(argp) + 1, NULL, 0); - return; - } - - if (validate_xml(argp) != True) { - xml_rtn_msg(&err_rply, ERR_INVALID_XML_REQUEST); - (void) strlcpy(argp, err_rply, arg_size); - free(err_rply); - (void) door_return(argp, strlen(argp) + 1, NULL, 0); - return; - } - - bzero(&m, sizeof (m)); - - if ((r = (xmlTextReaderPtr)xmlReaderForMemory(argp, strlen(argp), - NULL, NULL, 0)) != NULL) { - while (xmlTextReaderRead(r)) { - if (tgt_node_process(r, &node) == False) - break; - } - if (node != NULL) { - m.m_q = queue_alloc(); - m.m_request = mgmt_parse_xml; - m.m_time = time(NULL); - m.m_targ_name = NULL; - m.m_u.m_node = node; - m.m_cred = uc; - - queue_message_set(mgmtq, 0, msg_mgmt_rqst, &m); - if ((msg = queue_message_get(m.m_q)) == NULL) { - (void) xmlFreeTextReader(r); - (void) xmlCleanupParser(); - (void) ucred_free(uc); - tgt_node_free(node); - if (m.m_q != NULL) - queue_free(m.m_q, NULL); - (void) door_return("", 1, NULL, 0); - return; - } - - /* - * Check to see if the response can fit into the - * incoming argument buffer. If so, copy the response - * to that buffer so that we can free the data. - * If it's not big enough we'll request an updated - * space message, then delete the current data, allowing - * the request to be requeued again. - */ - if ((cur_space = strlen(msg->msg_data)) < arg_size) { - (void) strlcpy(argp, msg->msg_data, arg_size); - } else { - /* - * err_rply will be copied to argp at the end - */ - space_message(&err_rply, cur_space + 1); - } - free(msg->msg_data); - queue_message_free(msg); - } else { - xml_rtn_msg(&err_rply, ERR_NULL_XML_MESSAGE); - } - - xmlFreeTextReader(r); - xmlCleanupParser(); - - } else { - xml_rtn_msg(&err_rply, ERR_INIT_XML_READER_FAILED); - } - - if (node != NULL) - tgt_node_free(node); - if (err_rply != NULL) { - (void) strlcpy(argp, err_rply, arg_size); - free(err_rply); - } - if (m.m_q != NULL) - queue_free(m.m_q, NULL); - - ucred_free(uc); - (void) door_return(argp, strlen(argp) + 1, NULL, 0); -} - -/* - * []---- - * | setup_door -- Create a door portal for management requests - * | - * | First check to see if another daemon is already running by attempting - * | to send an empty request to the door. If successful it means this - * | daemon should exit. - * []---- - */ -static void -setup_door(target_queue_t *q, char *door_name) -{ - int did, fd; - struct stat s; - door_arg_t d; - char *msg = NULL; - - /* - * Figure out what the minimum amount of space required to send back - * either a success message or a need more space one. - * - * Commands fall into one of three categories. - * (1) Idempotent commands, like list operations, which can - * return large ammounts of data. If there's not enough room - * the client is informed and the command is run again with a - * larger buffer. - * (2) Create, modify, or delete operations that fail. These - * commands may return an error message which is larger than - * the incoming request buffer. If so, the client is informed - * that a larger buffer is needed and the command is rerun. This - * time it'll recieve the full error message. So, these commands - * are idempotent because no state changes occur on failure. - * (3) Create, modify, or delete operations which are successful. - * Since successful completion means state has change the daemon - * must always be able to report success, other wise a second - * attempt with a larger buffer would then fail, where the first - * one actually succeeded. - */ - xml_rtn_msg(&msg, ERR_SUCCESS); - door_min_space = strlen(msg); - free(msg); - msg = NULL; - /* - * Use an impossibly big number which will create the longest string - */ - space_message(&msg, 0x80000000); - door_min_space = MAX(door_min_space, strlen(msg)); - free(msg); - - door_min_space++; /* add 1 for the NULL byte */ - - /* - * DOOR_MIN_SPACE will be the amount used by the library as the default. - * Currently this will be set to 128 (check iscsitgt_impl.h for value). - * Since this will be a compiled value and the "success" or "more space" - * messages could grown we need to detect if there will be a problem. - * By failing here consistently, SMF will put the daemon in maintenance - * state and this will be caught during testing. Otherwise the library - * would receive a NULL back, but not know how much space is really - * required. - */ - if (door_min_space > DOOR_MIN_SPACE) { - syslog(LOG_ERR, - "Calculated min space (%d) is larger than default (%d)", - door_min_space, DOOR_MIN_SPACE); - assert(0); - } - - if ((fd = open(door_name, 0)) >= 0) { - - /* - * There's at least a file with the same name as our - * door. Let's see if someone is currently answering - * by sending an empty XML request. - */ - d.data_ptr = "<config></config>"; - d.data_size = strlen(d.data_ptr) + 1; - d.desc_ptr = NULL; - d.desc_num = 0; - d.rbuf = NULL; - d.rsize = 0; - - if (door_call(fd, &d) == 0) { - - /* - * If the door_call succeeds that means another - * daemon is already running so let's just exit. - */ - exit(0); - } - (void) close(fd); - } - - if ((did = door_create(server_for_door, (void *)q, 0)) < 0) { - syslog(LOG_ERR, "door_create"); - exit(1); - } - - if (stat(door_name, &s) < 0) { - int newfd; - if ((newfd = creat(door_name, 0666)) < 0) { - syslog(LOG_ERR, "creat failed"); - exit(1); - } - (void) close(newfd); - } - (void) fdetach(door_name); - - /* - * Open the door for general access. As the calls come in we'll - * get the credentials and validate within each operation as to the - * required privileges. - */ - (void) chmod(door_name, 0666); - - if (fattach(did, door_name) < 0) { - syslog(LOG_ERR, "fattach failed errno=%d", errno); - exit(2); - } -} - -/*ARGSUSED*/ -void -exit_after_door_setup(int sig, siginfo_t *sip, void *v) -{ - exit(SMF_EXIT_OK); -} - -int -main(int argc, char **argv) -{ - char c, *p, *door_name; - msg_t *msg; - target_queue_t *q; - port_args_t port1, port2; - Boolean_t mgmt_up = False; - Boolean_t daemonize = True; - Boolean_t console_output = True; - pthread_t junk; - mgmt_request_t *mgmt; - struct sigaction act; - struct rlimit rl; - void *thr_status; - - door_name = ISCSI_TARGET_MGMT_DOOR; - - while ((c = getopt(argc, argv, "c:d:")) != EOF) { - switch (c) { - case 'c': - config_file = optarg; - break; - case 'd': - door_name = optarg; - break; - } - } - - /* - * If the initiator closes the socket because of a protocol error - * or bad digest on the header packet we'll receive a SIGPIPE if we're - * in the middle of a write operation. There's no need to receive - * a signal when a -1 from the write will handle things correctly. - * So, ignore SIGPIPE's. - */ - (void) sigignore(SIGPIPE); - - /* - * Setup memory caches - */ - if ((iscsi_cmd_cache = umem_cache_create("iSCSI conn cmds", - sizeof (iscsi_cmd_t), 8, NULL, NULL, NULL, NULL, NULL, 0)) == - NULL) { - perror("cache create"); - exit(SMF_EXIT_ERR_CONFIG); - } - if ((t10_cmd_cache = umem_cache_create("T10 cmds", - sizeof (t10_cmd_t), 8, NULL, NULL, NULL, NULL, NULL, 0)) == NULL) { - perror("cache create"); - exit(SMF_EXIT_ERR_CONFIG); - } - if ((queue_cache = umem_cache_create("Queue messages", - sizeof (msg_t), 8, NULL, NULL, NULL, NULL, NULL, 0)) == NULL) { - perror("cache create"); - exit(SMF_EXIT_ERR_CONFIG); - } - - /* - * Look at the function lu_buserr_handler() in t10_sam.c to see the - * details of why we need to handle segmentation violations. - */ - bzero(&act, sizeof (act)); - act.sa_sigaction = lu_buserr_handler; - act.sa_flags = SA_SIGINFO; - - if (sigaction(SIGBUS, &act, NULL) == -1) { - perror("sigaction"); - exit(SMF_EXIT_ERR_CONFIG); - } - - - if (mgmt_convert_conf() == CONVERT_FAIL) - exit(SMF_EXIT_ERR_CONFIG); - - if (process_config() == False) - exit(SMF_EXIT_ERR_CONFIG); - - /* - * During the normal corse of events 'target_basedir' will be - * free when the administrator changes the base directory. Instead - * of trying to check for the initial case of this value being set - * to some static string, always allocate that string. - * NOTE: This must be done *after* process_config() is called since - * it's possible and very likely that this value will be set at that - * time. - */ - if (target_basedir == NULL) - target_basedir = strdup(DEFAULT_TARGET_BASEDIR); - - (void) tgt_find_value_boolean(main_config, XML_ELEMENT_DBGDAEMON, - &daemonize); - - q = queue_alloc(); - if (daemonize == True) { - closefrom(0); - - /* - * Set up a signal handler to catch SIGUSR2. Once the child - * has setup the door, it will signal the parent that it's - * safe to exit. Without doing this it's possible that the - * daemon will start and the parent exit before the child has - * setup the door. If that happens 'zfs share -a iscsi' which - * is run from svc-iscsitgt will fail to open the door and try - * to wait for the iscsitgt service to come online. Since - * the zfs command is part of the service start, the service - * will not come online and we'll fail to share any ZVOLs. - */ - bzero(&act, sizeof (act)); - act.sa_sigaction = exit_after_door_setup; - act.sa_flags = SA_SIGINFO; - if (sigaction(SIGUSR2, &act, NULL) == -1) { - perror("sigaction"); - exit(SMF_EXIT_ERR_CONFIG); - } - - switch (fork()) { - case 0: - /* - * As the child process, setup the door and then - * signal the parent that it can exit since the child - * is now ready to start accepting requests on the - * door. - */ - setup_door(q, door_name); - (void) kill(getppid(), SIGUSR2); - break; - - case -1: - /* ---- Failed to fork!. Trouble ---- */ - exit(SMF_EXIT_ERR_CONFIG); - - default: - /* - * If pause() returns with an error something - * interrupted the process which was not a SIGUSR2. - * Exit with an error code such that SMF can flag - * this problem. - */ - if (pause() == -1) - exit(SMF_EXIT_ERR_CONFIG); - } - } else { - - /* - * The daemon is working in debug mode, so go ahead and - * setup the door now. - */ - setup_door(q, door_name); - } - - /* - * Initialize the various subsystems. In most cases these are - * just initializing mutexs. - */ - (void) pthread_rwlock_init(&targ_config_mutex, NULL); - iscsi_cmd_init(); - session_init(); - t10_init(q); - port_init(); - queue_init(); - util_init(); - (void) isns_init(q); - - /* - * If there's no MAC address currently available don't worry about - * it. The first time an initiator connects the SAM-3 layer will - * attempt to create a GUID and force another look for a MAC address. - */ - if (if_find_mac(q) == False) - queue_prt(q, Q_GEN_DETAILS, "MAIN: No MAC address available"); - - /* - * At a minimum we need two file descriptors for each target, one for - * the socket and one for the backing store. If there's more than one - * initiator attached to a given target than that number goes up by 1. - * Once we have multiple sessions per connection that to will cause - * an increase. - */ - if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && - (rl.rlim_cur < TARGET_NOFILE)) { - rl.rlim_cur = TARGET_NOFILE; - if (setrlimit(RLIMIT_NOFILE, &rl) != 0) - syslog(LOG_NOTICE, - "Can't set new limit for open files"); - } - - port1.port_mgmtq = q; - port1.port_num = iscsi_port; - (void) pthread_create(&junk, NULL, port_watcher, &port1); - - if ((tgt_find_value_int(main_config, XML_ELEMENT_MGMTPORT, - &port2.port_num) == True) && (port2.port_num != -1)) { - port2.port_mgmtq = q; - port2.port_dataq = queue_alloc(); - (void) pthread_create(&junk, NULL, port_management, &port2); - } - - do { - msg = queue_message_get(q); - - switch (msg->msg_type) { - case msg_pthread_join: - (void) pthread_join((pthread_t)(uintptr_t)msg->msg_data, - &thr_status); - if (thr_status != 0) - queue_prt(q, Q_GEN_ERRS, - "Thread %d exit with %d", - msg->msg_data, thr_status); - msg->msg_data = NULL; - break; - - case msg_log: - if ((p = strchr(msg->msg_data, '\n')) != NULL) - *p = '\0'; - p = (char *)msg->msg_data; - if ((msg->msg_pri_level & dbg_lvl) == 0) - break; - - if (mgmt_up == True) - queue_str(port2.port_dataq, Q_GEN_DETAILS, - msg_log, p); - if (console_output == True) - (void) printf("%s\n", p); - break; - - case msg_mgmt_rqst: - mgmt = (mgmt_request_t *)msg->msg_data; - if (mgmt->m_request == mgmt_parse_xml) - parse_xml(mgmt->m_u.m_node, mgmt->m_q, q, - mgmt->m_cred); - msg->msg_data = NULL; - break; - - case msg_status: - p = (char *)msg->msg_data; - /* - * NOTE: - * These are real error conditons being sent from - * the other threads and should be logged in - * some manner, either syslog() or using a FMA - * interface. - */ - (void) printf("STATUS: %s\n", p); - break; - - default: - break; - } - - if (msg->msg_data != NULL) - free(msg->msg_data); - queue_message_free(msg); - /*CONSTANTCONDITION*/ - } while (1); - - return (0); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt.c b/usr/src/cmd/iscsi/iscsitgtd/mgmt.c deleted file mode 100644 index e0af446b8e..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <unistd.h> -#include <strings.h> -#include <stdlib.h> -#include <poll.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <netinet/in.h> -#include <sys/filio.h> -#include <utility.h> -#include <synch.h> -#include <sys/stropts.h> -#include <libxml/xmlreader.h> -#include <iscsitgt_impl.h> - -#include "queue.h" -#include "port.h" -#include "utility.h" - -static void -mgmt_monitor_queue(port_args_t *p) -{ - target_queue_t *in = p->port_dataq; - msg_t *m; - int process = True; - char *data, - *output; - - do { - m = queue_message_get(in); - switch (m->msg_type) { - case msg_conn_lost: - process = False; - break; - - case msg_log: - data = (char *)m->msg_data; - output = NULL; - tgt_buf_add(&output, "log", data); - (void) write(p->port_socket, output, strlen(output)); - free(output); - break; - - case msg_mgmt_rply: - data = (char *)m->msg_data; - output = NULL; - tgt_buf_add(&output, "mgmt", data); - (void) write(p->port_socket, output, strlen(output)); - free(output); - free(data); - m->msg_data = NULL; - break; - - default: - break; - } - - if (m->msg_data) - free(m->msg_data); - queue_message_free(m); - - } while (process == True); -} - -static void * -mgmt_process(void *v) -{ - port_args_t *p = (port_args_t *)v; - int nbytes, - nmsgs, - pval, - ret; - char *buf; - nfds_t nfds = 1; - struct pollfd fds[1]; - xmlTextReaderPtr r; - tgt_node_t *node = NULL; - mgmt_request_t m; - - fds[0].fd = p->port_socket; - fds[0].events = POLLIN; - - m.m_q = p->port_dataq; - m.m_request = mgmt_parse_xml; - m.m_time = time(NULL); - m.m_targ_name = NULL; - - while ((pval = poll(fds, nfds, -1)) != -1) { - if ((nmsgs = ioctl(p->port_socket, FIONREAD, &nbytes)) == -1) { - - queue_message_set(p->port_dataq, 0, msg_conn_lost, 0); - break; - - } else if ((nmsgs == 0) && (nbytes == 0)) { - - queue_message_set(p->port_dataq, 0, msg_conn_lost, 0); - break; - - } else if ((buf = malloc(nbytes)) == NULL) { - - queue_message_set(p->port_dataq, 0, msg_conn_lost, 0); - break; - - } else if (read(p->port_socket, buf, nbytes) != nbytes) { - - queue_message_set(p->port_dataq, 0, msg_conn_lost, 0); - break; - - } - - buf[nbytes] = '\0'; - r = (xmlTextReaderPtr)xmlReaderForMemory(buf, nbytes, - NULL, NULL, 0); - if (r != NULL) { - ret = xmlTextReaderRead(r); - while (ret == 1) { - if (tgt_node_process(r, &node) == False) - break; - ret = xmlTextReaderRead(r); - } - if (node != NULL) { - m.m_u.m_node = node; - queue_message_set(p->port_mgmtq, 0, - msg_mgmt_rqst, &m); - } - xmlFreeTextReader(r); - tgt_node_free(node); - node = NULL; - } - - } - - if (pval == -1) - queue_message_set(p->port_dataq, 0, msg_conn_lost, 0); - (void) close(p->port_socket); - p->port_socket = -1; - return (NULL); -} - -void * -port_management(void *v) -{ - int s, - fd, - on = 1; - struct sockaddr_in sin_ip; - struct sockaddr_in6 sin6_ip; - socklen_t fromlen; - struct sockaddr_storage from; - port_args_t *p = (port_args_t *)v; - target_queue_t *q = p->port_mgmtq; - int l; - pthread_t junk; - char debug[80]; - - if ((s = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { - if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { - queue_str(q, Q_GEN_ERRS, msg_status, - "Can't open socket"); - return (NULL); - } else { - - bzero(&sin_ip, sizeof (sin_ip)); - sin_ip.sin_family = AF_INET; - sin_ip.sin_port = htons(p->port_num); - sin_ip.sin_addr.s_addr = INADDR_ANY; - - (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof (on)); - - if ((bind(s, (struct sockaddr *)&sin_ip, - sizeof (sin_ip))) < 0) { - (void) snprintf(debug, sizeof (debug), - "bind on port %d failed\n", p->port_num); - queue_str(q, Q_GEN_ERRS, msg_status, debug); - return (NULL); - } - } - } else { - - bzero(&sin6_ip, sizeof (sin6_ip)); - sin6_ip.sin6_family = AF_INET6; - sin6_ip.sin6_port = htons(p->port_num); - sin6_ip.sin6_addr = in6addr_any; - - (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, - sizeof (on)); - - if ((bind(s, (struct sockaddr *)&sin6_ip, sizeof (sin6_ip))) - < 0) { - (void) snprintf(debug, sizeof (debug), - "bind on port %d failed\n", - p->port_num); - queue_str(q, Q_GEN_ERRS, msg_status, debug); - return (NULL); - } - } - - if (listen(s, 5) < 0) { - queue_str(q, Q_GEN_ERRS, msg_status, "listen failed"); - return (NULL); - } - - /*CONSTANTCONDITION*/ - while (1) { - fromlen = sizeof (from); - if ((fd = accept(s, (struct sockaddr *)&from, - &fromlen)) < 0) { - queue_str(q, Q_GEN_ERRS, msg_status, "accept failed"); - return (NULL); - } - - l = 128 * 1024; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&l, - sizeof (l)) < 0) - queue_str(q, Q_GEN_ERRS, msg_status, - "setsockopt failed"); - - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&l, - sizeof (l)) < 0) - queue_str(q, Q_GEN_ERRS, msg_status, - "setsockopt failed"); - - - p->port_socket = fd; - (void) pthread_create(&junk, NULL, mgmt_process, p); - - mgmt_monitor_queue(p); - } - return (NULL); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt_create.c b/usr/src/cmd/iscsi/iscsitgtd/mgmt_create.c deleted file mode 100644 index fffd6e99df..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_create.c +++ /dev/null @@ -1,1447 +0,0 @@ -/* - * 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 <ctype.h> -#include <sys/types.h> -#include <time.h> -#include <sys/utsname.h> -#include <unistd.h> -#include <sys/param.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <sys/statvfs.h> -#include <errno.h> -#include <strings.h> -#include <sys/vtoc.h> -#include <sys/efi_partition.h> -#include <uuid/uuid.h> -#include <sys/scsi/impl/uscsi.h> -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/impl/commands.h> -#include <libzfs.h> -#include <syslog.h> -#include <priv.h> - -#include <iscsitgt_impl.h> -#include "queue.h" -#include "target.h" -#include "iscsi_cmd.h" -#include "utility.h" -#include "errcode.h" -#include "t10_spc.h" -#include "isns_client.h" -#include "mgmt_scf.h" - -extern char *getfullrawname(); - -static char *create_target(tgt_node_t *); -static char *create_initiator(tgt_node_t *); -static char *create_tpgt(tgt_node_t *); -static char *create_zfs(tgt_node_t *, ucred_t *); -static Boolean_t create_target_dir(char *targ_name, char *local_name); -static char *create_node_name(char *local_nick, char *alias); -static Boolean_t create_lun(char *targ_name, char *local_name, char *type, - int lun, char *size_str, char *backing, err_code_t *code); -static Boolean_t create_lun_common(char *targ_name, char *local_name, int lun, - uint64_t size, err_code_t *code); -static Boolean_t setup_disk_backing(err_code_t *code, char *path, char *backing, - tgt_node_t *n, uint64_t *size); -static Boolean_t setup_raw_backing(err_code_t *code, char *path, char *backing, - uint64_t *size); - -/* - * []---- - * | create_func -- Branch out to appropriate object create function - * []---- - */ -/*ARGSUSED*/ -void -create_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, - ucred_t *cred) -{ - tgt_node_t *x; - char msgbuf[80]; - char *reply_msg = NULL; - - x = p->x_child; - - /* - * create_zfs() does not affect SMF data - * therefore it is not covered by auth check - */ - if (x == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { - reply_msg = create_zfs(x, cred); - } else if (check_auth_addremove(cred) != True) { - xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); - } else { - if (x->x_name == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { - reply_msg = create_target(x); - } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { - reply_msg = create_initiator(x); - } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { - reply_msg = create_tpgt(x); - } else { - (void) snprintf(msgbuf, sizeof (msgbuf), - "Unknown object '%s' for create element", - x->x_name); - xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); - } - } - queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); -} - -/* - * create_target -- an administrative request to create a target - */ -static char * -create_target(tgt_node_t *x) -{ - char *msg = NULL; - char *name = NULL; - char *alias = NULL; - char *size = NULL; - char *type = NULL; - char *backing = NULL; - char *node_name = NULL; - char path[MAXPATHLEN]; - int lun = 0; /* default to LUN 0 */ - int i; - tgt_node_t *n, *c, *l; - err_code_t code; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - (void) tgt_find_value_str(x, XML_ELEMENT_BACK, &backing); - (void) tgt_find_value_str(x, XML_ELEMENT_ALIAS, &alias); - if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun) == False) { - xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); - goto error; - } - - /* - * We've got to have a name element or all bets are off. - */ - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - /* - * RFC3722 states that names must be one of: - * (1) a..z - * (2) A..Z - * (3) 0-9 - * or - * (4) ':', '.', '-' - * If it's an upper case character is must be made lower - * case. - */ - for (i = 0; i < strlen(name); i++) { - if (!isalnum(name[i]) && - (name[i] != ':') && (name[i] != '.') && (name[i] != '-')) { - xml_rtn_msg(&msg, ERR_SYNTAX_INVALID_NAME); - goto error; - } else if (isupper(name[i])) - name[i] = tolower(name[i]); - } - - if (tgt_find_value_str(x, XML_ELEMENT_TYPE, &type) == False) { - /* - * If a type hasn't been specified default to disk emulation. - * We use strdup() since at the end of this routine the code - * is expecting to free 'type' along with other strings. - */ - type = strdup(TGT_TYPE_DISK); - } - - if ((strcmp(type, "raw") == 0) && (backing == NULL)) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_BACKING_STORE); - goto error; - } - - if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &size) == False) { - if (backing != NULL) { - - /* - * If a backing store has been provided we don't - * need the size since we can determine that from - * a READ_CAPACITY command which everyone issues. - * - * NOTE: strdup is used here, since at the end - * of this routine any of the string pointers which - * are non-NULL get freed. - */ - size = strdup("0"); - } else { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_SIZE); - goto error; - } - } - if ((lun < 0) || (lun > T10_MAX_LUNS)) { - xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); - goto error; - } - - /* - * See if we already have a local target name created. If so, - * the user is most likely wanting to create another LUN for this - * target. Checking to see if there's a duplicate LUN will be - * done later. - */ - for (n = main_config->x_child; n; n = n->x_sibling) { - if (strcmp(n->x_value, name) == 0) - break; - } - - if (n == NULL) { - if (lun != 0) { - xml_rtn_msg(&msg, ERR_LUN_ZERO_NOT_FIRST); - goto error; - } - if ((node_name = create_node_name(name, alias)) == NULL) { - xml_rtn_msg(&msg, ERR_CREATE_NAME_TOO_LONG); - goto error; - } - if (create_target_dir(node_name, name) == False) { - xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED); - goto error; - } - n = tgt_node_alloc(XML_ELEMENT_TARG, String, name); - c = tgt_node_alloc(XML_ELEMENT_INAME, String, node_name); - tgt_node_add(n, c); - c = tgt_node_alloc(XML_ELEMENT_LUNLIST, String, ""); - l = tgt_node_alloc(XML_ELEMENT_LUN, Int, &lun); - tgt_node_add(c, l); - tgt_node_add(n, c); - if (alias != NULL) { - c = tgt_node_alloc(XML_ELEMENT_ALIAS, String, alias); - tgt_node_add(n, c); - } - tgt_node_add(targets_config, n); - - } else { - if (tgt_find_value_str(n, XML_ELEMENT_INAME, - &node_name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_INAME); - goto error; - } - if ((c = tgt_node_next(n, XML_ELEMENT_LUNLIST, NULL)) == NULL) { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - goto error; - } - l = tgt_node_alloc(XML_ELEMENT_LUN, Int, &lun); - tgt_node_add(c, l); - } - - if (create_lun(node_name, name, type, lun, size, backing, &code) - == True) { - if (mgmt_config_save2scf() == False) { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - goto error; - } - - /* Only isns register on the 1st creation of the target */ - if (lun == 0 && isns_enabled() == True) { - if (isns_reg(node_name) != 0) { - xml_rtn_msg(&msg, ERR_ISNS_ERROR); - goto error; - } - } - - } else if ((lun == 0) && (code != ERR_LUN_EXISTS)) { - - /* - * The first LU will have created the directory and - * symbolic link. Remove those on error. - */ - (void) snprintf(path, sizeof (path), "%s/%s", - target_basedir, node_name); - (void) rmdir(path); - (void) snprintf(path, sizeof (path), "%s/%s", - target_basedir, name); - (void) unlink(path); - (void) tgt_node_remove(targets_config, n, MatchBoth); - } else - (void) tgt_node_remove(c, l, MatchBoth); - - xml_rtn_msg(&msg, code); - -error: - if (name != NULL) - free(name); - if (size != NULL) - free(size); - if (alias != NULL) - free(alias); - if (backing != NULL) - free(backing); - if (node_name != NULL) - free(node_name); - if (type != NULL) - free(type); - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -static char * -create_initiator(tgt_node_t *x) -{ - char *msg = NULL; - char *name = NULL; - char *iscsi_name = NULL; - tgt_node_t *inode = NULL; - tgt_node_t *n, *c; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - if (tgt_find_value_str(x, XML_ELEMENT_INAME, &iscsi_name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_INAME); - goto error; - } - if (strlen(iscsi_name) >= ISCSI_MAX_NAME_LEN) { - xml_rtn_msg(&msg, ERR_NAME_TOO_LONG); - goto error; - } - - while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, - inode)) != NULL) { - if (strcmp(inode->x_value, name) == 0) { - xml_rtn_msg(&msg, ERR_INIT_EXISTS); - goto error; - } - } - - n = tgt_node_alloc(XML_ELEMENT_INIT, String, name); - c = tgt_node_alloc(XML_ELEMENT_INAME, String, iscsi_name); - tgt_node_add(n, c); - tgt_node_add(main_config, n); - - if (mgmt_config_save2scf() == True) - xml_rtn_msg(&msg, ERR_SUCCESS); - else - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - -error: - if (name) - free(name); - if (iscsi_name) - free(iscsi_name); - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -static char * -create_tpgt(tgt_node_t *x) -{ - char *msg = NULL; - char *tpgt = NULL; - char *extra = NULL; - tgt_node_t *tnode = NULL; - tgt_node_t *n; - int tpgt_val; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &tpgt) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - /* ---- Validation checks ---- */ - tpgt_val = strtol(tpgt, &extra, 0); - if ((extra && (*extra != '\0')) || - (tpgt_val < TPGT_MIN) || (tpgt_val > TPGT_MAX)) { - xml_rtn_msg(&msg, ERR_INVALID_TPGT); - goto error; - } - - while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, - tnode)) != NULL) { - if (strcmp(tnode->x_value, tpgt) == 0) { - xml_rtn_msg(&msg, ERR_TPGT_EXISTS); - goto error; - } - } - - n = tgt_node_alloc(XML_ELEMENT_TPGT, String, tpgt); - tgt_node_add(main_config, n); - - if (mgmt_config_save2scf() == True) - xml_rtn_msg(&msg, ERR_SUCCESS); - else - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - -error: - if (tpgt) - free(tpgt); - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -/* - * create_zfs -- given a dataset, export it through the iSCSI protocol - * - * This function is called when someone uses the libiscsitgt function - * iscsitgt_zfs_share(char *dataset) - */ -static char * -create_zfs(tgt_node_t *x, ucred_t *cred) -{ - char *msg = NULL; - char *dataset = NULL; - char *cptr = NULL; - char path[MAXPATHLEN]; - tgt_node_t *n = NULL; - tgt_node_t *c; - tgt_node_t *l; - uint64_t size; - int status; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - /* - * Extract the dataset name from the arguments passed in - */ - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - /* - * Since this is a create, assure that an existing dataset with the - * same name does not exists - */ - c = NULL; - while ((c = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, c))) { - if (strcmp(c->x_value, dataset) == 0) { - xml_rtn_msg(&msg, ERR_LUN_EXISTS); - goto error; - } - } - - /* - * See if this is a re-create of a previously create ZVOL target - * If no shareiscsi properties exists, create a new set of properties - */ - status = get_zfs_shareiscsi(dataset, &n, &size, cred); - if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) { - xml_rtn_msg(&msg, status); - goto error; - } else if (status == ERR_NULL_XML_MESSAGE) { - - char *name; - int lun = 0; - int guid = 0; - int rpm = DEFAULT_RPM; - int heads = DEFAULT_HEADS; - int cylinders = DEFAULT_CYLINDERS; - int spt = DEFAULT_SPT; - int bytes_sect = DEFAULT_BYTES_PER; - int interleave = DEFAULT_INTERLEAVE; - - n = tgt_node_alloc(XML_ELEMENT_TARG, String, NULL); - c = tgt_node_alloc(XML_ELEMENT_INCORE, String, XML_VALUE_TRUE); - tgt_node_add_attr(n, c); - - if (name = create_node_name(NULL, NULL)) { - c = tgt_node_alloc(XML_ELEMENT_INAME, String, name); - tgt_node_add(n, c); - free(name); - } else { - xml_rtn_msg(&msg, ERR_CREATE_NAME_TOO_LONG); - goto error; - } - - c = tgt_node_alloc(XML_ELEMENT_LUNLIST, String, ""); - tgt_node_add(n, c); - - l = tgt_node_alloc(XML_ELEMENT_LUN, Int, &lun); - tgt_node_add(c, l); - - c = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0"); - tgt_node_add_attr(l, c); - - c = tgt_node_alloc(XML_ELEMENT_GUID, Int, &guid); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_PID, String, DEFAULT_PID); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_VID, String, DEFAULT_VID); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_DTYPE, String, TGT_TYPE_DISK); - tgt_node_add(l, c); - - create_geom(size, &cylinders, &heads, &spt); - - c = tgt_node_alloc(XML_ELEMENT_RPM, Int, &rpm); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_HEADS, Int, &heads); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_CYLINDERS, Int, &cylinders); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_SPT, Int, &spt); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_BPS, Int, &bytes_sect); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_INTERLEAVE, Int, &interleave); - tgt_node_add(l, c); - - c = tgt_node_alloc(XML_ELEMENT_STATUS, String, - TGT_STATUS_ONLINE); - tgt_node_add(l, c); - - /* - * Set the ZFS persisted shareiscsi options - */ - if ((status = put_zfs_shareiscsi(dataset, n)) != ERR_SUCCESS) { - xml_rtn_msg(&msg, status); - goto error; - } - } else { - /* - * If the was a recreate of a ZVOL iSCSI Target, 'n' is expected - * to contain the properties for this iSCSI target node - * - * Make sure these properties have the "in-core" attribute - */ - if (tgt_find_attr_str(n, XML_ELEMENT_INCORE, &cptr) == True) { - if (strcmp(cptr, "true") != 0) { - free(cptr); - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - goto error; - } - free(cptr); - } - } - - /* - * Pick up the LU node from the LU List which hangs off of the target - * node. If either is NULL there's an internal error someplace. - */ - if (((l = tgt_node_next(n, XML_ELEMENT_LUNLIST, NULL)) == NULL) || - ((l = tgt_node_next(l, XML_ELEMENT_LUN, NULL)) == NULL)) { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - goto error; - } - - /* - * With ZVOLS, some elements can change everytime we share the dataset. - * The TargetAlias and backing store can change since these are based on - * the dataset and the size of the volume. Therefore, these pieces of - * information are not stored as part of the iscsioptions properity, but - * are retained in the in-core targets_config - */ - (void) tgt_update_value_str(n, XML_ELEMENT_TARG, dataset); - c = tgt_node_alloc(XML_ELEMENT_ALIAS, String, dataset); - tgt_node_add(n, c); - - (void) snprintf(path, sizeof (path), "%s%s", ZVOL_PATH, dataset); - c = tgt_node_alloc(XML_ELEMENT_BACK, String, path); - tgt_node_add(l, c); - - size /= 512LL; - c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &size); - tgt_node_add(l, c); - - cptr = NULL; - if (tgt_find_value_str(n, XML_ELEMENT_INAME, &cptr) != True) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_INAME); - goto error; /* xml node contruction has an issue. */ - } - - /* - * Add ZVOL target to config of all targets - */ - tgt_node_add(targets_config, n); - n = NULL; /* don't remove the node from the targets_config. */ - - /* register with iSNS */ - if (isns_enabled() == True) { - if (isns_reg(cptr) != 0) { - xml_rtn_msg(&msg, ERR_ISNS_ERROR); - goto error; - } - } - - xml_rtn_msg(&msg, ERR_SUCCESS); - -error: - if (cptr) - free(cptr); - if (dataset) - free(dataset); - if (n) - tgt_node_free(n); - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -/* - * []------------------------------------------------------------------[] - * | Utility functions used by the routines above. | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | create_node_name -- Creates the IQN that adhears to RFC3270 - * []---- - */ -static char * -create_node_name(char *local_nick, char *alias) -{ - uuid_t id; - char id_str[37]; - char *p; - char *anp; /* alias or nick pointer */ - - if ((p = (char *)malloc(ISCSI_MAX_NAME_LEN)) == NULL) - return (NULL); - - /* - * Originally we we going to use the machines MAC address and - * timestamp in hex format. This would be consistent with the - * Solaris iSCSI initiator and NAS5310. Unfortunately, someone - * pointed out that there's no requirement that the network - * interfaces be plumbed before someone attempts to create - * targets. If the networks aren't plumbed there are no MAC - * addresses available and we can't use 0 for the MAC address - * since that would introduce the probability of non-unique - * IQN names. - */ - uuid_generate(id); - uuid_unparse(id, id_str); - if (snprintf(p, ISCSI_MAX_NAME_LEN, "iqn.1986-03.com.sun:%02d:%s", - TARGET_NAME_VERS, id_str) > ISCSI_MAX_NAME_LEN) { - free(p); - return (NULL); - } - if (local_nick || alias) { - anp = (alias != NULL) ? alias : local_nick; - - /* - * Make sure we still have room to add the alias or - * local nickname, a '.', and NULL character to the - * buffer. - */ - if ((strlen(p) + strlen(anp) + 2) > ISCSI_MAX_NAME_LEN) { - free(p); - return (NULL); - } - (void) strcat(p, "."); - (void) strcat(p, anp); - } - - return (p); -} - -/* - * []---- - * | create_target_dir -- create the target directory - * []---- - */ -static Boolean_t -create_target_dir(char *targ_name, char *local_name) -{ - char path[MAXPATHLEN]; - char sympath[MAXPATHLEN]; - - if ((mkdir(target_basedir, 0777) == -1) && (errno != EEXIST)) - return (False); - - (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, - targ_name); - (void) snprintf(sympath, sizeof (sympath), "%s/%s", target_basedir, - local_name); - - if ((mkdir(path, 0777) == -1) && (errno != EEXIST)) - return (False); - - /* - * This symbolic link is here for convenience and nothing more, so if - * if fails. Oh well. - */ - (void) symlink(path, sympath); - return (True); -} - -/* - * []---- - * | create_lun -- given type, lun, size, backing create LU and params - * []---- - */ -static Boolean_t -create_lun(char *targ_name, char *local_name, char *type, int lun, - char *size_str, char *backing, err_code_t *code) -{ - uint64_t size, ssize; - int fd = -1; - int rpm = DEFAULT_RPM; - int heads = DEFAULT_HEADS; - int cylinders = DEFAULT_CYLINDERS; - int spt = DEFAULT_SPT; - int bytes_sect = DEFAULT_BYTES_PER; - int interleave = DEFAULT_INTERLEAVE; - char *vid = DEFAULT_VID; - char *pid = DEFAULT_PID; - char path[MAXPATHLEN]; - tgt_node_t *n = NULL; - tgt_node_t *pn = NULL; - - /* - * after calling stroll_multipler it's an error for size to be - * 0, if and only if, the size_str doesn't equal "0". The administrator - * may want the code to determine the size. This would be the case - * when the administrator has provide a backing store which exists. - */ - if ((strtoll_multiplier(size_str, &size) == False) || - ((size == 0) && (size_str != NULL) && strcmp(size_str, "0"))) { - *code = ERR_INVALID_SIZE; - return (False); - } - - if ((size % 512) != 0) { - *code = ERR_SIZE_MOD_BLOCK; - return (False); - } - - /* - * Make sure we're not trying to recreate an existing LU. - */ - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, - targ_name, LUNBASE, lun); - if (access(path, F_OK) == 0) { - *code = ERR_LUN_EXISTS; - return (False); - } - - n = tgt_node_alloc(XML_ELEMENT_PARAMS, String, NULL); - - pn = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0"); - tgt_node_add_attr(n, pn); - - pn = tgt_node_alloc(XML_ELEMENT_GUID, String, "0"); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_PID, String, pid); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_VID, String, vid); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_DTYPE, String, type); - tgt_node_add(n, pn); - - if (strcmp(type, TGT_TYPE_DISK) == 0) { - - (void) snprintf(path, sizeof (path), "%s/%s/lun.%d", - target_basedir, targ_name, lun); - if (setup_disk_backing(code, path, backing, n, &size) == False) - goto error; - - create_geom(size, &cylinders, &heads, &spt); - - pn = tgt_node_alloc(XML_ELEMENT_RPM, Int, &rpm); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_HEADS, Int, &heads); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_CYLINDERS, Int, &cylinders); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_SPT, Int, &spt); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_BPS, Int, &bytes_sect); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_INTERLEAVE, Int, &interleave); - tgt_node_add(n, pn); - pn = tgt_node_alloc(XML_ELEMENT_STATUS, String, - TGT_STATUS_OFFLINE); - tgt_node_add(n, pn); - - } else if (strcmp(type, TGT_TYPE_TAPE) == 0) { -#ifndef _LP64 - *code = ERR_TAPE_NOT_SUPPORTED_IN_32BIT; - goto error; -#else - pn = tgt_node_alloc(XML_ELEMENT_STATUS, String, - TGT_STATUS_OFFLINE); - tgt_node_add(n, pn); - - (void) snprintf(path, sizeof (path), "%s/%s/lun.%d", - target_basedir, targ_name, lun); - if (setup_disk_backing(code, path, backing, n, &size) == False) - goto error; -#endif - - } else if (strcmp(type, TGT_TYPE_RAW) == 0) { - - pn = tgt_node_alloc(XML_ELEMENT_STATUS, String, - TGT_STATUS_ONLINE); - tgt_node_add(n, pn); - - backing = getfullrawname(backing); - if (setup_raw_backing(code, path, backing, &size) == False) - goto error; - - pn = tgt_node_alloc(XML_ELEMENT_MMAP_LUN, String, "false"); - tgt_node_add(n, pn); - - (void) snprintf(path, sizeof (path), "%s/%s/lun.%d", - target_basedir, targ_name, lun); - if (symlink(backing, path)) { - *code = ERR_CREATE_SYMLINK_FAILED; - goto error; - } - - iscsi_inventory_change(targ_name); - - } else if (strcmp(type, TGT_TYPE_OSD) == 0) { - - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", - target_basedir, targ_name, OSDBASE, lun); - if (mkdir(path, 0700) != 0) - goto error; - } - - - /* - * Wait to set the size until here because it may be unknown until - * the possible backing store has been setup. - */ - ssize = size / 512LL; - pn = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &ssize); - tgt_node_add(n, pn); - - if (backing != NULL) { - pn = tgt_node_alloc(XML_ELEMENT_BACK, String, backing); - tgt_node_add(n, pn); - } - - (void) mgmt_param_save2scf(n, local_name, lun); - - if ((strcmp(type, TGT_TYPE_DISK) == 0) || - (strcmp(type, TGT_TYPE_TAPE) == 0)) { - if (create_lun_common(targ_name, local_name, lun, size, - code) == False) - goto error; - } - - tgt_node_free(n); - - *code = ERR_SUCCESS; - return (True); - -error: - /* Free node n */ - tgt_node_free(n); - - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, - targ_name, PARAMBASE, lun); - (void) unlink(path); - if (fd == -1) - (void) close(fd); - return (False); -} - -/* - * []---- - * | create_lun_common -- create LU and start provisioning if needed - * | - * | This function is common to both the tape and disk emulation - * | code. - * []---- - */ -static Boolean_t -create_lun_common(char *targ_name, char *local_name, int lun, uint64_t size, - err_code_t *code) -{ - struct stat s; - int fd = -1; - char path[MAXPATHLEN]; - char buf[512]; - struct statvfs fs; - tgt_node_t *node = NULL; - tgt_node_t *c; - - /* - * Touch the last block of the file which will cause file systems - * to understand the intent of the file to be a certain size. The - * space isn't allocated, but the daemon can then mmap in this file - * and start writing to it. - */ - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", - target_basedir, targ_name, LUNBASE, lun); - if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) - goto error; - - (void) lseek(fd, size - 512LL, 0); - bzero(buf, sizeof (buf)); - if (write(fd, buf, sizeof (buf)) != sizeof (buf)) { - (void) unlink(path); - if (errno == EFBIG) - *code = ERR_FILE_TOO_BIG; - else - *code = ERR_FAILED_TO_CREATE_LU; - goto error; - } - (void) close(fd); - - /* - * Set the fd back to -1 so that if an error occurs we don't - * attempt to close this device twice. This could be an issue - * if another thread opened a file right after we closed this - * one and the system reused the file descriptor. During an - * error we would then close another threads file which would - * be ugly, not to mention difficult to track down. - */ - fd = -1; - - if (stat(path, &s) != 0) { - *code = ERR_FAILED_TO_CREATE_LU; - goto error; - } - - /* - * If the backing store is a regular file and the default is - * used which initializes the file instead of sparse allocation - * go ahead a set things up. - */ - if ((thin_provisioning == False) && ((s.st_mode & S_IFMT) == S_IFREG)) { - thick_provo_t *tp; - pthread_t junk; - - /* - * Attempt to see if there is enough space currently - * for the LU. The initialization might still fail - * with "out of space" because someone else is - * consuming space while the initialization is occuring. - * Nothing we can do about that. - */ - if (statvfs(path, &fs) != 0) { - queue_prt(mgmtq, Q_GEN_ERRS, - "GEN statvfs failed for %s", path); - *code = ERR_FAILED_TO_CREATE_LU; - goto error; - } else if ((fs.f_frsize * fs.f_bfree) < size) { - queue_prt(mgmtq, Q_STE_ERRS, - "GEN Not enough space for LU"); - *code = ERR_FILE_TOO_BIG; - goto error; - } - - /* - * Run the initialization thread in the background so that - * the administrator doesn't have to wait which for UFS could - * be a long time on a large LU. - */ - if ((tp = calloc(1, sizeof (*tp))) != NULL) { - tp->targ_name = strdup(targ_name); - tp->lun = lun; - tp->q = queue_alloc(); - (void) pthread_create(&junk, NULL, - thick_provo_start, tp); - - /* - * As soon as the thread starts it will send a simple - * ACK to it's own queue that we can look for. When - * we see this message we know that the thread has - * started and it's been added to the provisioning - * list. If this were not done it's possible for someone - * to create and delete a target within a script and - * have the delete run and fail to find the provision - * thread in the list. - */ - queue_message_free(queue_message_get(tp->q)); - } - } else { - (void) mgmt_get_param(&node, local_name, lun); - - c = tgt_node_alloc(XML_ELEMENT_STATUS, String, - TGT_STATUS_ONLINE); - tgt_node_replace(node, c, MatchName); - tgt_node_free(c); - - if (mgmt_param_save2scf(node, local_name, lun) == False) { - queue_prt(mgmtq, Q_STE_ERRS, - "GEN%d failed to dump out params", lun); - goto error; - } - iscsi_inventory_change(targ_name); - tgt_node_free(node); - } - - return (True); - -error: - if (fd != -1) - (void) close(fd); - if (node) - tgt_node_free(node); - return (False); -} - -static Boolean_t -readvtoc(int fd, struct extvtoc *v, int *slice) -{ - if ((*slice = read_extvtoc(fd, v)) >= 0) - return (True); - else - return (False); -} - -static Boolean_t -readefi(int fd, struct dk_gpt **efi, int *slice) -{ - if ((*slice = efi_alloc_and_read(fd, efi)) >= 0) - return (True); - else - return (False); -} - -/* - * []---- - * | setup_alt_backing -- use backing store link for regular file lun - * | - * | If the size is zero, then the administrator MUST have - * | specified a backing store to use. - * | If the size is non-zero and the backing store doesn't exist it will - * | be created. Also a tag will be added indicating that during removal - * | the backing store should be deleted as well. - * []---- - */ -static Boolean_t -setup_disk_backing(err_code_t *code, char *path, char *backing, tgt_node_t *n, - uint64_t *size) -{ - struct stat s; - char *raw_name, buf[512]; - struct extvtoc extvtoc; - struct dk_gpt *efi; - int slice, fd; - tgt_node_t *pn; - - /* - * Error checking regarding size and backing store has already - * been done. If the backing store is null at this point everything - * is okay so just return True. - */ - if (backing == NULL) - return (True); - - if (stat(backing, &s) == -1) { - if (*size == 0) { - *code = ERR_STAT_BACKING_FAILED; - return (False); - } else { - pn = tgt_node_alloc(XML_ELEMENT_DELETE_BACK, String, - "true"); - tgt_node_add(n, pn); - if ((fd = open(backing, O_RDWR|O_CREAT|O_LARGEFILE, - 0600)) < 0) { - *code = ERR_FAILED_TO_CREATE_LU; - return (False); - } - (void) lseek(fd, *size - 512LL, 0); - bzero(buf, sizeof (buf)); - (void) write(fd, buf, sizeof (buf)); - (void) close(fd); - } - } else if (*size != 0) { - *code = ERR_DISK_BACKING_SIZE_OR_FILE; - return (False); - } else if (((s.st_mode & S_IFMT) == S_IFCHR) || - ((s.st_mode & S_IFMT) == S_IFBLK)) { - raw_name = getfullrawname(backing); - if ((raw_name == NULL) || - ((fd = open(raw_name, O_NONBLOCK|O_RDONLY)) < 0)) { - *code = ERR_DISK_BACKING_NOT_VALID_RAW; - (void) close(fd); - if (raw_name) - free(raw_name); - return (False); - } - free(raw_name); - if (readvtoc(fd, &extvtoc, &slice) == True) { - *size = extvtoc.v_part[slice].p_size * 512; - - } else if (readefi(fd, &efi, &slice) == True) { - *size = efi->efi_parts[slice].p_size * 512; - efi_free(efi); - } else { - *code = ERR_DISK_BACKING_NOT_VALID_RAW; - (void) close(fd); - return (False); - } - (void) close(fd); - - } else if ((s.st_mode & S_IFMT) == S_IFREG) { - *size = s.st_size; - } else { - *code = ERR_DISK_BACKING_MUST_BE_REGULAR_FILE; - return (False); - } - - if (symlink(backing, path)) { - *code = ERR_CREATE_SYMLINK_FAILED; - return (False); - } - - return (True); -} - -/* - * []---- - * | validate_raw_backing -- check that device is full partition - * | - * | The size of the device will be returned in rtn_size in bytes. - * | - * | Need to guarantee that the backing store for a raw device is: - * | (a) character device - * | (b) Not buffered - * | Don't want this host to have data which is not flushed - * | out during a write since a multiple path access to - * | the backing store would be possible meaning we'd have - * | cache issue. - * | (c) read/write will access entire device. - * | To speed things up we use asynchronous I/O which means - * | the path has to have access to the entire device through - * | the partition table. If not, some client will issue a - * | READ_CAPACITY command, but not be able to access all of - * | the data. - * []---- - */ -static Boolean_t -setup_raw_backing(err_code_t *code, char *path, char *backing, - uint64_t *rtn_size) -{ - struct stat s; - char buf[512]; - int fd; - uint64_t size; - struct uscsi_cmd u; - struct scsi_extended_sense sense; - union scsi_cdb cdb; - struct scsi_capacity cap; - struct scsi_capacity_16 cap16; - int cap_len = sizeof (cap16); - size_t cc; - Boolean_t rval = False; - - if (stat(backing, &s) == -1) { - *code = ERR_ACCESS_RAW_DEVICE_FAILED; - return (False); - } else if (((s.st_mode & S_IFMT) != S_IFCHR) && - ((s.st_mode & S_IFMT) != S_IFBLK)) { - *code = ERR_DISK_BACKING_NOT_VALID_RAW; - return (False); - } - - if ((backing == NULL) || - ((fd = open(backing, O_NDELAY|O_RDONLY|O_LARGEFILE)) < 0)) { - *code = ERR_DISK_BACKING_NOT_VALID_RAW; - (void) close(fd); - return (False); - } - - bzero(&u, sizeof (u)); - bzero(&cdb, sizeof (cdb)); - bzero(&cap, sizeof (cap)); - bzero(&sense, sizeof (sense)); - - cdb.scc_cmd = 0x25; /* ---- READ_CAPACITY(10) ---- */ - - u.uscsi_cdb = (caddr_t)&cdb; - u.uscsi_cdblen = CDB_GROUP1; - u.uscsi_bufaddr = (caddr_t)∩ - u.uscsi_buflen = sizeof (cap); - u.uscsi_flags = USCSI_READ | USCSI_RQENABLE; - u.uscsi_rqbuf = (char *)&sense; - u.uscsi_rqlen = sizeof (sense); - - if ((ioctl(fd, USCSICMD, &u) != 0) || (u.uscsi_status != 0)) { - queue_prt(mgmtq, Q_GEN_DETAILS, "GEN0 uscsi(READ_CAP) failed"); - *code = ERR_DISK_BACKING_NOT_VALID_RAW; - rval = False; - goto error; - } - - if (cap.capacity == 0xffffffff) { - - bzero(&u, sizeof (u)); - bzero(&cdb, sizeof (cdb)); - bzero(&sense, sizeof (sense)); - /* - * The device is to large for the 10byte CDB. - * Using the larger 16byte read capacity command - */ - cdb.scc_cmd = 0x9E; - cdb.g4_reladdr = 0x10; - cdb.g4_count3 = hibyte(hiword(cap_len)); - cdb.g4_count2 = lobyte(hiword(cap_len)); - cdb.g4_count1 = hibyte(loword(cap_len)); - cdb.g4_count0 = lobyte(loword(cap_len)); - - u.uscsi_cdb = (caddr_t)&cdb; - u.uscsi_cdblen = CDB_GROUP4; - u.uscsi_bufaddr = (caddr_t)&cap16; - u.uscsi_buflen = sizeof (cap16); - u.uscsi_flags = USCSI_READ | USCSI_RQENABLE; - u.uscsi_rqbuf = (char *)&sense; - u.uscsi_rqlen = sizeof (sense); - - if ((ioctl(fd, USCSICMD, &u) != 0) || (u.uscsi_status != 0)) { - queue_prt(mgmtq, Q_GEN_DETAILS, - "GEN0 uscsi(READ_CAP16) failed"); - *code = ERR_DISK_BACKING_NOT_VALID_RAW; - rval = False; - goto error; - } - - size = ntohll(cap16.sc_capacity) - 1; - } else - size = (uint64_t)ntohl(cap.capacity) - 1; - - if ((cc = pread(fd, buf, sizeof (buf), size * 512LL)) != sizeof (buf)) { - queue_prt(mgmtq, Q_GEN_DETAILS, - "GEN0 Partition size != capacity(0x%llx), cc=%d, errno=%d", - size, cc, errno); - *code = ERR_RAW_PART_NOT_CAP; - rval = False; - goto error; - } else { - *rtn_size = size * 512LL; - rval = True; - } - -error: - (void) close(fd); - return (rval); -} - -/* - * get_zfs_shareiscsi -- given a dataset, get the ZFS properties - * - * This function is called when "set shareiscsi=on" calles into libiscsitgt, - * such that the iSCSI Target can get the ZFS_PROP_ISCSIOPTIONS. This is in - * lieu of properties being stored in SCF. - */ -int -get_zfs_shareiscsi(char *dataset, tgt_node_t **n, uint64_t *size, ucred_t *cred) -{ - libzfs_handle_t *zh; - zfs_handle_t *zfsh; - const priv_set_t *eset; - tgt_node_t *c; - char *prop = NULL; - char *cp; /* current pair */ - char *np; /* next pair */ - char *vp; /* value pointer */ - int status = ERR_SUCCESS; - - if (((zh = libzfs_init()) == NULL) || - ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { - status = ERR_INTERNAL_ERROR; - goto error; - } - - if (((eset = ucred_getprivset(cred, PRIV_EFFECTIVE)) != NULL) - ? !priv_ismember(eset, PRIV_SYS_CONFIG) - : ucred_geteuid(cred) != 0) { - /* - * See if user has ZFS dataset permissions to do operation - */ - if (zfs_iscsi_perm_check(zh, dataset, cred) != 0) { - status = ERR_NO_PERMISSION; - goto error; - } - } - - /* - * Get the current size of the volume, return to caller - */ - *size = zfs_prop_get_int(zfsh, ZFS_PROP_VOLSIZE); - - /* - * Allocate a local buffer to read the ZFS properties into - */ - if ((prop = malloc(ZFS_PROP_SIZE)) == NULL) { - status = ERR_INTERNAL_ERROR; - goto error; - } - - /* - * Get the shareiscsi property - */ - *prop = '\0'; - if (zfs_prop_get(zfsh, ZFS_PROP_SHAREISCSI, prop, ZFS_PROP_SIZE, NULL, - NULL, 0, B_TRUE)) { - status = ERR_INTERNAL_ERROR; - goto error; - } - - /* - * The options property is a string with name/value pairs separated - * by comma characters. Stand alone values of 'on' and 'off' are - * also permitted, but having the property set to off when share() - * is called is an error. - * Currently we only look for 'type=<value>' and ignore others. - */ - - for (cp = prop; cp; cp = np) { - if (np = strchr(cp, ',')) - *np++ = '\0'; - if (strcmp(cp, "on") == 0) { - cp = np; - continue; - } - if (strcmp(cp, "off") == 0) { - status = ERR_ZFS_ISCSISHARE_OFF; - goto error; - } - if (vp = strchr(cp, '=')) - *vp++ = '\0'; - /* - * Only support 'disk' emulation at this point. - */ - if ((strcmp(cp, "type") == 0) && (strcmp(vp, "disk") != 0)) { - status = ERR_INTERNAL_ERROR; - goto error; - } - } - - /* - * Now get the ZFS persisted shareiscsi options - */ - *prop = '\0'; - if (zfs_prop_get(zfsh, ZFS_PROP_ISCSIOPTIONS, prop, ZFS_PROP_SIZE, NULL, - NULL, 0, B_TRUE) && (status != ERR_ZFS_ISCSISHARE_OFF)) { - status = ERR_INTERNAL_ERROR; - goto error; - } - - /* - * Now move the ZFS persisted shareiscsi options into XML, then into - * iSCSI Target properties - */ - if (strlen(prop)) { - xmlTextReaderPtr xml_ptr = (xmlTextReaderPtr)xmlReaderForMemory( - prop, strlen(prop), NULL, NULL, 0); - - if (xml_ptr != NULL) { - *n = NULL; - while (xmlTextReaderRead(xml_ptr)) { - if (tgt_node_process(xml_ptr, n) == False) { - break; - } - } - - /* Cleanup XML data */ - (void) xmlTextReaderClose(xml_ptr); - xmlFreeTextReader(xml_ptr); - xmlCleanupParser(); - - /* Assure these XML elements are tagged as in-core */ - if (tgt_find_attr_str(*n, XML_ELEMENT_INCORE, &cp) - == False) { - c = tgt_node_alloc(XML_ELEMENT_INCORE, String, - XML_VALUE_TRUE); - tgt_node_add_attr(*n, c); - } else { - free(cp); - } - - } else { - status = ERR_NULL_XML_MESSAGE; - } - } else { - status = ERR_NULL_XML_MESSAGE; - } - -error: - if (prop) - free(prop); - if (zh) { - if (zfsh) - zfs_close(zfsh); - libzfs_fini(zh); - } - return (status); -} - -/* - * put_zfs_shareiscsi -- given a dataset, put the ZFS properties - * - * This function is called whenever persistence is needed to the set of - * iSCSI Target properties stored in ZFS_PROP_ISCSIOPTIONS. This is in lieu - * of properties being stored in SCF. - */ -int -put_zfs_shareiscsi(char *dataset, tgt_node_t *n) -{ - libzfs_handle_t *zh; - zfs_handle_t *zfsh; - char *prop = NULL; - int status; - - if (((zh = libzfs_init()) == NULL) || - ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { - status = ERR_INTERNAL_ERROR; - goto error; - } - - /* - * Now store this information on the ZVOL property so that - * next time we get a shareiscsi request the same data will be - * used. - */ - tgt_dump2buf(n, &prop); - if (zfs_prop_set(zfsh, zfs_prop_to_name(ZFS_PROP_ISCSIOPTIONS), prop)) { - status = ERR_INTERNAL_ERROR; - } else { - status = ERR_SUCCESS; - } - -error: - if (prop) - free(prop); - if (zh) { - if (zfsh) - zfs_close(zfsh); - libzfs_fini(zh); - } - return (status); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt_list.c b/usr/src/cmd/iscsi/iscsitgtd/mgmt_list.c deleted file mode 100644 index c3f621ac7d..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_list.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/stat.h> -#include <time.h> -#include <sys/utsname.h> -#include <unistd.h> -#include <sys/param.h> -#include <fcntl.h> -#include <errno.h> -#include <strings.h> -#include <dirent.h> -#include <priv.h> -#include <syslog.h> - -#include <iscsitgt_impl.h> -#include "utility.h" -#include "queue.h" -#include "target.h" -#include "iscsi_cmd.h" -#include "iscsi_conn.h" -#include "port.h" -#include "errcode.h" -#include "mgmt_scf.h" -#include "isns_client.h" - -static char *list_targets(tgt_node_t *x); -static char *list_initiator(tgt_node_t *x); -static char *list_tpgt(tgt_node_t *x); -static char *list_admin(tgt_node_t *x); -static void target_info(char **msg, char *targ_name, tgt_node_t *tnode); -static void target_stat(char **msg, char *iname, mgmt_type_t type); - -/*ARGSUSED*/ -void -list_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, - ucred_t *cred) -{ - tgt_node_t *x; - char msgbuf[80]; - char *reply_msg = NULL; - - if (p->x_child == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else { - x = p->x_child; - - if (x->x_name == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { - reply_msg = list_targets(x); - } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { - reply_msg = list_initiator(x); - } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { - reply_msg = list_tpgt(x); - } else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) { - reply_msg = list_admin(x); - } else { - (void) snprintf(msgbuf, sizeof (msgbuf), - "Unknown object '%s' for list element", - x->x_name); - xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); - } - } - queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); -} - -/*ARGSUSED*/ -static char * -list_targets(tgt_node_t *x) -{ - char *msg = NULL; - char *prop = NULL; - char *iname = NULL; - tgt_node_t *targ = NULL; - Boolean_t luninfo = False; - Boolean_t dostat = False; - - /* - * It's okay to not supply a "name" element. That just means the - * administrator wants a complete list of targets. However if a - * "name" is supplied then there must be a value for that element. - */ - if ((tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) && - (prop == NULL)) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - return (msg); - } - - /* ---- optional arguments ---- */ - (void) tgt_find_value_boolean(x, XML_ELEMENT_LUNINFO, &luninfo); - (void) tgt_find_value_boolean(x, XML_ELEMENT_IOSTAT, &dostat); - - tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'"); - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - if (targ->x_value == NULL) { - tgt_buf_add(&msg, XML_ELEMENT_TARG, - "bogus entry"); - continue; - } - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &iname) == - False) { - tgt_buf_add(&msg, XML_ELEMENT_TARG, - "missing iscsi-name"); - continue; - } - if (prop != NULL) { - if (strcmp(prop, targ->x_value) == 0) { - tgt_buf_add_tag(&msg, XML_ELEMENT_TARG, - Tag_Start); - tgt_buf_add_tag(&msg, targ->x_value, - Tag_String); - tgt_buf_add(&msg, XML_ELEMENT_INAME, iname); - if (luninfo == True) - target_info(&msg, iname, targ); - if (dostat == True) - target_stat(&msg, iname, - mgmt_full_phase_statistics); - tgt_buf_add_tag(&msg, XML_ELEMENT_TARG, - Tag_End); - } - } else { - tgt_buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_Start); - tgt_buf_add_tag(&msg, targ->x_value, Tag_String); - tgt_buf_add(&msg, XML_ELEMENT_INAME, iname); - if (dostat == True) - target_stat(&msg, iname, - mgmt_full_phase_statistics); - if (luninfo == True) - target_info(&msg, iname, targ); - tgt_buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_End); - } - free(iname); - } - tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End); - free(prop); - - return (msg); -} - -/*ARGSUSED*/ -static char * -list_initiator(tgt_node_t *x) -{ - char *msg = NULL; - char *attr = NULL; - char *prop = NULL; - Boolean_t verbose = False; - tgt_node_t *init = NULL; - - /* ---- Optional arguments ---- */ - if ((tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) && - (prop == NULL)) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - return (msg); - } - (void) tgt_find_value_boolean(x, XML_ELEMENT_VERBOSE, &verbose); - - tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'"); - while ((init = tgt_node_next_child(main_config, XML_ELEMENT_INIT, init)) - != NULL) { - if ((prop == NULL) || - ((prop != NULL) && (strcmp(prop, init->x_value) == 0))) { - - tgt_buf_add_tag(&msg, XML_ELEMENT_INIT, Tag_Start); - tgt_buf_add_tag(&msg, init->x_value, Tag_String); - - if (tgt_find_value_str(init, XML_ELEMENT_INAME, - &attr) == True) { - tgt_buf_add(&msg, XML_ELEMENT_INAME, attr); - free(attr); - } - - if (tgt_find_value_str(init, XML_ELEMENT_CHAPSECRET, - &attr) == True) { - tgt_buf_add(&msg, XML_ELEMENT_CHAPSECRET, - "Set"); - free(attr); - } - - if (tgt_find_value_str(init, XML_ELEMENT_CHAPNAME, - &attr) == True) { - tgt_buf_add(&msg, XML_ELEMENT_CHAPNAME, attr); - free(attr); - } - - tgt_buf_add_tag(&msg, XML_ELEMENT_INIT, Tag_End); - } - } - - if (prop != NULL) - free(prop); - - tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End); - - return (msg); -} - -/*ARGSUSED*/ -static char * -list_tpgt(tgt_node_t *x) -{ - char *msg = NULL; - char *prop = NULL; - Boolean_t verbose = False; - tgt_node_t *tpgt = NULL; - tgt_node_t *ip = NULL; - - /* ---- Optional arguments ---- */ - if ((tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) && - (prop == NULL)) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - return (msg); - } - (void) tgt_find_value_boolean(x, XML_ELEMENT_VERBOSE, &verbose); - - tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'"); - while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt)) - != NULL) { - if ((prop == NULL) || - ((prop != NULL) && (strcmp(prop, tpgt->x_value) == 0))) { - - tgt_buf_add_tag(&msg, XML_ELEMENT_TPGT, Tag_Start); - tgt_buf_add_tag(&msg, tpgt->x_value, Tag_String); - - while ((ip = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, - ip)) != NULL) { - tgt_buf_add(&msg, ip->x_name, ip->x_value); - } - - tgt_buf_add_tag(&msg, XML_ELEMENT_TPGT, Tag_End); - } - } - tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End); - - if (prop != NULL) - free(prop); - return (msg); -} - -/*ARGSUSED*/ -static char * -list_admin(tgt_node_t *x) -{ - char *msg = NULL; - admin_table_t *p; - tgt_node_t *node = NULL; - tgt_node_t *isns_srv_node = NULL; - Boolean_t enabled = False; - - tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'"); - tgt_buf_add_tag(&msg, XML_ELEMENT_ADMIN, Tag_Start); - - node = NULL; - for (p = admin_prop_list; p->name != NULL; p++) { - node = tgt_node_next_child(main_config, p->name, NULL); - if (node) { - if (strcmp(p->name, XML_ELEMENT_CHAPSECRET) == 0) { - tgt_buf_add(&msg, p->name, "Set"); - } else if (strcmp(p->name, XML_ELEMENT_ISNS_ACCESS) - == 0) { - tgt_buf_add(&msg, p->name, node->x_value); - /* check the isns discovery */ - if (node->x_value && - strcmp(node->x_value, "true") == 0) { - enabled = True; - } - } else if (strcmp(p->name, XML_ELEMENT_ISNS_SERV) - == 0) { - tgt_buf_add(&msg, p->name, node->x_value); - /* - * check the state of isns server connection. - */ - if (node->x_value != NULL) { - isns_srv_node = node; - } - } else { - tgt_buf_add(&msg, p->name, node->x_value); - } - } - } - - /* - * check the state of isns server connection and add the node. - * the conncection state is dynamic so it doesn't get stored in - * incore config. - */ - if (enabled && isns_srv_node) { - if (isns_open(isns_srv_node->x_value) == -1) { - tgt_buf_add(&msg, XML_ELEMENT_ISNS_SERVER_STATUS, - "Unavailable"); - } else { - tgt_buf_add(&msg, XML_ELEMENT_ISNS_SERVER_STATUS, - "Available"); - } - } else { - tgt_buf_add(&msg, XML_ELEMENT_ISNS_SERVER_STATUS, - "Not applicable"); - } - - tgt_buf_add_tag(&msg, XML_ELEMENT_ADMIN, Tag_End); - tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End); - - return (msg); -} - -static void -target_stat(char **msg, char *targ_name, mgmt_type_t type) -{ - iscsi_conn_t *c; - msg_t *m; - target_queue_t *q = queue_alloc(); - mgmt_request_t mgmt_rqst; - int msg_sent; - int i; - extern pthread_mutex_t port_mutex; - - mgmt_rqst.m_q = q; - mgmt_rqst.m_u.m_resp = msg; - mgmt_rqst.m_time = time(NULL); - mgmt_rqst.m_request = type; - (void) pthread_mutex_init(&mgmt_rqst.m_resp_mutex, NULL); - - (void) pthread_mutex_lock(&port_mutex); - mgmt_rqst.m_targ_name = targ_name; - msg_sent = 0; - for (c = conn_head; c; c = c->c_next) { - if (c->c_state == S5_LOGGED_IN) { - /* - * Only send requests for statistics to - * connections that are up. Could even - * go further and only look at connections - * which are S5_LOGGED_IN, but there may - * be statistics, such as connection time, - * which we'd like to have. - */ - queue_message_set(c->c_dataq, 0, msg_mgmt_rqst, - &mgmt_rqst); - msg_sent++; - } - } - (void) pthread_mutex_unlock(&port_mutex); - - /* - * Comment: main.c:list_targets:1 - * We wait for the responses without the port_mutex - * being held. There is a small window between when the - * connection last listens for a message and when the - * queue is freed. During that time the connection will - * attempt to grab the port_mutex lock so that it - * can unlink itself and call queueu_free(). If we sent - * the message with the lock held and then wait for a response - * it's possible that the connection will deadlock waiting - * to get the port_mutex. - */ - for (i = 0; i < msg_sent; i++) { - m = queue_message_get(q); - queue_message_free(m); - } - queue_free(q, NULL); -} - -static void -target_info(char **msg, char *targ_name, tgt_node_t *tnode) -{ - char lun_buf[16]; - char *prop; - char *local_name = NULL; - tgt_node_t *lnode; /* list node */ - tgt_node_t *lnp; /* list node pointer */ - tgt_node_t *lun; - tgt_node_t *params; - int lun_num; - Boolean_t incore; - struct stat s; - - if ((lnode = tgt_node_next(tnode, XML_ELEMENT_ACLLIST, NULL)) != - NULL) { - lnp = NULL; - tgt_buf_add_tag(msg, XML_ELEMENT_ACLLIST, Tag_Start); - while ((lnp = tgt_node_next(lnode, XML_ELEMENT_INIT, lnp)) != - NULL) - tgt_buf_add(msg, XML_ELEMENT_INIT, lnp->x_value); - tgt_buf_add_tag(msg, XML_ELEMENT_ACLLIST, Tag_End); - } - - if ((lnode = tgt_node_next(tnode, XML_ELEMENT_TPGTLIST, NULL)) != - NULL) { - lnp = NULL; - tgt_buf_add_tag(msg, XML_ELEMENT_TPGTLIST, Tag_Start); - while ((lnp = tgt_node_next(lnode, XML_ELEMENT_TPGT, lnp)) != - NULL) - tgt_buf_add(msg, XML_ELEMENT_TPGT, lnp->x_value); - tgt_buf_add_tag(msg, XML_ELEMENT_TPGTLIST, Tag_End); - } - - if ((lnode = tgt_node_next(tnode, XML_ELEMENT_ALIAS, NULL)) != NULL) - tgt_buf_add(msg, XML_ELEMENT_ALIAS, lnode->x_value); - - if ((lnode = tgt_node_next(tnode, XML_ELEMENT_MAXRECV, NULL)) != NULL) - tgt_buf_add(msg, XML_ELEMENT_MAXRECV, lnode->x_value); - - if ((lnode = tgt_node_next(tnode, XML_ELEMENT_LUNLIST, NULL)) == NULL) - return; - - if (tgt_find_attr_str(tnode, XML_ELEMENT_INCORE, &prop) == True) { - if (strcmp(prop, "true") == 0) - incore = True; - else - incore = False; - free(prop); - } else - incore = False; - - tgt_buf_add_tag(msg, XML_ELEMENT_LUNINFO, Tag_Start); - lun = NULL; - while ((lun = tgt_node_next(lnode, XML_ELEMENT_LUN, lun)) != NULL) { - if ((tgt_find_value_int(lun, XML_ELEMENT_LUN, &lun_num)) == - False) - continue; - if (incore == False) { - local_name = get_local_name(targ_name); - if (local_name != NULL) { - (void) mgmt_get_param(¶ms, local_name, - lun_num); - free(local_name); - } else { - continue; - } - } else { - params = lun; - } - - tgt_buf_add_tag(msg, XML_ELEMENT_LUN, Tag_Start); - (void) snprintf(lun_buf, sizeof (lun_buf), "%d", lun_num); - tgt_buf_add_tag(msg, lun_buf, Tag_String); - - if (tgt_find_value_str(params, XML_ELEMENT_GUID, &prop) == - True) { - tgt_buf_add(msg, XML_ELEMENT_GUID, prop); - free(prop); - } - if (tgt_find_value_str(params, XML_ELEMENT_VID, &prop) == - True) { - tgt_buf_add(msg, XML_ELEMENT_VID, prop); - free(prop); - } - if (tgt_find_value_str(params, XML_ELEMENT_PID, &prop) == - True) { - tgt_buf_add(msg, XML_ELEMENT_PID, prop); - free(prop); - } - if (tgt_find_value_str(params, XML_ELEMENT_DTYPE, &prop) == - True) { - tgt_buf_add(msg, XML_ELEMENT_DTYPE, prop); - free(prop); - } - if (tgt_find_value_str(params, XML_ELEMENT_SIZE, &prop) == - True) { - tgt_buf_add(msg, XML_ELEMENT_SIZE, prop); - free(prop); - } - if (tgt_find_value_str(params, XML_ELEMENT_BACK, &prop) == - True) { - tgt_buf_add(msg, XML_ELEMENT_BACK, prop); - if (stat(prop, &s) == 0) { - tgt_buf_add(msg, XML_ELEMENT_STATUS, - TGT_STATUS_ONLINE); - } else { - tgt_buf_add(msg, XML_ELEMENT_STATUS, - strerror(errno)); - } - free(prop); - } - tgt_buf_add_tag(msg, XML_ELEMENT_LUN, Tag_End); - - if (incore == False) - tgt_node_free(params); - } - tgt_buf_add_tag(msg, XML_ELEMENT_LUNINFO, Tag_End); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c b/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c deleted file mode 100644 index 4dfc6a1b61..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c +++ /dev/null @@ -1,1191 +0,0 @@ -/* - * 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. - */ - -#include <sys/types.h> -#include <time.h> -#include <sys/utsname.h> -#include <unistd.h> -#include <sys/param.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <errno.h> -#include <strings.h> -#include <assert.h> -#include <sys/socket.h> -#include <netdb.h> -#include <libgen.h> -#include <libzfs.h> -#include <syslog.h> - -#include <iscsitgt_impl.h> -#include "queue.h" -#include "utility.h" -#include "iscsi_cmd.h" -#include "target.h" -#include "errcode.h" -#include "isns_client.h" -#include "mgmt_scf.h" - -static char *modify_target(tgt_node_t *x, ucred_t *cred); -static char *modify_initiator(tgt_node_t *x); -static char *modify_admin(tgt_node_t *x); -static char *modify_tpgt(tgt_node_t *x); -static char *modify_zfs(tgt_node_t *x, ucred_t *cred); -static char *validate_zfs_iscsitgt(tgt_node_t *x); -static Boolean_t modify_element(char *, char *, tgt_node_t *, match_type_t); -static Boolean_t delete_element(char *, tgt_node_t *, match_type_t); - -/* - * []---- - * | modify_func -- dispatch routine for objects - * []---- - */ -/*ARGSUSED*/ -void -modify_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, - ucred_t *cred) -{ - tgt_node_t *x; - char *reply_msg = NULL; - - x = p->x_child; - - if (p->x_child == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { - reply_msg = modify_zfs(x, cred); - } else if (check_auth_modify(cred) != True) { - xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); - } else { - if (x->x_name == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { - reply_msg = modify_target(x, cred); - } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { - reply_msg = modify_initiator(x); - } else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) { - reply_msg = modify_admin(x); - } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { - reply_msg = modify_tpgt(x); - } else { - xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); - } - } - queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); -} - -/* - * []---- - * | modify_target -- updates one or more properties for a target - * []---- - */ -static char * -modify_target(tgt_node_t *x, ucred_t *cred) -{ - char *msg = NULL; - char *name = NULL; - char iscsi_path[MAXPATHLEN]; - char targ_name[64]; - char *iscsi = NULL; - char *prop = NULL; - char path[MAXPATHLEN]; - char *m; - char buf[512]; /* one sector size block */ - tgt_node_t *t = NULL; - tgt_node_t *list = NULL; - tgt_node_t *c = NULL; - tgt_node_t *node = NULL; - tgt_node_t *tpgt = NULL; - Boolean_t change_made = False; - int lun = 0; - int fd; - uint64_t val, new_lu_size, cur_lu_size; - struct stat st; - uint32_t isns_mods = 0; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - t)) != NULL) { - if (strcmp(t->x_value, name) == 0) { - break; - } - } - if (t == NULL) { - free(name); - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - if (tgt_find_attr_str(t, XML_ELEMENT_INCORE, &m) == True) { - if (strcmp(m, "true") == 0) { - free(m); - free(name); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (modify_zfs(x, cred)); - } - free(m); - } - - /* - * Under base dir, file 'target name' is a symbolic link - * to the real directory 'IQN name' which stores params and back - * storage. Therefore we can easily get IQN name from target - * name by read the symbolic link content. - */ - (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, name); - bzero(iscsi_path, sizeof (iscsi_path)); - (void) readlink(path, iscsi_path, sizeof (iscsi_path)); - iscsi = basename(iscsi_path); - - /* ---- Finished with these so go ahead and release the memory ---- */ - (void) strncpy(targ_name, name, sizeof (targ_name)); - free(name); - - /* - * Grow the LU. We currently do not support shrinking the LU and - * that is only because it's unknown if any applications could support - * that type of data loss. To support shrinking all that would be - * needed is to remove the new/old size check and perform a truncation. - * The actually truncation request should be shipped off to the T10 - * layer so that the LU thread can remap the smaller size without - * anyone accessing the data. - */ - if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); - goto error; - } - if (strtoll_multiplier(prop, &new_lu_size) == False) { - free(prop); - xml_rtn_msg(&msg, ERR_INVALID_SIZE); - goto error; - } - free(prop); - if ((new_lu_size % 512LL) != 0) { - xml_rtn_msg(&msg, ERR_SIZE_MOD_BLOCK); - goto error; - } - new_lu_size /= 512LL; - - /* ---- default to LUN 0 ---- */ - (void) tgt_find_value_int(x, XML_ELEMENT_LUN, &lun); - - /* ---- read in current parameters ---- */ - if (mgmt_get_param(&node, targ_name, lun) == False) { - xml_rtn_msg(&msg, ERR_OPEN_PARAM_FILE_FAILED); - goto error; - } - - /* ---- validate that we're indeed growing the LU ---- */ - if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &prop) == - False) { - xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); - goto error; - } - if (strtoll_multiplier(prop, &cur_lu_size) == False) { - free(prop); - xml_rtn_msg(&msg, ERR_INVALID_SIZE); - goto error; - } - free(prop); - - if (new_lu_size < cur_lu_size) { - xml_rtn_msg(&msg, ERR_CANT_SHRINK_LU); - goto error; - } - - /* ---- check that this LU is of type 'disk' or 'tape' ---- */ - if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &prop) == - False) { - xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); - goto error; - } - if ((strcmp(prop, TGT_TYPE_DISK) != 0) && - (strcmp(prop, TGT_TYPE_TAPE) != 0)) { - xml_rtn_msg(&msg, ERR_RESIZE_WRONG_DTYPE); - free(prop); - goto error; - } - free(prop); - - /* ---- validate the backing store is a regular file ---- */ - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", - target_basedir, iscsi, LUNBASE, lun); - if (stat(path, &st) == -1) { - xml_rtn_msg(&msg, ERR_STAT_BACKING_FAILED); - goto error; - } - if ((st.st_mode & S_IFMT) != S_IFREG) { - xml_rtn_msg(&msg, - ERR_DISK_BACKING_MUST_BE_REGULAR_FILE); - goto error; - } - - /* ---- update the parameter node with new size ---- */ - if ((c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &new_lu_size)) - == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_replace(node, c, MatchName); - tgt_node_free(c); - - /* ---- now update params file ---- */ - (void) mgmt_param_save2scf(node, targ_name, lun); - - /* ---- grow lu backing store ---- */ - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", - target_basedir, iscsi, LUNBASE, lun); - if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) { - xml_rtn_msg(&msg, ERR_LUN_NOT_FOUND); - goto error; - } - (void) lseek(fd, (new_lu_size * 512LL) - 512LL, 0); - bzero(buf, sizeof (buf)); - if (write(fd, buf, sizeof (buf)) != sizeof (buf)) { - xml_rtn_msg(&msg, ERR_LUN_NOT_GROWN); - (void) close(fd); - goto error; - } - (void) close(fd); - - /* ---- send updates to current initiators via ASC/ASCQ ---- */ - iscsi_capacity_change(iscsi, lun); - - prop = NULL; - tgt_node_free(node); - node = NULL; - change_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); - goto error; - } - - /* - * Validate that the Target Portal Group Tag is reasonable. - */ - val = strtoll(prop, &m, 0); - if ((val < TPGT_MIN) || (val > TPGT_MAX) || - ((m != NULL) && (*m != '\0'))) { - xml_rtn_msg(&msg, ERR_INVALID_TPGT); - free(prop); - goto error; - } - - /* update isns only if TPGT contains ip_addr */ - tpgt = NULL; - while ((tpgt = tgt_node_next_child(main_config, - XML_ELEMENT_TPGT, tpgt)) != NULL) { - if (strcmp(prop, tpgt->x_value) != 0) - continue; - if (tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL) - != NULL) { - isns_mods |= ISNS_MOD_TPGT; - break; - } else { - xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR); - free(prop); - goto error; - } - } - - if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == - NULL) { - free(prop); - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - - if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, - NULL)) != NULL) { - tgt_node_replace(list, c, MatchBoth); - /* - * tgt_node_replace will duplicate the child node - * tgt_node_add which is used below just links it - * into the tree. - */ - tgt_node_free(c); - } else { - list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); - if (list == NULL) { - free(prop); - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_add(list, c); - tgt_node_add(t, list); - } - - free(prop); - prop = NULL; - change_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); - goto error; - } - - c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); - if (c == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - free(prop); - goto error; - } - if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, - NULL)) != NULL) { - tgt_node_replace(list, c, MatchBoth); - /* ---- See above usage ---- */ - tgt_node_free(c); - } else { - list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); - if (list == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - free(prop); - goto error; - } - tgt_node_add(list, c); - tgt_node_add(t, list); - } - free(prop); - prop = NULL; - change_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_ALIAS, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ALIAS); - goto error; - } - - if (modify_element(XML_ELEMENT_ALIAS, prop, t, MatchName) == - False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - free(prop); - goto error; - } - free(prop); - prop = NULL; - isns_mods |= ISNS_MOD_ALIAS; - change_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_MAXRECV, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_MAXRECV); - goto error; - } - - if ((strtoll_multiplier(prop, &val) == False) || - (val < MAXRCVDATA_MIN) || (val > MAXRCVDATA_MAX)) { - free(prop); - xml_rtn_msg(&msg, ERR_INVALID_MAXRECV); - goto error; - } - free(prop); - if ((prop = malloc(32)) == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - (void) snprintf(prop, 32, "%d", val); - - if (modify_element(XML_ELEMENT_MAXRECV, prop, t, MatchName) == - False) { - free(prop); - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - free(prop); - prop = NULL; - change_made = True; - } - - if (change_made == True) { - if (mgmt_config_save2scf() == False) { - xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED); - goto error; - } - if (isns_enabled() == True) { - if (isns_dev_update(t->x_value, isns_mods) != 0) { - xml_rtn_msg(&msg, ERR_ISNS_ERROR); - goto error; - } - } - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - } - -error: - (void) pthread_rwlock_unlock(&targ_config_mutex); - if (node) - tgt_node_free(node); - return (msg); -} - -/* - * []---- - * | modify_initiator -- store the CHAP information for an initiator - * []---- - */ -static char * -modify_initiator(tgt_node_t *x) -{ - char *msg = NULL; - char *name = NULL; - char *prop = NULL; - tgt_node_t *inode = NULL; - Boolean_t changes_made = False; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, - inode)) != NULL) { - if (strcmp(inode->x_value, name) == 0) - break; - } - - /* - * We no longer need the name since we should have found the node - * it refers to and this way we don't have to worry about freeing - * the storage later. - */ - free(name); - - if (inode == NULL) { - xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); - goto error; - } - - if (tgt_find_value_str(x, XML_ELEMENT_CHAPSECRET, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPSECRET); - goto error; - } - - if (modify_element(XML_ELEMENT_CHAPSECRET, prop, inode, - MatchName) == False) { - free(prop); - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - free(prop); - changes_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPSECRET, - &prop) == True) { - if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) { - if (prop != NULL) - free(prop); - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - goto error; - } - free(prop); - - if (delete_element(XML_ELEMENT_CHAPSECRET, inode, - MatchName) == False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - changes_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_CHAPNAME, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPNAME); - goto error; - } - - if (modify_element(XML_ELEMENT_CHAPNAME, prop, inode, - MatchName) == False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - free(prop); - goto error; - } - free(prop); - changes_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPNAME, &prop) == True) { - if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) { - if (prop != NULL) - free(prop); - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - goto error; - } - free(prop); - - - if (delete_element(XML_ELEMENT_CHAPNAME, inode, - MatchName) == False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - changes_made = True; - } - - if (changes_made == True) { - if (mgmt_config_save2scf() == True) { - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - } - } else { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - } - -error: - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -/* - * []---- - * | modify_admin -- modify one or more of the admin related props - * []---- - */ -static char * -modify_admin(tgt_node_t *x) -{ - char *msg = NULL; - char *prop; - Boolean_t changes_made = False; - Boolean_t update_isns = False; - admin_table_t *ap; - - for (ap = admin_prop_list; ap->name; ap++) { - if (tgt_find_value_str(x, ap->name, &prop) == True) { - - if ((prop == NULL) || (strlen(prop) == 0)) - break; - - /* - * Do the function call first if it exists which - * will allow possible checking to be done first. - */ - if (ap->func) { - msg = (*ap->func)(ap->name, prop); - if (msg != NULL) { - free(prop); - return (msg); - } - } - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (ap->delete_name == NULL) { - if (modify_element(ap->name, prop, main_config, - MatchName) == False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - free(prop); - (void) pthread_rwlock_unlock( - &targ_config_mutex); - return (msg); - } - } else { - if (strcmp(prop, XML_VALUE_TRUE) != 0) { - xml_rtn_msg(&msg, - ERR_SYNTAX_MISSING_OPERAND); - free(prop); - (void) pthread_rwlock_unlock( - &targ_config_mutex); - return (msg); - } - if (delete_element(ap->delete_name, - main_config, MatchName) == False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - free(prop); - (void) pthread_rwlock_unlock( - &targ_config_mutex); - return (msg); - } - } - (void) pthread_rwlock_unlock(&targ_config_mutex); - if (0 == strcmp(ap->name, XML_ELEMENT_ISNS_ACCESS) || - 0 == strcmp(ap->name, XML_ELEMENT_ISNS_SERV)) { - update_isns = True; - } - free(prop); - changes_made = True; - } - } - - if (changes_made == True) { - /* isns_update updates isns_access & isns server name */ - if (update_isns == True) { - if (isns_update() != 0) { - xml_rtn_msg(&msg, ERR_ISNS_ERROR); - return (msg); - } - } - if (mgmt_config_save2scf() == True) { - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - } - } else { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - } - - return (msg); -} - -/* - * []---- - * | modify_tpgt -- add an IP-address to a target portal group - * []---- - */ -static char * -modify_tpgt(tgt_node_t *x) -{ - struct addrinfo *res = NULL; - char *msg = NULL; - char *name = NULL; - char *ip_str = NULL; - tgt_node_t *tnode = NULL; - tgt_node_t *list = NULL; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &ip_str) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_IPADDR); - goto error; - } - if ((getaddrinfo(ip_str, NULL, NULL, &res) != 0) || (res == NULL)) { - xml_rtn_msg(&msg, ERR_INVALID_IP); - goto error; - } - while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, - tnode)) != NULL) { - if (strcmp(tnode->x_value, name) == 0) - break; - } - if (tnode == NULL) { - xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); - goto error; - } - - if ((list = tgt_node_next(tnode, XML_ELEMENT_IPADDRLIST, NULL)) - == NULL) { - list = tgt_node_alloc(XML_ELEMENT_IPADDRLIST, String, ""); - if (list == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_add(tnode, list); - } - if (modify_element(XML_ELEMENT_IPADDR, ip_str, list, MatchBoth) == - False) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - - if (mgmt_config_save2scf() == True) { - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - /* tpgt change should be updated to smf */ - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - } - - /* - * Re-register all targets, currently there's no method to - * update TPGT for individual target - */ - if (isns_enabled() == True) { - (void) isns_reg_all(); - } - -error: - if (name) - free(name); - if (ip_str) - free(ip_str); - if (res) - freeaddrinfo(res); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -/* - * modify_zfs -- test for the existence of a certain dataset being shared - * - * Called when someone uses the iscsitgt_is_shared() function from libiscsitgt. - * All that - */ -static char * -modify_zfs(tgt_node_t *x, ucred_t *cred) -{ - char *msg = NULL; - char *dataset = NULL; - char *prop; - char *m; - tgt_node_t *n = NULL; - tgt_node_t *t = NULL; - tgt_node_t *list = NULL; - tgt_node_t *c1, *c2; - Boolean_t change_made = False; - uint64_t size; - int status; - int val; - char *tru = "true"; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - /* - * Validate request - */ - if (tgt_find_value_str(x, XML_ELEMENT_VALIDATE, &tru)) { - (void) pthread_rwlock_unlock(&targ_config_mutex); - if (tru) - free(tru); - free(dataset); - return (validate_zfs_iscsitgt(x)); - } - - /* - * Check for existance of ZFS shareiscsi properties - */ - status = get_zfs_shareiscsi(dataset, &n, &size, cred); - if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) - != NULL) { - if (strcmp(t->x_value, dataset) == 0) - break; - } - if (t == NULL) { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); - goto error; - } - - /* - * Validate that the Target Portal Group Tag is reasonable. - */ - val = strtoll(prop, &m, 0); - if ((val < TPGT_MIN) || (val > TPGT_MAX) || - ((m != NULL) && (*m != '\0'))) { - xml_rtn_msg(&msg, ERR_INVALID_TPGT); - goto error; - } - - if ((c1 = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == - NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - - /* - * Due to the fact that the targets_config differs from the - * ZVOL properties stored in zfs_shareiscsi, two lists need to - * be updated - */ - c2 = tgt_node_dup(c1); - if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) - != NULL) { - /* - * tgt_node_replace will duplicate the child node - * tgt_node_add which is used below just links it - * into the tree. - */ - tgt_node_replace(list, c1, MatchBoth); - tgt_node_free(c1); - } else { - list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); - if (list == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_add(list, c1); - tgt_node_add(t, list); - } - if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL)) - != NULL) { - /* - * tgt_node_replace will duplicate the child node - * tgt_node_add which is used below just links it - * into the tree. - */ - tgt_node_replace(list, c2, MatchBoth); - tgt_node_free(c2); - } else { - list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); - if (list == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_add(list, c2); - tgt_node_add(n, list); - } - change_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); - goto error; - } - - c1 = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); - if (c1 == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - - /* - * Due to the fact that the targets_config differs from the - * ZVOL properties stored in zfs_shareiscsi, two lists need to - * be updated - */ - c2 = tgt_node_dup(c1); - if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) - != NULL) { - /* - * tgt_node_replace will duplicate the child node - * tgt_node_add which is used below just links it - * into the tree. - */ - tgt_node_replace(list, c1, MatchBoth); - tgt_node_free(c1); - } else { - list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); - if (list == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_add(list, c1); - tgt_node_add(t, list); - } - if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL)) - != NULL) { - /* - * tgt_node_replace will duplicate the child node - * tgt_node_add which is used below just links it - * into the tree. - */ - tgt_node_replace(list, c2, MatchBoth); - tgt_node_free(c2); - } else { - list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); - if (list == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - goto error; - } - tgt_node_add(list, c2); - tgt_node_add(n, list); - } - - change_made = True; - } - - if (change_made == True) { - status = put_zfs_shareiscsi(dataset, n); - if (status != ERR_SUCCESS) { - xml_rtn_msg(&msg, status); - goto error; - } else { - xml_rtn_msg(&msg, ERR_SUCCESS); - } - } else { - xml_rtn_msg(&msg, ERR_SUCCESS); - } - -error: - if (n) - tgt_node_free(n); - if (dataset) - free(dataset); - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -/* - * Just checking the existance of the given target. Here we check whether - * both zfs and iscsitarget aware of the given target/volume. It neither - * care about the credentials nor SHAREISCSI properties. - */ -static char * -validate_zfs_iscsitgt(tgt_node_t *x) -{ - char *msg = NULL; - char *prop = NULL; - char *dataset = NULL; - libzfs_handle_t *zh = NULL; - zfs_handle_t *zfsh = NULL; - tgt_node_t *n = NULL; - - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - return (msg); - } - - if (((zh = libzfs_init()) == NULL) || - ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - while ((n = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, n)) != - NULL) { - if (strcmp(n->x_value, dataset) == 0) - break; - } - if (n == NULL) { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - xml_rtn_msg(&msg, ERR_SUCCESS); - -error: - if (zfsh) - zfs_close(zfsh); - if (prop) - free(prop); - if (zh) - libzfs_fini(zh); - if (dataset) - free(dataset); - - return (msg); - -} - - -/* - * []---- - * | modify_element -- helper function to create node and add it to parent - * | - * | A False return value indicates a failure to allocate enough memory. - * []---- - */ -static Boolean_t -modify_element(char *name, char *value, tgt_node_t *p, match_type_t m) -{ - tgt_node_t *c; - - - if ((c = tgt_node_alloc(name, String, value)) == NULL) { - return (False); - } else { - tgt_node_replace(p, c, m); - tgt_node_free(c); - return (True); - } -} - -/* - * []---- - * | delete_element -- helper function to remove a node from a parent - * | - * | A False return value indicates a failure to allocate enough memory. - * []---- - */ -static Boolean_t -delete_element(char *name, tgt_node_t *p, match_type_t m) -{ - tgt_node_t *c; - - if ((c = tgt_node_alloc(name, String, NULL)) == NULL) { - return (False); - } - (void) tgt_node_remove(p, c, m); - tgt_node_free(c); - return (True); -} - -/* - * []---- - * | update_basedir -- update the global target directory - * | - * | Most of the properties when updated require no futher processing. The - * | target base directory however must be updated if it hasn't been set. - * | On a new system the daemon will not have any location to place the - * | backing store and target configuration files. On a live system we would - * | screw things up if we changed the global variable if it was already - * | in use, so we only allow the updating to occur if there are no targets. - * []---- - */ -/*ARGSUSED*/ -char * -update_basedir(char *name, char *prop) -{ - tgt_node_t *targ = NULL; - char *msg = NULL; - char *v; - - if ((prop == NULL) || (strlen(prop) == 0) || (prop[0] != '/')) { - xml_rtn_msg(&msg, ERR_INVALID_BASEDIR); - return (msg); - } - - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - /* - * Traverse the list of configured targets, serching for any - * target that is using the current base-directory. Fail the - * update if found. - * - * The only targets that do not use the base-directory at this - * time are those targets persisted in ZFS. - */ - if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &v) == True) { - if (v != NULL) { - if (strcmp(v, XML_VALUE_TRUE) == 0) { - free(v); - continue; - } - free(v); - } - } - - /* - * Found at least one target, so fail - */ - xml_rtn_msg(&msg, ERR_VALID_TARG_EXIST); - return (msg); - } - - if (target_basedir) { - free(target_basedir); - } - target_basedir = strdup(prop); - if ((mkdir(target_basedir, 0700) != 0) && (errno != EEXIST)) { - xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED); - free(target_basedir); - target_basedir = NULL; - } - return (msg); -} - -/* - * []---- - * | validate_radius -- validate that server[:port] are valid - * []---- - */ -char * -valid_radius_srv(char *name, char *prop) -{ - struct addrinfo *res = NULL; - char *msg = NULL; - char *sp, *p; - int port; - - if ((sp = strdup(prop)) == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - return (msg); - } else if ((p = strrchr(sp, ':')) != NULL) { - *p++ = '\0'; - port = atoi(p); - if ((port < 1) || (port > 65535)) { - xml_rtn_msg(&msg, ERR_INVALID_RADSRV); - free(sp); - return (msg); - } - } - if ((getaddrinfo(sp, NULL, NULL, &res) != 0) || (res == NULL)) - xml_rtn_msg(&msg, ERR_INVALID_RADSRV); - else - freeaddrinfo(res); - free(sp); - return (msg); -} - -/* - * []---- - * | validate_isns_server -- validate that server[:port] are valid - * []---- - */ -char * -valid_isns_srv(char *name, char *prop) -{ - char *msg = NULL; - char *sp, *p; - int so; - int port; - - if (strlen(prop) > MAXHOSTNAMELEN) { - xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); - return (msg); - } - - if ((sp = strdup(prop)) == NULL) { - xml_rtn_msg(&msg, ERR_NO_MEM); - return (msg); - } - if ((p = strrchr(sp, ':')) != NULL) { - *p++ = '\0'; - port = atoi(p); - if ((port < 1) || (port > 65535)) { - xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); - free(sp); - return (msg); - } - } - - so = isns_open(sp); - if (so < 0) { - if (isns_enabled() == True) { - xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV); - } else { /* Just print a warning and accept the server */ - syslog(LOG_ALERT, - "Check if the server:%s is valid", sp); - } - } else { - isns_close(so); - } - free(sp); - return (msg); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt_remove.c b/usr/src/cmd/iscsi/iscsitgtd/mgmt_remove.c deleted file mode 100644 index 90757a0d0c..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_remove.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * 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. - */ - -/* - * This file deals with XML data for removing various configuration data. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <errno.h> -#include <strings.h> -#include <unistd.h> -#include <priv.h> -#include <syslog.h> -#include <libzfs.h> - -#include <iscsitgt_impl.h> -#include "utility.h" -#include "queue.h" -#include "target.h" -#include "iscsi_cmd.h" -#include "errcode.h" -#include "isns_client.h" -#include "mgmt_scf.h" - -static char *remove_target(tgt_node_t *x, ucred_t *cred); -static char *remove_initiator(tgt_node_t *x); -static char *remove_tpgt(tgt_node_t *x); -static char *remove_zfs(tgt_node_t *x, ucred_t *cred); - - -/*ARGSUSED*/ -void -remove_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt, - ucred_t *cred) -{ - tgt_node_t *x; - char msgbuf[80]; - char *reply_msg = NULL; - - x = p->x_child; - - /* - * remove_zfs() does not affect SMF data - * therefore it is not covered by auth check - */ - if (x == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_ZFS) == 0) { - reply_msg = remove_zfs(x, cred); - } else if (check_auth_addremove(cred) != True) { - xml_rtn_msg(&reply_msg, ERR_NO_PERMISSION); - } else { - if (x->x_name == NULL) { - xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT); - } else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) { - reply_msg = remove_target(x, cred); - } else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) { - reply_msg = remove_initiator(x); - } else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) { - reply_msg = remove_tpgt(x); - } else { - (void) snprintf(msgbuf, sizeof (msgbuf), - "Unknown object '%s' for delete element", - x->x_name); - xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT); - } - } - queue_message_set(reply, 0, msg_mgmt_rply, reply_msg); -} - -/* - * remove_zfs -- remove a ZFS property, or the entire ZVOL - */ -static char * -remove_zfs(tgt_node_t *x, ucred_t *cred) -{ - char *msg = NULL; - char *dataset = NULL; - char *prop = NULL; - tgt_node_t *n = NULL; - tgt_node_t *t = NULL; - tgt_node_t *list = NULL; - tgt_node_t *c; - Boolean_t change_made = False; - uint64_t size; - int status; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - /* - * Check for existance of ZFS shareiscsi properties - */ - status = get_zfs_shareiscsi(dataset, &n, &size, cred); - - if ((status != ERR_SUCCESS) && (status != ERR_ZFS_ISCSISHARE_OFF) && - (status != ERR_NULL_XML_MESSAGE)) { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) - != NULL) { - if (strcmp(t->x_value, dataset) == 0) - break; - } - - if (t == NULL) { - if (status == ERR_ZFS_ISCSISHARE_OFF) { - /* - * This is iscsishare=off request from zfs on a target - * which is already unshared. In that case, zfs expects - * "success" result. - */ - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - } - goto error; - } - - if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); - goto error; - } - if (status == ERR_ZFS_ISCSISHARE_OFF) { - xml_rtn_msg(&msg, status); - goto error; - } - - /* - * Due to the fact that the targets_config differs from the - * ZVOL properties stored in zfs_shareiscsi, two lists need to - * be updated - */ - c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop); - if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) != - NULL) { - (void) tgt_node_remove(list, c, MatchBoth); - if (list->x_child == NULL) - (void) tgt_node_remove(t, list, MatchName); - } - if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL)) != - NULL) { - (void) tgt_node_remove(list, c, MatchBoth); - if (list->x_child == NULL) - (void) tgt_node_remove(n, list, MatchName); - } - tgt_node_free(c); - - /* update isns */ - if (isns_enabled()) { - if (isns_dev_update(t->x_value, ISNS_MOD_TPGT) != 0) - syslog(LOG_ALERT, "ISNS register failed\n"); - } - free(prop); - prop = NULL; - change_made = True; - } - - if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); - goto error; - } - if (status == ERR_ZFS_ISCSISHARE_OFF) { - xml_rtn_msg(&msg, status); - goto error; - } - /* - * Due to the fact that the targets_config differs from the - * ZVOL properties stored in zfs_shareiscsi, two lists need to - * be updated - */ - c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); - if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) != - NULL) { - (void) tgt_node_remove(list, c, MatchBoth); - if (list->x_child == NULL) - (void) tgt_node_remove(t, list, MatchName); - } - if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL)) != - NULL) { - (void) tgt_node_remove(list, c, MatchBoth); - if (list->x_child == NULL) - (void) tgt_node_remove(n, list, MatchName); - } - tgt_node_free(c); - free(prop); - prop = NULL; - change_made = True; - } - - if (change_made == False) { - if (tgt_find_value_str(t, XML_ELEMENT_INAME, &prop) == False) { - xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); - goto error; - } - - /* deregister zovl target from iSNS server. */ - if (isns_enabled() == True) { - if (isns_dereg(prop) != 0) - syslog(LOG_INFO, "ISNS dereg failed\n"); - } - - (void) tgt_node_remove(targets_config, t, MatchBoth); - - /* - * Wait until here to issue a logout to any initiators that - * might be logged into the target. Certain initiators are - * sneaky in that if asked to logout they will, but turn right - * around and log back into the target. By waiting here to issue - * the logout we'll have removed reference to the target such - * that this can't happen. - */ - logout_targ(prop); - thick_provo_stop(prop, 0); - - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - status = put_zfs_shareiscsi(dataset, n); - if (status != ERR_SUCCESS) { - xml_rtn_msg(&msg, status); - goto error; - } else { - xml_rtn_msg(&msg, ERR_SUCCESS); - } - } - -error: - if (prop) - free(prop); - if (n) - tgt_node_free(n); - if (dataset) - free(dataset); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -static char * -remove_target(tgt_node_t *x, ucred_t *cred) -{ - char *msg = NULL; - char *prop = NULL; - tgt_node_t *targ = NULL; - tgt_node_t *list; - tgt_node_t *c = NULL; - Boolean_t change_made = False; - int lun_num; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - goto error; - } - - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - if (strcmp(targ->x_value, prop) == 0) - break; - } - free(prop); - prop = NULL; - if (targ == NULL) { - xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); - goto error; - } - - if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &prop) == True) { - if (strcmp(prop, "true") == 0) { - free(prop); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (remove_zfs(x, cred)); - } - free(prop); - } - - if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); - goto error; - } - if ((list = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == - NULL) { - xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND); - goto error; - } - c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); - if (tgt_node_remove(list, c, MatchBoth) == False) { - xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); - goto error; - } - tgt_node_free(c); - if (list->x_child == NULL) - (void) tgt_node_remove(targ, list, MatchName); - free(prop); - change_made = True; - } - if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); - goto error; - } - if ((list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL)) == - NULL) { - xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); - goto error; - } - c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop); - if (tgt_node_remove(list, c, MatchBoth) == False) { - xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); - goto error; - } - tgt_node_free(c); - if (list->x_child == NULL) - (void) tgt_node_remove(targ, list, MatchName); - - /* update isns */ - if (isns_enabled()) { - if (isns_dev_update(targ->x_value, ISNS_MOD_TPGT) != 0) - syslog(LOG_ALERT, "ISNS register failed\n"); - } - - free(prop); - prop = NULL; - change_made = True; - } - if (tgt_find_value_int(x, XML_ELEMENT_LUN, &lun_num) == True) { - - if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun_num) == - False) { - xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); - goto error; - } - - /* - * Save the iscsi-name which we'll need to remove LUNs. - */ - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == - False) { - xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); - goto error; - } - - logout_targ(prop); - thick_provo_stop(prop, lun_num); - - remove_target_common(targ->x_value, lun_num, &msg); - if (msg != NULL) - goto error; - - /* ISNS de-register target if it's the last lun */ - if (lun_num == 0 && isns_enabled() == True) { - if (isns_dereg(prop) != 0) - syslog(LOG_INFO, "ISNS dereg failed\n"); - } - - iscsi_inventory_change(prop); - free(prop); - change_made = True; - } - - if (change_made == True) { - if (mgmt_config_save2scf() == True) { - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - } - } else { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - } - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - -error: - if (c != NULL) - tgt_node_free(c); - if (prop != NULL) - free(prop); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -static char * -remove_initiator(tgt_node_t *x) -{ - char *msg = NULL; - char *name; - tgt_node_t *node = NULL; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - } - while ((node = tgt_node_next_child(main_config, XML_ELEMENT_INIT, node)) - != NULL) { - if (strcmp(node->x_value, name) == 0) - break; - } - free(name); - if (node == NULL) { - xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - } - if (tgt_find_value_str(x, XML_ELEMENT_ALL, &name) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_ALL); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - } - (void) tgt_node_remove(main_config, node, MatchBoth); - - if (mgmt_config_save2scf() == True) { - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - } - - free(name); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} - -static char * -remove_tpgt(tgt_node_t *x) -{ - char *msg = NULL; - char *prop = NULL; - tgt_node_t *targ = NULL; - tgt_node_t *lnode = NULL; - tgt_node_t *lnp = NULL; - tgt_node_t *node = NULL; - tgt_node_t *c = NULL; - tgt_node_t *list = NULL; - Boolean_t change_made = False; - - (void) pthread_rwlock_wrlock(&targ_config_mutex); - if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - } - while ((node = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, node)) - != NULL) { - if (strcmp(node->x_value, prop) == 0) - break; - } - if (node == NULL) { - xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); - free(prop); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - } - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - if ((lnode = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, - NULL)) != NULL) { - lnp = NULL; - while ((lnp = tgt_node_next_child(lnode, XML_ELEMENT_TPGT, - lnp)) != NULL) - if (strcmp(lnp->x_value, prop) == 0) { - xml_rtn_msg(&msg, ERR_TPGT_IN_USE); - free(prop); - (void) pthread_rwlock_unlock( - &targ_config_mutex); - return (msg); - } - } - } - free(prop); - if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &prop) == True) { - if (prop == NULL) { - xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_IPADDR); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - } - if ((list = tgt_node_next(node, XML_ELEMENT_IPADDRLIST, NULL)) - == NULL) { - xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR); - goto error; - } - c = tgt_node_alloc(XML_ELEMENT_IPADDR, String, prop); - if (tgt_node_remove(list, c, MatchBoth) == False) { - xml_rtn_msg(&msg, ERR_INVALID_IP); - goto error; - } - tgt_node_free(c); - free(prop); - if (list->x_child == NULL) - (void) tgt_node_remove(node, list, MatchName); - change_made = True; - } - if ((change_made != True) && - (tgt_find_value_str(x, XML_ELEMENT_ALL, &prop) == True)) { - (void) tgt_node_remove(main_config, node, MatchBoth); - change_made = True; - free(prop); - } - - if (change_made == True) { - /* Isns re-register all target */ - if (isns_enabled() == True) - (void) isns_reg_all(); - if (mgmt_config_save2scf() == True) { - xml_rtn_msg(&msg, ERR_SUCCESS); - } else { - xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); - } - } else { - xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); - } - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); - -error: - if (c != NULL) - tgt_node_free(c); - if (prop != NULL) - free(prop); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (msg); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c b/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c deleted file mode 100644 index 11b316eb35..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.c +++ /dev/null @@ -1,1647 +0,0 @@ -/* - * 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. - */ - -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <time.h> -#include <unistd.h> -#include <pthread.h> -#include <sys/conf.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <assert.h> -#include <errno.h> -#include <signal.h> -#include <siginfo.h> -#include <libscf.h> -#include <syslog.h> -#include <synch.h> -#include <libxml/xmlreader.h> -#include <sys/resource.h> -#include <sys/select.h> -#include <iscsitgt_impl.h> -#include <umem.h> -#include <priv.h> -#include <libgen.h> -#include <ctype.h> -#include <pthread.h> -#include <pwd.h> -#include <auth_attr.h> -#include <sasl/saslutil.h> -#include <sys/wait.h> - -#include "mgmt_scf.h" -#include "port.h" -#include "iscsi_conn.h" -#include "target.h" -#include "utility.h" -#include "iscsi_ffp.h" -#include "errcode.h" -#include "t10.h" - -static Boolean_t create_pg(targ_scf_t *h, char *pgname, char *prop); -static void new_property(targ_scf_t *h, tgt_node_t *n); -static void new_value_list(targ_scf_t *h, tgt_node_t *p); -static int isnumber(char *s); -static void backup(char *file, char *ext); -static pthread_mutex_t scf_conf_mutex; -static pthread_mutex_t scf_param_mutex; - -static void pgname_encode(char *instr, char *outstr, int max_len); -static void pgname_decode(char *instr); - -Boolean_t -mgmt_scf_init() -{ - (void) pthread_mutex_init(&scf_conf_mutex, NULL); - (void) pthread_mutex_init(&scf_param_mutex, NULL); - return (True); -} - -void -mgmt_scf_fini() -{ - (void) pthread_mutex_destroy(&scf_conf_mutex); - (void) pthread_mutex_destroy(&scf_param_mutex); -} - -void -mgmt_handle_fini(targ_scf_t *h) -{ - if (h != NULL) { - int unbind = 0; - if (h->t_scope != NULL) { - unbind = 1; - scf_scope_destroy(h->t_scope); - h->t_scope = NULL; - } - if (h->t_instance != NULL) { - scf_instance_destroy(h->t_instance); - h->t_instance = NULL; - } - if (h->t_service != NULL) { - scf_service_destroy(h->t_service); - h->t_service = NULL; - } - if (h->t_pg != NULL) { - scf_pg_destroy(h->t_pg); - h->t_pg = NULL; - } - if (h->t_handle != NULL) { - if (unbind) - (void) scf_handle_unbind(h->t_handle); - scf_handle_destroy(h->t_handle); - h->t_handle = NULL; - } - free(h); - h = NULL; - } -} - -targ_scf_t * -mgmt_handle_init(void) -{ - targ_scf_t *h; - - h = calloc(1, sizeof (targ_scf_t)); - if (h == NULL) - return (NULL); - - h->t_handle = scf_handle_create(SCF_VERSION); - if (h->t_handle != NULL) { - if (scf_handle_bind(h->t_handle) == 0) { - h->t_scope = scf_scope_create(h->t_handle); - h->t_service = scf_service_create(h->t_handle); - h->t_pg = scf_pg_create(h->t_handle); - h->t_instance = scf_instance_create(h->t_handle); - if (scf_handle_get_scope(h->t_handle, SCF_SCOPE_LOCAL, - h->t_scope) == 0) { - if (scf_scope_get_service(h->t_scope, - SA_TARGET_SVC_NAME, h->t_service) != 0) - goto error; - - } else { - syslog(LOG_ERR, - "Got local scope which is wrong\n"); - goto error; - } - } else - goto error; - } else { - free(h); - h = NULL; - syslog(LOG_ERR, - "iscsitgt could not access SMF repository: %s\n", - scf_strerror(scf_error())); - } - - return (h); -error: - mgmt_handle_fini(h); - free(h); - syslog(LOG_ERR, "iscsitgt SMF initialization problem: %s\n", - scf_strerror(scf_error())); - return (NULL); -} - -/* - * This function starts a transaction with name of a property group - * and name of its property. If the property group does not exist - * this function will create an empty property group. - */ -Boolean_t -mgmt_transaction_start(targ_scf_t *h, char *pg, char *prop) -{ - Boolean_t ret = True; - - h->t_trans = scf_transaction_create(h->t_handle); - if (h->t_trans != NULL) { - if ((create_pg(h, pg, prop) == False) || - (scf_transaction_start(h->t_trans, h->t_pg) != 0)) { - scf_transaction_destroy(h->t_trans); - h->t_trans = NULL; - ret = False; - syslog(LOG_ERR, "transaction_start start: %s\n", - scf_strerror(scf_error())); - } - } else { - syslog(LOG_ERR, "transaction_start create: %s\n", - scf_strerror(scf_error())); - ret = False; - } - return (ret); -} - -Boolean_t -mgmt_transaction_end(targ_scf_t *h) -{ - Boolean_t ret = True; - - if (scf_transaction_commit(h->t_trans) < 0) - ret = False; - (void) scf_pg_update(h->t_pg); - (void) scf_transaction_destroy_children(h->t_trans); - (void) scf_transaction_destroy(h->t_trans); - h->t_trans = NULL; - return (ret); -} - -void -mgmt_transaction_abort(targ_scf_t *h) -{ - if (h->t_trans != NULL) { - scf_transaction_reset_all(h->t_trans); - scf_transaction_destroy_children(h->t_trans); - scf_transaction_destroy(h->t_trans); - h->t_trans = NULL; - } -} - -/* - * process property group name first - * a reasonable buf to receive encoded pgname is double size of pgname - */ -#define PG_FACTOR 2 -static Boolean_t -create_pg(targ_scf_t *h, char *pgname, char *prop) -{ - int len; - char *buf = NULL; - - len = strlen(pgname); - buf = (char *)calloc(1, len * PG_FACTOR); - if (buf == NULL) - return (False); - - pgname_encode(pgname, buf, len * PG_FACTOR); - - if (scf_service_get_pg(h->t_service, buf, h->t_pg) != 0) { - if (scf_service_add_pg(h->t_service, buf, - prop, 0, h->t_pg) != 0) { - free(buf); - return (False); - } - } - free(buf); - return (True); -} - -/* - * Manage allocating dynamic memory for a string that is stored in - * the SCF database. - * - * scf_limit(3SCF) is called in order to compute the maximum length of - * the type of string specified by the 'limit' argument. malloc() - * is then called to allocate the memory. - * - * If the function returns True, then the by-reference arguments will - * be updated to hold the length and address of the memory chunk. - */ -static Boolean_t -alloc_scf_element(uint32_t limit, ssize_t *max_len, void **buf) -{ - ssize_t max_name_len; - void *name_buf; - Boolean_t status = False; - - /* - * Dynamically compute the maximum length of the specified type - * of string so that our algorithms do not use an arbitrary, - * statically-defined value. - */ - if ((max_name_len = scf_limit(limit)) >= 0) { - /* - * scf_limit's return value knows nothing about a C-string's - * trailing NULL byte; increment the count to allow for it. - */ - max_name_len++; - - if ((name_buf = malloc(max_name_len)) != NULL) { - *max_len = max_name_len; - *buf = name_buf; - status = True; - } - } - - return (status); -} - -/* - * Allocate dynamic memory for a string containing a NAME that is stored in - * the SCF database. - */ -static Boolean_t -alloc_scf_name(ssize_t *max_len, void **buf) -{ - return (alloc_scf_element(SCF_LIMIT_MAX_NAME_LENGTH, max_len, buf)); -} - -/* - * Allocate dynamic memory for a string containing a VALUE that is stored in - * the SCF database. - */ -static Boolean_t -alloc_scf_value(ssize_t *max_len, void **buf) -{ - return (alloc_scf_element(SCF_LIMIT_MAX_VALUE_LENGTH, max_len, buf)); -} - -/* - * mgmt_get_main_config() loads main configuration - * from scf into a node tree. - * Main configuration includes: admin/target/tpgt/initiator info. - * admin info is stored in "iscsitgt" property group - * target info is stored in "target_<name>" property group - * initiator info is stored in "initiator_<name>" property group - * tpgt info is stored in "tpgt_<number>" property group - */ -Boolean_t -mgmt_get_main_config(tgt_node_t **node) -{ - targ_scf_t *h = NULL; - scf_property_t *prop = NULL; - scf_value_t *value = NULL; - scf_iter_t *iter = NULL; - scf_iter_t *iter_v = NULL; - scf_iter_t *iter_pv = NULL; - char *pname = NULL; - char *valuebuf = NULL; - ssize_t max_name_len; - ssize_t max_value_len; - char passcode[32]; - unsigned int outlen; - tgt_node_t *n; - tgt_node_t *pn; - tgt_node_t *vn; - Boolean_t status = False; - - h = mgmt_handle_init(); - - if (h == NULL) - return (status); - - prop = scf_property_create(h->t_handle); - value = scf_value_create(h->t_handle); - iter = scf_iter_create(h->t_handle); - - if ((alloc_scf_name(&max_name_len, (void *)&pname) == False) || - (alloc_scf_value(&max_value_len, (void *)&valuebuf) == False)) { - goto error; - } - - (void) pthread_mutex_lock(&scf_conf_mutex); - - /* Basic Information is stored in iscsitgt pg */ - if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == -1) { - goto error; - } - - *node = NULL; - *node = tgt_node_alloc("main_config", String, NULL); - if (*node == NULL) - goto error; - - if (scf_iter_pg_properties(iter, h->t_pg) == -1) { - goto error; - } - - while (scf_iter_next_property(iter, prop) > 0) { - (void) scf_property_get_value(prop, value); - (void) scf_value_get_as_string(value, valuebuf, max_value_len); - (void) scf_property_get_name(prop, pname, max_name_len); - - /* avoid load auth to incore data */ - if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || - strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || - strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) - continue; - - n = tgt_node_alloc(pname, String, valuebuf); - if (n == NULL) - goto error; - - /* put version info into root node's attr */ - if (strcmp(pname, XML_ELEMENT_VERS) == 0) { - tgt_node_add_attr(*node, n); - } else { - /* add other basic info into root node */ - tgt_node_add(*node, n); - } - } - - /* - * targets/initiators/tpgt information is - * stored as type "configuration" in scf - * each target's param is stored as type "parameter" - */ - if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration") - == -1) { - goto error; - } - - while (scf_iter_next_pg(iter, h->t_pg) > 0) { - char *iname; - - (void) scf_pg_get_name(h->t_pg, pname, max_name_len); - pgname_decode(pname); - iname = strchr(pname, '_'); - if (iname == NULL) { - /* the pg found here is not a tgt/initiator/tpgt */ - continue; - } - *iname = '\0'; - iname++; - /* - * now pname is "target" or "initiator" or "tpgt" - * meanwhile iname is the actual name of the item - */ - - n = tgt_node_alloc(pname, String, iname); - if (n == NULL) - goto error; - - iter_v = scf_iter_create(h->t_handle); - if (scf_iter_pg_properties(iter_v, h->t_pg) == -1) { - goto error; - } - while (scf_iter_next_property(iter_v, prop) > 0) { - /* there may be many values in one property */ - char *vname; - - (void) scf_property_get_name(prop, pname, - max_name_len); - /* avoid load auth to incore data */ - if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || - strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || - strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) - continue; - - vname = strstr(pname, "-list"); - if (vname == NULL) { - (void) scf_property_get_value(prop, value); - (void) scf_value_get_as_string(value, valuebuf, - max_value_len); - - pn = tgt_node_alloc(pname, String, valuebuf); - if (pn == NULL) - goto error; - tgt_node_add(n, pn); - } else { - pn = tgt_node_alloc(pname, String, NULL); - if (pn == NULL) - goto error; - tgt_node_add(n, pn); - *vname = '\0'; - - iter_pv = scf_iter_create(h->t_handle); - (void) scf_iter_property_values(iter_pv, prop); - while (scf_iter_next_value(iter_pv, value) - > 0) { - (void) scf_value_get_as_string( - value, valuebuf, max_value_len); - /* - * map 'acl' to 'initiator' since that - * is what used inside the acl-list. - */ - if (strcmp(pname, XML_ELEMENT_ACL) - == 0) { - vn = tgt_node_alloc( - XML_ELEMENT_INIT, - String, valuebuf); - } else { - vn = tgt_node_alloc( - pname, String, valuebuf); - } - if (vn == NULL) - goto error; - tgt_node_add(pn, vn); - } - scf_iter_destroy(iter_pv); - iter_pv = NULL; - } - } - tgt_node_add(*node, n); - scf_iter_destroy(iter_v); - iter_v = NULL; - } - - /* chap-secrets are stored in "passwords" pgroup as "application" */ - if (scf_service_get_pg(h->t_service, "passwords", h->t_pg) == 0) { - if (scf_iter_pg_properties(iter, h->t_pg) == -1) { - goto error; - } - - while (scf_iter_next_property(iter, prop) > 0) { - (void) scf_property_get_value(prop, value); - (void) scf_value_get_as_string(value, valuebuf, - max_value_len); - (void) scf_property_get_name(prop, pname, - max_name_len); - - /* avoid load auth to incore data */ - if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || - strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || - strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) - continue; - - /* max length of decoded passwd is 16B */ - (void) sasl_decode64(valuebuf, strlen(valuebuf), - passcode, sizeof (passcode), &outlen); - - if (strcmp(pname, "radius") == 0) { - pn = tgt_node_alloc(XML_ELEMENT_RAD_SECRET, - String, passcode); - tgt_node_add(*node, pn); - } else if (strcmp(pname, "main") == 0) { - pn = tgt_node_alloc(XML_ELEMENT_CHAPSECRET, - String, passcode); - tgt_node_add(*node, pn); - } else { - /* find corresponding initiator */ - n = NULL; - while (n = tgt_node_next_child(*node, - XML_ELEMENT_INIT, n)) { - if (strcmp(pname + 2, n->x_value) != 0) - continue; - pn = tgt_node_alloc( - XML_ELEMENT_CHAPSECRET, - String, passcode); - tgt_node_add(n, pn); - } - } - } - } - - status = True; -error: - if ((status != True) && (*node != NULL)) - tgt_node_free(*node); - (void) pthread_mutex_unlock(&scf_conf_mutex); - if (iter_pv != NULL) - scf_iter_destroy(iter_pv); - if (iter_v != NULL) - scf_iter_destroy(iter_v); - - free(valuebuf); - free(pname); - - scf_iter_destroy(iter); - scf_value_destroy(value); - scf_property_destroy(prop); - mgmt_handle_fini(h); - return (status); -} - -static int -isnumber(char *s) -{ - register int c; - - if (!s || !(*s)) - return (0); - while ((c = *(s++)) != '\0') { - if (!isdigit(c)) - return (0); - } - return (1); -} - -static void -new_property(targ_scf_t *h, - tgt_node_t *n) -{ - scf_transaction_entry_t *e = NULL; - scf_value_t *v = NULL; - scf_type_t type; - - assert(n != NULL); - - e = scf_entry_create(h->t_handle); - v = scf_value_create(h->t_handle); - - if (strcmp(n->x_value, "true") == 0 || - strcmp(n->x_value, "false") == 0) { - type = SCF_TYPE_BOOLEAN; - } else if (strcmp(n->x_name, "main") == 0 || - strcmp(n->x_name, "radius") == 0) { - type = SCF_TYPE_ASTRING; - } else if (strncmp(n->x_name, "I_", 2) == 0) { - type = SCF_TYPE_ASTRING; - } else if (strcmp(n->x_name, XML_ELEMENT_VERS) == 0) { - type = SCF_TYPE_ASTRING; - } else if (isnumber(n->x_value)) { - type = SCF_TYPE_COUNT; - } else { - type = SCF_TYPE_ASTRING; - } - if ((scf_transaction_property_new(h->t_trans, e, n->x_name, type) - == 0)) { - (void) scf_value_set_from_string(v, type, n->x_value); - (void) scf_entry_add_value(e, v); - } else { - scf_entry_destroy(e); - scf_value_destroy(v); - } -} - -static void -new_value_list(targ_scf_t *h, - tgt_node_t *p) -{ - scf_transaction_entry_t *e = NULL; - scf_value_t *v = NULL; - tgt_node_t *c; - char *name; - - assert(p != NULL); - - name = p->x_name; - e = scf_entry_create(h->t_handle); - (void) scf_transaction_property_new(h->t_trans, e, name, - SCF_TYPE_ASTRING); - - for (c = p->x_child; c; c = c->x_sibling) { - v = scf_value_create(h->t_handle); - (void) scf_value_set_astring(v, c->x_value); - (void) scf_entry_add_value(e, v); - } -} - -/* - * mgmt_config_save2scf() saves main configuration to scf - * See also : mgmt_get_main_config() - */ -Boolean_t -mgmt_config_save2scf() -{ - targ_scf_t *h = NULL; - scf_property_t *prop = NULL; - scf_value_t *value = NULL; - scf_iter_t *iter = NULL; - char *pgname = NULL; - ssize_t max_name_len; - char passcode[32]; - char *incore = NULL; - unsigned int outlen; - tgt_node_t *n = NULL; - tgt_node_t *pn = NULL; - tgt_node_t *tn = NULL; - scf_transaction_t *tx = NULL; - secret_list_t *sl_head; - secret_list_t *sl_tail; - Boolean_t status = False; - - h = mgmt_handle_init(); - - if (h == NULL) - return (status); - - prop = scf_property_create(h->t_handle); - value = scf_value_create(h->t_handle); - iter = scf_iter_create(h->t_handle); - - if (alloc_scf_name(&max_name_len, (void *)&pgname) == False) { - goto error; - } - - (void) pthread_mutex_lock(&scf_conf_mutex); - - if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { - (void) scf_pg_delete(h->t_pg); - (void) mgmt_transaction_end(h); - } - - if (mgmt_transaction_start(h, "passwords", "application") == True) { - (void) scf_pg_delete(h->t_pg); - (void) mgmt_transaction_end(h); - } - - if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration") - == -1) { - goto error; - } - - tx = scf_transaction_create(h->t_handle); - while (scf_iter_next_pg(iter, h->t_pg) > 0) { - (void) scf_transaction_start(tx, h->t_pg); - (void) scf_pg_delete(h->t_pg); - (void) scf_transaction_commit(tx); - } - scf_transaction_reset(tx); - scf_transaction_destroy(tx); - - sl_head = (secret_list_t *)calloc(1, sizeof (secret_list_t)); - sl_tail = sl_head; - - if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { - for (n = main_config->x_child; n; n = n->x_sibling) { - if ((tgt_find_attr_str(n, XML_ELEMENT_INCORE, &incore)) - == True) { - if (strcmp(incore, "true") == 0) { - /* - * Ignore in core only elements. - * zvol target is the only one with - * incore attr as of now. - */ - free(incore); - continue; - } - /* if incore is false continue on */ - free(incore); - } - if (strcmp(n->x_name, - XML_ELEMENT_CHAPSECRET) == 0) { - sl_tail->next = (secret_list_t *) - calloc(1, sizeof (secret_list_t)); - sl_tail = sl_tail->next; - sl_tail->name = strdup("main"); - sl_tail->secret = strdup(n->x_value); - continue; - } - /* so does the radius server secret */ - if (strcmp(n->x_name, - XML_ELEMENT_RAD_SECRET) == 0) { - sl_tail->next = (secret_list_t *) - calloc(1, sizeof (secret_list_t)); - sl_tail = sl_tail->next; - sl_tail->name = strdup("radius"); - sl_tail->secret = strdup(n->x_value); - continue; - } - if (n->x_child == NULL) { - new_property(h, n); - } - } - new_property(h, main_config->x_attr); - n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, - ISCSI_AUTH_MODIFY); - new_property(h, n); - tgt_node_free(n); - n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, - ISCSI_AUTH_VALUE); - new_property(h, n); - tgt_node_free(n); - (void) mgmt_transaction_end(h); - } - - /* now update target/initiator/tpgt information */ - for (n = main_config->x_child; n; n = n->x_sibling) { - if (n->x_child == NULL) - continue; - - if ((tgt_find_attr_str(n, XML_ELEMENT_INCORE, &incore)) - == True) { - if (strcmp(incore, "true") == 0) { - /* - * Ignore in core only elements. - * zvol target is the only one with - * incore attr as of now. - */ - free(incore); - continue; - } - /* if incore is false continue on */ - free(incore); - } - - (void) snprintf(pgname, max_name_len, "%s_%s", n->x_name, - n->x_value); - - if (mgmt_transaction_start(h, pgname, "configuration") - == True) { - for (pn = n->x_child; pn; pn = pn->x_sibling) { - if (strcmp(pn->x_name, - XML_ELEMENT_CHAPSECRET) == 0) { - sl_tail->next = (secret_list_t *) - calloc(1, sizeof (secret_list_t)); - sl_tail = sl_tail->next; - sl_tail->name = (char *) - calloc(1, strlen(n->x_value) + 3); - (void) snprintf(sl_tail->name, - strlen(n->x_value) + 3, - "I_%s", n->x_value); - sl_tail->secret = strdup(pn->x_value); - continue; - } - if (pn->x_child == NULL) { - /* normal property */ - new_property(h, pn); - } else { - /* pn -> xxx-list */ - new_value_list(h, pn); - } - tn = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, - String, ISCSI_AUTH_MODIFY); - new_property(h, tn); - tgt_node_free(tn); - tn = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, - String, ISCSI_AUTH_VALUE); - new_property(h, tn); - tgt_node_free(tn); - } - (void) mgmt_transaction_end(h); - } else - goto error; - } - - if (mgmt_transaction_start(h, "passwords", "application") == True) { - while (sl_head != NULL) { - /* Here we use sl_tail as a temporari var */ - sl_tail = sl_head->next; - if (sl_head->name) { - /* max length of encoded passwd is 24B */ - (void) sasl_encode64(sl_head->secret, - strlen(sl_head->secret), passcode, - sizeof (passcode), &outlen); - - n = tgt_node_alloc(sl_head->name, String, - passcode); - new_property(h, n); - tgt_node_free(n); - } - if (sl_head->name) - free(sl_head->name); - if (sl_head->secret) - free(sl_head->secret); - free(sl_head); - sl_head = sl_tail; - } - n = tgt_node_alloc(ISCSI_READ_AUTHNAME, String, - ISCSI_AUTH_READ); - new_property(h, n); - tgt_node_free(n); - n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, - ISCSI_AUTH_VALUE); - new_property(h, n); - tgt_node_free(n); - n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, - ISCSI_AUTH_MODIFY); - new_property(h, n); - tgt_node_free(n); - (void) mgmt_transaction_end(h); - } - - if (smf_refresh_instance(SA_TARGET_SVC_INSTANCE_FMRI) != 0) - goto error; - - status = True; -error: - (void) pthread_mutex_unlock(&scf_conf_mutex); - free(pgname); - scf_iter_destroy(iter); - scf_value_destroy(value); - scf_property_destroy(prop); - mgmt_handle_fini(h); - return (status); -} - -Boolean_t -mgmt_param_save2scf(tgt_node_t *node, char *target_name, int lun) -{ - targ_scf_t *h = NULL; - char *pgname = NULL; - ssize_t max_name_len; - tgt_node_t *n = NULL; - Boolean_t status = False; - - h = mgmt_handle_init(); - - if (h == NULL) - return (status); - - if (alloc_scf_name(&max_name_len, (void *)&pgname) == False) { - goto error; - } - - (void) snprintf(pgname, max_name_len, "param_%s_%d", target_name, - lun); - - (void) pthread_mutex_lock(&scf_param_mutex); - - if (mgmt_transaction_start(h, pgname, "parameter") == True) { - (void) scf_pg_delete(h->t_pg); - (void) mgmt_transaction_end(h); - } - - if (mgmt_transaction_start(h, pgname, "parameter") == True) { - for (n = node->x_child; n; n = n->x_sibling) { - if (n->x_child == NULL) { - /* now n is node of basic property */ - new_property(h, n); - } - } - new_property(h, node->x_attr); - n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, - ISCSI_AUTH_VALUE); - new_property(h, n); - tgt_node_free(n); - n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, - ISCSI_AUTH_MODIFY); - new_property(h, n); - tgt_node_free(n); - (void) mgmt_transaction_end(h); - } - - status = True; -error: - (void) pthread_mutex_unlock(&scf_param_mutex); - free(pgname); - mgmt_handle_fini(h); - return (status); -} - -/* - * mgmt_get_param() get parameter of a specific LUN from scf - * Args: - * node - the node which parameters will be stored in mem - * target_name - the local target name - * lun - the LUN number - * See also : mgmt_param_save2scf() - */ -Boolean_t -mgmt_get_param(tgt_node_t **node, char *target_name, int lun) -{ - targ_scf_t *h = NULL; - scf_property_t *prop = NULL; - scf_value_t *value = NULL; - scf_iter_t *iter = NULL; - char *pname = NULL; - char *expgname = NULL; - char *pgname = NULL; - char *valuebuf = NULL; - ssize_t max_name_len; - ssize_t expg_max_name_len; - ssize_t max_value_len; - tgt_node_t *n; - Boolean_t status = False; - - /* Set NULL as default output value */ - *node = NULL; - h = mgmt_handle_init(); - - if (h == NULL) - return (status); - - prop = scf_property_create(h->t_handle); - value = scf_value_create(h->t_handle); - iter = scf_iter_create(h->t_handle); - - if ((alloc_scf_name(&max_name_len, (void *)&pname) == NULL) || - (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) || - (alloc_scf_value(&max_value_len, (void *)&valuebuf) == NULL)) { - goto error; - } - - /* - * Allocate memory for an "expanded" (or "decoded") Property Group - * name. - */ - expg_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) * PG_FACTOR - + 1; - if ((expgname = malloc(expg_max_name_len)) == NULL) { - goto error; - } - - (void) snprintf(pgname, max_name_len, "param_%s_%d", target_name, - lun); - pgname_encode(pgname, expgname, max_name_len); - - (void) pthread_mutex_lock(&scf_param_mutex); - - if (scf_service_get_pg(h->t_service, expgname, h->t_pg) == -1) { - goto error; - } - - *node = tgt_node_alloc(XML_ELEMENT_PARAMS, String, NULL); - if (*node == NULL) - goto error; - - if (scf_iter_pg_properties(iter, h->t_pg) == -1) { - goto error; - } - - while (scf_iter_next_property(iter, prop) > 0) { - (void) scf_property_get_value(prop, value); - (void) scf_value_get_as_string(value, valuebuf, max_value_len); - (void) scf_property_get_name(prop, pname, max_name_len); - - /* avoid load auth to incore data */ - if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || - strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || - strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) - continue; - - n = tgt_node_alloc(pname, String, valuebuf); - if (n == NULL) - goto error; - - /* put version info into root node's attr */ - if (strcmp(pname, XML_ELEMENT_VERS) == 0) { - tgt_node_add_attr(*node, n); - } else { - /* add other basic info into root node */ - tgt_node_add(*node, n); - } - } - - status = True; -error: - (void) pthread_mutex_unlock(&scf_param_mutex); - - free(valuebuf); - free(expgname); - free(pgname); - free(pname); - - scf_iter_destroy(iter); - scf_value_destroy(value); - scf_property_destroy(prop); - mgmt_handle_fini(h); - return (status); -} - -Boolean_t -mgmt_param_remove(char *target_name, int lun) -{ - targ_scf_t *h = NULL; - char *pgname = NULL; - ssize_t max_name_len; - Boolean_t status = False; - - h = mgmt_handle_init(); - if (h == NULL) - return (status); - - if (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) { - goto error; - } - - (void) snprintf(pgname, max_name_len, "param_%s_%d", target_name, - lun); - - if (mgmt_transaction_start(h, pgname, "parameter") == True) { - (void) scf_pg_delete(h->t_pg); - (void) mgmt_transaction_end(h); - status = True; - } -error: - free(pgname); - mgmt_handle_fini(h); - return (status); -} - -/* - * mgmt_convert_param() converts legacy params file of each LUN - * to scf data. It will convert LUNs under one target each time. - * Args: - * dir - string of directory where param file is stored - * tnode - node tree which contains to a target - */ -Boolean_t -mgmt_convert_param(char *dir, tgt_node_t *tnode) -{ - Boolean_t ret = False; - char path[MAXPATHLEN]; - int xml_fd = -1; - int n; - int lun_num; - tgt_node_t *lun = NULL; - tgt_node_t *params = NULL; - xmlTextReaderPtr r; - - while ((lun = tgt_node_next(tnode, XML_ELEMENT_LUN, lun)) != NULL) { - if ((tgt_find_value_int(lun, XML_ELEMENT_LUN, &lun_num)) == - False) - continue; - (void) snprintf(path, sizeof (path), "%s/%s%d", - dir, PARAMBASE, lun_num); - if ((xml_fd = open(path, O_RDONLY)) < 0) - continue; - if ((r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, - NULL, NULL, 0)) == NULL) - continue; - - n = xmlTextReaderRead(r); - while (n == 1) { - if (tgt_node_process(r, ¶ms) == False) { - break; - } - n = xmlTextReaderRead(r); - } - if (n < 0) { - ret = False; - break; - } - - if (mgmt_param_save2scf(params, tnode->x_value, lun_num) - != True) { - ret = False; - break; - } else { - backup(path, tnode->x_value); - ret = True; - } - params = NULL; - (void) close(xml_fd); - (void) xmlTextReaderClose(r); - xmlFreeTextReader(r); - } - - if (ret == False) - syslog(LOG_ERR, "Converting target %s params failed", dir); - return (ret); -} - -/* - * Convert legacy (XML) configuration files into an equivalent SCF - * representation. - * - * Read the XML from disk, translate the XML into a tree of nodes of - * type tgt_node_t, and write the in-memory tree to SCF's persistent - * data-store using mgmt_config_save2scf(). - * - * Return Values: - * CONVERT_OK: successfully converted - * CONVERT_INIT_NEW: configuration files don't exist; created an SCF entry - * CONVERT_FAIL: some conversion error occurred; no SCF entry created. - * In this case, user has to manually check files and try - * conversion again. - */ -convert_ret_t -mgmt_convert_conf() -{ - targ_scf_t *h = NULL; - xmlTextReaderPtr r; - convert_ret_t ret = CONVERT_FAIL; - int xml_fd = -1; - int n; - tgt_node_t *node = NULL; - tgt_node_t *next = NULL; - char path[MAXPATHLEN]; - char *target = NULL; - - h = mgmt_handle_init(); - if (h == NULL) - return (CONVERT_FAIL); - - /* - * Check if the "iscsitgt" PropertyGroup has already been added - * to the "iscsitgt" SMF Service. If so, then we have already - * converted the legacy configuration files (and there is no work - * to do). - */ - if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) { - ret = CONVERT_OK; - goto done; - } - - if (access(config_file, R_OK) != 0) { - /* - * then the Main Config file is not present; initialize - * SCF Properties to default values. - */ - if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { - ret = CONVERT_INIT_NEW; - - node = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0"); - new_property(h, node); - tgt_node_free(node); - /* "daemonize" is set to true by default */ - node = tgt_node_alloc(XML_ELEMENT_DBGDAEMON, String, - "true"); - new_property(h, node); - tgt_node_free(node); - node = NULL; - node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, - ISCSI_AUTH_MODIFY); - new_property(h, node); - tgt_node_free(node); - node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, - ISCSI_AUTH_VALUE); - new_property(h, node); - tgt_node_free(node); - (void) mgmt_transaction_end(h); - } else { - syslog(LOG_ERR, "Creating empty entry failed"); - ret = CONVERT_FAIL; - goto done; - } - if (mgmt_transaction_start(h, "passwords", "application") == - True) { - node = tgt_node_alloc(ISCSI_READ_AUTHNAME, String, - ISCSI_AUTH_READ); - new_property(h, node); - tgt_node_free(node); - node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, - ISCSI_AUTH_MODIFY); - new_property(h, node); - tgt_node_free(node); - node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, - ISCSI_AUTH_VALUE); - new_property(h, node); - tgt_node_free(node); - (void) mgmt_transaction_end(h); - } else { - syslog(LOG_ERR, "Creating empty entry failed"); - ret = CONVERT_FAIL; - } - goto done; - } - - if ((xml_fd = open(config_file, O_RDONLY)) >= 0) - r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0); - - if (r != NULL) { - int is_target_config; - - n = xmlTextReaderRead(r); - while (n == 1) { - if (tgt_node_process(r, &node) == False) { - break; - } - n = xmlTextReaderRead(r); - } - if (n < 0) { - syslog(LOG_ERR, "Parsing main config failed"); - ret = CONVERT_FAIL; - goto done; - } - - main_config = node; - - /* - * Initialize the Base Directory (global) variable by - * using the value specified in the XML_ELEMENT_BASEDIR - * XML tag. If a tag is not specified, use a default. - */ - (void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR, - &target_basedir); - - if (target_basedir == NULL) - target_basedir = strdup(DEFAULT_TARGET_BASEDIR); - - if (xml_fd != -1) { - (void) close(xml_fd); - xml_fd = -1; - } - (void) xmlTextReaderClose(r); - xmlFreeTextReader(r); - xmlCleanupParser(); - - /* - * If a Target Config file is present, read and translate - * its XML representation into a tree of tgt_node_t. - * Merge that tree with the tree of tgt_node_t rooted at - * 'main_config'. The merged tree will then be archived - * using an SCF representation. - */ - (void) snprintf(path, MAXPATHLEN, "%s/%s", - target_basedir, "config.xml"); - - if ((xml_fd = open(path, O_RDONLY)) >= 0) { - is_target_config = 1; - r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, - NULL, NULL, 0); - } else { - is_target_config = 0; - r = NULL; - } - - if (r != NULL) { - /* then the Target Config file is available. */ - - node = NULL; - - /* - * Create a tree of tgt_node_t rooted at 'node' by - * processing each XML Tag in the file. - */ - n = xmlTextReaderRead(r); - while (n == 1) { - if (tgt_node_process(r, &node) == False) { - break; - } - n = xmlTextReaderRead(r); - } - if (n < 0) { - syslog(LOG_ERR, "Parsing target conf failed"); - ret = CONVERT_FAIL; - goto done; - } - - /* - * Merge the tree at 'node' into the tree rooted at - * 'main_config'. - */ - if (node != NULL) { - next = NULL; - while ((next = tgt_node_next(node, - XML_ELEMENT_TARG, next)) != NULL) { - tgt_node_add(main_config, - tgt_node_dup(next)); - } - tgt_node_free(node); - } - } - - /* - * Iterate over the in-memory tree rooted at 'main_config' - * and write a representation of the appropriate nodes to - * SCF's persistent data-store. - */ - if (mgmt_config_save2scf() != True) { - syslog(LOG_ERR, "Converting config failed"); - if (xml_fd != -1) { - (void) close(xml_fd); - xml_fd = -1; - } - (void) xmlTextReaderClose(r); - xmlFreeTextReader(r); - xmlCleanupParser(); - ret = CONVERT_FAIL; - goto done; - } - - /* - * Move the configuration files into a well-known backup - * directory. This allows a user to restore their - * configuration, if they choose. - */ - (void) snprintf(path, sizeof (path), "%s/backup", - target_basedir); - if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) { - syslog(LOG_ERR, "Creating backup dir failed"); - ret = CONVERT_FAIL; - goto done; - } - /* Save the Main Config file. */ - backup(config_file, NULL); - - /* Save the Target Config file, if it was present. */ - if (is_target_config != 0) { - (void) snprintf(path, MAXPATHLEN, "%s/%s", - target_basedir, "config.xml"); - backup(path, NULL); - } - - /* - * For each tgt_node_t node in 'main_config' whose value is - * an iSCSI Name as defined in the RFC (3720) standard (eg, - * "iqn.1986..."), read its XML-encoded attributes from a - * flat-file and write an equivalent representation to SCF's - * data-store. - */ - while ((next = tgt_node_next(main_config, - XML_ELEMENT_TARG, next)) != NULL) { - if (tgt_find_value_str(next, XML_ELEMENT_INAME, - &target) == False) { - continue; - } - (void) snprintf(path, MAXPATHLEN, "%s/%s", - target_basedir, target); - if (mgmt_convert_param(path, next) - != True) { - ret = CONVERT_FAIL; - goto done; - } - free(target); - } - - ret = CONVERT_OK; - syslog(LOG_NOTICE, "Conversion succeeded"); - - (void) xmlTextReaderClose(r); - xmlFreeTextReader(r); - xmlCleanupParser(); - } else { - syslog(LOG_ERR, "Reading main config failed"); - ret = CONVERT_FAIL; - goto done; - } - -done: - if (xml_fd != -1) - (void) close(xml_fd); - mgmt_handle_fini(h); - return (ret); -} - -/* - * backup() moves configuration xml files into backup directory - * under base-directory. It is called once when converting legacy - * xml data into scf data. - * Param files will be renamed as params.<lun#>.<initiatorname> - */ -static void -backup(char *file, char *ext) -{ - char dest[MAXPATHLEN]; - char *bname; - - bname = basename(file); - if (ext) { - (void) snprintf(dest, sizeof (dest), "%s/backup/%s.%s", - target_basedir, bname, ext); - } else { - (void) snprintf(dest, sizeof (dest), "%s/backup/%s", - target_basedir, bname); - } - - if (fork() == 0) { - (void) execl("/bin/mv", "mv", file, dest, (char *)0); - exit(0); - } -} - -/* - * check_auth() checks if a given cred has - * the authorization to create/remove targets/initiators/tpgt - * cred is from the door call. - */ -Boolean_t -check_auth_addremove(ucred_t *cred) -{ - targ_scf_t *h = NULL; - Boolean_t ret = False; - int exit_code = 1; - uid_t uid; - gid_t gid; - pid_t pid; - const priv_set_t *eset; - - pid = fork(); - - switch (pid) { - case 0: - /* Child process to check authorization */ - uid = ucred_geteuid(cred); - if (seteuid(uid) != 0) { - syslog(LOG_ERR, "not priviliged\n"); - exit(-1); - } - - gid = ucred_getegid(cred); - if (setegid(gid) != 0) { - syslog(LOG_ERR, "not priviliged\n"); - exit(-1); - } - - eset = ucred_getprivset(cred, PRIV_EFFECTIVE); - (void) setppriv(PRIV_ON, PRIV_EFFECTIVE, eset); - - h = mgmt_handle_init(); - - if (h == NULL) { - exit(1); - } - if (mgmt_transaction_start(h, "dummy", "dummy") == True) { - (void) scf_pg_delete(h->t_pg); - (void) mgmt_transaction_end(h); - exit_code = 0; - } else { - exit_code = 1; - } - mgmt_handle_fini(h); - exit(exit_code); - break; - case -1: - /* Fail to fork */ - exit(SMF_EXIT_ERR_CONFIG); - default: - (void) wait(&exit_code); - exit_code = exit_code >> 8; - if (exit_code == 0) - ret = True; - else - ret = False; - break; - } - - return (ret); -} -/* - * check_auth_modify() checks if a given cred has - * the authorization to add/change/remove configuration values. - * cred is from the door call. - */ -Boolean_t -check_auth_modify(ucred_t *cred) -{ - targ_scf_t *h = NULL; - Boolean_t ret = False; - int exit_code = -1; - uid_t uid; - gid_t gid; - pid_t pid; - tgt_node_t *n = NULL; - scf_transaction_entry_t *ent = NULL; - const priv_set_t *eset; - - pid = fork(); - - switch (pid) { - case 0: - /* Child process to check authorization */ - uid = ucred_geteuid(cred); - if (seteuid(uid) != 0) { - syslog(LOG_ERR, "not priviliged\n"); - exit(-1); - } - - gid = ucred_getegid(cred); - if (setegid(gid) != 0) { - syslog(LOG_ERR, "not priviliged\n"); - exit(-1); - } - - eset = ucred_getprivset(cred, PRIV_EFFECTIVE); - (void) setppriv(PRIV_ON, PRIV_EFFECTIVE, eset); - - h = mgmt_handle_init(); - - if (h == NULL) { - exit(-1); - } - if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { - n = tgt_node_alloc("dummy", String, "dummy"); - new_property(h, n); - tgt_node_free(n); - if (mgmt_transaction_end(h) == True) { - exit_code = 0; - } else { - exit_code = -1; - } - } else { - exit_code = -1; - } - if (exit_code != 0) { - mgmt_handle_fini(h); - exit(exit_code); - } - if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { - ent = scf_entry_create(h->t_handle); - if (ent) { - (void) scf_transaction_property_delete( - h->t_trans, ent, "dummy"); - } - } - (void) mgmt_transaction_end(h); - - mgmt_handle_fini(h); - exit(exit_code); - break; - case -1: - /* Fail to fork */ - exit(SMF_EXIT_ERR_CONFIG); - default: - (void) wait(&exit_code); - exit_code = exit_code >> 8; - if (exit_code == 0) - ret = True; - else - ret = False; - break; - } - - return (ret); -} - -/* - * Following two functions replace ':' and '.' in target/initiator - * names into '__2' and '__1' when write to SMF, and do a reverse - * replacement when read from SMF. - * pgname_encode's buffers are allocated by caller. - * see CR 6626684 - */ -#define SMF_COLON "__2" -#define SMF_DOT "__1" - -static void -pgname_encode(char *instr, char *outstr, int max_len) -{ - int i = 0; - - assert(instr != NULL && outstr != NULL); - for (; *instr != '\0'; instr++) { - switch (*instr) { - case ':': - (void) strcpy(outstr + i, SMF_COLON); - i += 3; - break; - case '.': - (void) strcpy(outstr + i, SMF_DOT); - i += 3; - break; - default: - *(outstr + i) = *instr; - i ++; - break; - } - /* in case of next possible ':' or '.', we cease on len-3 */ - if (i >= max_len - 3) - break; - } - outstr[i] = '\0'; -} - -/* - * pgname_decode use original buffer, since it reduces string length - */ -static void -pgname_decode(char *instr) -{ - char *buf; - char *rec; - - assert(instr != NULL); - buf = strdup(instr); - - if (buf == NULL) - return; - - rec = buf; - for (; *buf != '\0'; buf++) { - if (*buf == '_') { - if (memcmp(buf, SMF_COLON, strlen(SMF_COLON)) == 0) { - *instr = ':'; - buf += 2; - } else if (memcmp(buf, SMF_DOT, strlen(SMF_DOT)) == 0) { - *instr = '.'; - buf += 2; - } else { - *instr = *buf; - } - } else { - *instr = *buf; - } - instr ++; - } - *instr = '\0'; - free(rec); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.h b/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.h deleted file mode 100644 index 4dc93fd8ef..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_scf.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 _MGMT_SCF_H -#define _MGMT_SCF_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef _cplusplus -extern "C" { -#endif - -#include <libscf.h> -#include <iscsitgt_impl.h> -#include <ucred.h> - -#define SA_TARGET_SVC_NAME "system/iscsitgt" -#define SA_TARGET_SVC_INSTANCE_FMRI "svc:/system/iscsitgt:default" - -#define ISCSI_READ_AUTHNAME "read_authorization" -#define ISCSI_MODIFY_AUTHNAME "modify_authorization" -#define ISCSI_VALUE_AUTHNAME "value_authorization" - -#define ISCSI_AUTH_READ "solaris.smf.read.iscsitgt" -#define ISCSI_AUTH_MANAGE "solaris.smf.manage.iscsitgt" -#define ISCSI_AUTH_MODIFY "solaris.smf.modify.iscsitgt" -#define ISCSI_AUTH_VALUE "solaris.smf.value.iscsitgt" - -typedef enum { - CONVERT_OK = 0, - CONVERT_INIT_NEW, - CONVERT_FAIL -} convert_ret_t; - -typedef struct { - scf_handle_t *t_handle; - scf_scope_t *t_scope; - scf_service_t *t_service; - scf_propertygroup_t *t_pg; - scf_instance_t *t_instance; - scf_transaction_t *t_trans; -} targ_scf_t; - -typedef struct secret_list { - char *name; - char *secret; - struct secret_list *next; -} secret_list_t; - -Boolean_t mgmt_scf_init(); -void mgmt_scf_fini(); - -targ_scf_t *mgmt_handle_init(void); -Boolean_t mgmt_transaction_start(targ_scf_t *h, char *pg, char *prop); -Boolean_t mgmt_transaction_end(targ_scf_t *h); -void mgmt_transaction_abort(targ_scf_t *h); - -Boolean_t mgmt_get_main_config(tgt_node_t **node); -Boolean_t mgmt_config_save2scf(); - -Boolean_t mgmt_param_save2scf(tgt_node_t *node, char *target_name, int lun); -Boolean_t mgmt_get_param(tgt_node_t **node, char *target_name, int lun); -Boolean_t mgmt_param_remove(char *target_name, int lun); -convert_ret_t mgmt_convert_conf(); - -Boolean_t check_auth_modify(ucred_t *cred); -Boolean_t check_auth_addremove(ucred_t *cred); - -int get_zfs_shareiscsi(char *, tgt_node_t **, uint64_t *, ucred_t *); -int put_zfs_shareiscsi(char *, tgt_node_t *); -#define ZFS_PROP_SIZE (2 * 1024) - - -#ifdef __cplusplus -} -#endif - -#endif /* _MGMT_SCF_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/port.h b/usr/src/cmd/iscsi/iscsitgtd/port.h deleted file mode 100644 index e1cc377fee..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/port.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef PORT_H -#define PORT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include "iscsi_conn.h" - -typedef struct port_args { - target_queue_t *port_mgmtq, /* management queue */ - *port_dataq; /* incoming data for thread */ - int port_num, /* port number to monitor */ - port_socket; -} port_args_t; - -void port_init(); -void *port_watcher(void *v); -void *port_management(void *v); -void port_conn_remove(iscsi_conn_t *c); - -extern iscsi_conn_t *conn_head; - -#endif /* PORT_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/queue.h b/usr/src/cmd/iscsi/iscsitgtd/queue.h deleted file mode 100644 index df5576a06e..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/queue.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * 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 _TARGET_QUEUE_H -#define _TARGET_QUEUE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <pthread.h> -#include <sys/time.h> -#include <stdarg.h> -#include <synch.h> -#include <door.h> - -#include <iscsitgt_impl.h> - -/* Connections */ -#define Q_CONN_ERRS 0x00000001 -#define Q_CONN_LOGIN 0x00000002 -#define Q_CONN_NONIO 0x00000004 -#define Q_CONN_IO 0x00000008 - -/* Sessions */ -#define Q_SESS_ERRS 0x00000010 -#define Q_SESS_LOGIN 0x00000020 -#define Q_SESS_NONIO 0x00000040 -#define Q_SESS_IO 0x00000080 - -/* SCSI Target Emulation */ -#define Q_STE_ERRS 0x00000100 -#define Q_STE_NONIO 0x00000200 -#define Q_STE_IO 0x00000400 - -/* General Errors */ -#define Q_GEN_ERRS 0x00001000 -#define Q_GEN_DETAILS 0x00002000 - -/* ISCSI Debugging */ -#define Q_ISNS_DBG 0x00004000 - -/* Persistent Reservations */ -#define Q_PR_ERRS 0x00010000 -#define Q_PR_NONIO 0x00020000 -#define Q_PR_IO 0x00040000 - -/* - * When used the queue request will be place at the head of the queue. - */ -#define Q_HIGH 0x80000000 - -extern int qlog_lvl; - -typedef enum { - /* - * []---------------------------------------------------------------- - * | Messages internal to the SAM-3 portion. When the transport calls - * | the SAM-3 interfaces messages are enqueued to the LU. The LU - * | thread then dequeues these messages and calls the appropriate - * | function for the emulator. - */ - - /* ---- from transport ---- */ - msg_cmd_send, - msg_cmd_data_out, - - /* ---- from emulation ---- */ - msg_cmd_data_in, - msg_cmd_data_rqst, - msg_cmd_cmplt, - - /* ---- Internal SAM-3 messages ---- */ - msg_lu_add, - msg_lu_remove, - msg_lu_online, - msg_lu_aio_done, - - /* - * | End of SAM-3 messages - * []---------------------------------------------------------------- - */ - - msg_reset_lu, - msg_reset_targ, - msg_targ_inventory_change, - msg_lu_capacity_change, - - /* - * The ConnectionReader will send packet ready messages when - * data is available. If the socket has an error or is closed - * a conn_lost message will be sent. Packet ready will have the - * number of bytes currently available on the connection. Don't - * free. - */ - msg_conn_lost, - msg_packet_ready, - - /* - * Shutdowns happen from the bottom up. The replies are in place - * so that threads can wait for the top end to disappear, at least - * they must no longer reference any common structures such as - * message queues. - */ - msg_drain_complete, - msg_shutdown, - msg_shutdown_rsp, - - /* - * Here's a special error condition for STE. When using mmap - * to access the backing store of a LUN which is larger than - * the underlying storage it's possible to run out of room - * on the device (no duh). When that happens the OS will send - * the daemon a SIGSBUS. The STE thread catches that signal, - * sends a UNIT ATTENTION to the other side, and closes down - * the STE thread in a special manner. The transport layer - * can then restart another STE thread with the same queues - * which mean outstanding I/O restarts. - */ - msg_ste_media_error, - - /* - * A NopIn request could be sent on the connection receive thread - * except for one little issue. Since both the receive and transmit - * threads could be issuing packets and data to the socket at the - * same time we must protect those writes so that all of the data - * for a single PDU (hdr, checksum, data, checksum) go out together. - * It's possible for the socket to receive so much incoming data - * that writes will be blocked until some of that data has been - * read. If the transmit grabs the lock, attempts to write, and is - * blocked we find a condition where the receiver is also blocked - * processing a nop command because it can't get the lock. So, instead - * we build up the packet and queue it. - * - * This will also occur with Task Management Requests. - */ - msg_send_pkt, - - /* - * During login when the TargetName name/value pair is processed - * the value will be sent to STE through the session layer. - * STE can use the information however it sees fit. - * The InitiatorName will also be sent which STE can use to - * validate login properties. - */ - msg_target_name, - msg_initiator_name, - msg_initiator_alias, - - /* - * Issued when causing full allocation of backing store. - * This is an internal message used by t10_sam.c - */ - msg_thick_provo, - - /* - * ---------------- Debug/Management type messages ---------------- - */ - /* - * When a thread shutdowns someone must call pthread_join else - * the thread will remain in a zombie state taking up some - * amount of memory. - */ - msg_pthread_join, - - /* - * Requests from and replys to the management host will be done using - * these messages. - */ - msg_mgmt_rqst, - msg_mgmt_rply, - - /* - * General debug messages. - */ - msg_log, - - /* - * Problem message by some of the auxiliary threads indication - * problems. - */ - msg_status, - - msg_wait_for_destroy - -} msg_type_t; - -typedef struct msg { - struct msg *msg_next, - *msg_prev; - struct msg *msg_all_next; - - msg_type_t msg_type; - void *msg_data; - - /* - * This can be used either to insert a message higher into the queue - * or as debug level flags. - */ - uint32_t msg_pri_level; -} msg_t; - -typedef struct target_queue { - msg_t *q_head, - *q_tail; - pthread_mutex_t q_mutex; - sema_t q_sema; - int q_num; -} target_queue_t; - -typedef enum mgmt_type { - mgmt_full_phase_statistics, - mgmt_discovery_statistics, - mgmt_lun_information, - mgmt_parse_xml, - mgmt_logout -} mgmt_type_t; - -typedef struct mgmt_request { - target_queue_t *m_q; - mgmt_type_t m_request; - time_t m_time; - char *m_targ_name; - ucred_t *m_cred; - - /* - * This mutex protects the m_buf pointer from multiple connections - * attempting to update the response at the same time. One management - * request structure is sent to possible multiple connections when - * gathering statistics. The connections/sessions will lock access - * to the buffer. - */ - pthread_mutex_t m_resp_mutex; - union { - char **m_resp; - tgt_node_t *m_node; - } m_u; -} mgmt_request_t; - -typedef struct name_request { - target_queue_t *nr_q; - char *nr_name; -} name_request_t; - -void queue_init(); -target_queue_t *queue_alloc(); -void queue_message_set(target_queue_t *, uint32_t lvl, msg_type_t, void *); -msg_t *queue_message_get(target_queue_t *); -msg_t *queue_message_try_get(target_queue_t *q); -void queue_message_free(msg_t *); -void queue_walker_free(target_queue_t *q, - Boolean_t (*func)(msg_t *, void *v), void *v1); -void queue_free(target_queue_t *, void (*free_func)(msg_t *)); -void queue_reset(target_queue_t *q); -void queue_prt(target_queue_t *q, int type, char *fmt, ...); -void queue_str(target_queue_t *, uint32_t lvl, msg_type_t, char *); -void queue_log(Boolean_t on_off); -void ste_queue_data_remove(msg_t *m); -void conn_queue_data_remove(msg_t *m); -void sess_queue_data_remove(msg_t *m); - -#ifdef __cplusplus -} -#endif - -#endif /* _TARGET_QUEUE_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/radius.c b/usr/src/cmd/iscsi/iscsitgtd/radius.c deleted file mode 100644 index a6432ae451..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/radius.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/random.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> -#include <stdlib.h> - -#include <netinet/in.h> -#include <sys/socket.h> - -#include <md5.h> -#include "target.h" -#include "radius.h" - -/* Forward declaration */ - -/* - * Encode a CHAP-Password attribute. This function basically prepends - * the identifier in front of chap_passwd and copy the results to - * *result. - */ -static -void -encode_chap_password(int identifier, - int chap_passwd_len, - uint8_t *chap_passwd, - uint8_t *result); - -int -snd_radius_request(int sd, - iscsi_ipaddr_t rsvr_ip_addr, - uint32_t rsvr_port, - radius_packet_data_t *req_data); - -int -rcv_radius_response(int sd, - uint8_t *shared_secret, - uint32_t shared_secret_len, - uint8_t *req_authenticator, - radius_packet_data_t *resp_data); - -/* - * Annotate the radius_attr_t objects with authentication data. - */ -static -void -set_radius_attrs(radius_packet_data_t *req, - char *target_chap_name, - unsigned char *target_response, - uint32_t responseLength, - uint8_t *challenge, -uint32_t challengeLength); - -/* - * See radius_auth.h. - */ -/* ARGSUSED */ -chap_validation_status_type -radius_chap_validate(char *target_chap_name, - char *initiator_chap_name, - uint8_t *challenge, - uint32_t challengeLength, - uint8_t *target_response, - uint32_t responseLength, - uint8_t identifier, - iscsi_ipaddr_t rad_svr_ip_addr, - uint32_t rad_svr_port, - uint8_t *rad_svr_shared_secret, - uint32_t rad_svr_shared_secret_len) -{ - chap_validation_status_type validation_status; - int rcv_status; - int sd; - int rc; - struct sockaddr_in sockaddr; - radius_packet_data_t req; - radius_packet_data_t resp; - MD5_CTX context; - uint8_t md5_digest[16]; /* MD5 digest length 16 */ - uint8_t random_number[16]; - int fd; - - if (rad_svr_shared_secret_len == 0) { - /* The secret must not be empty (section 3, RFC 2865) */ - return (CHAP_VALIDATION_BAD_RADIUS_SECRET); - } - - bzero(&req, sizeof (radius_packet_data_t)); - - req.identifier = identifier; - req.code = RAD_ACCESS_REQ; - set_radius_attrs(&req, - target_chap_name, - target_response, - responseLength, - challenge, - challengeLength); - - /* Prepare the request authenticator */ - MD5Init(&context); - bzero(&md5_digest, 16); - /* First, the shared secret */ - MD5Update(&context, rad_svr_shared_secret, rad_svr_shared_secret_len); - /* Then a unique number - use a random number */ - fd = open("/dev/random", O_RDONLY); - if (fd == -1) - return (CHAP_VALIDATION_INTERNAL_ERROR); - (void) read(fd, &random_number, sizeof (random_number)); - (void) close(fd); - MD5Update(&context, random_number, sizeof (random_number)); - MD5Final(md5_digest, &context); - bcopy(md5_digest, &req.authenticator, RAD_AUTHENTICATOR_LEN); - - /* Create UDP socket */ - sd = socket(AF_INET, SOCK_DGRAM, 0); - if (sd < 0) { - return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR); - } - sockaddr.sin_family = AF_INET; - sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); - sockaddr.sin_port = htons(0); - rc = bind(sd, (struct sockaddr *)&sockaddr, sizeof (sockaddr)); - if (rc < 0) { - return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR); - } - - /* Send the authentication access request to the RADIUS server */ - if (snd_radius_request(sd, - rad_svr_ip_addr, - rad_svr_port, - &req) == -1) { - (void) close(sd); - return (CHAP_VALIDATION_RADIUS_ACCESS_ERROR); - } - - bzero(&resp, sizeof (radius_packet_data_t)); - /* Analyze the response coming through from the same socket. */ - rcv_status = rcv_radius_response(sd, - rad_svr_shared_secret, - rad_svr_shared_secret_len, - req.authenticator, &resp); - if (rcv_status == RAD_RSP_RCVD_SUCCESS) { - if (resp.code == RAD_ACCESS_ACPT) { - validation_status = CHAP_VALIDATION_PASSED; - } else if (resp.code == RAD_ACCESS_REJ) { - validation_status = CHAP_VALIDATION_INVALID_RESPONSE; - } else { - validation_status = - CHAP_VALIDATION_UNKNOWN_RADIUS_CODE; - } - } else if (rcv_status == RAD_RSP_RCVD_AUTH_FAILED) { - validation_status = CHAP_VALIDATION_BAD_RADIUS_SECRET; - } else { - validation_status = CHAP_VALIDATION_RADIUS_ACCESS_ERROR; - } - - (void) close(sd); - return (validation_status); -} - -/* See forward declaration. */ -static void -set_radius_attrs(radius_packet_data_t *req, - char *target_chap_name, - unsigned char *target_response, - uint32_t responseLength, - uint8_t *challenge, - uint32_t challengeLength) -{ - req->attrs[0].attr_type_code = RAD_USER_NAME; - (void) strncpy((char *)req->attrs[0].attr_value, - (const char *)target_chap_name, - strlen(target_chap_name)); - req->attrs[0].attr_value_len = strlen(target_chap_name); - - req->attrs[1].attr_type_code = RAD_CHAP_PASSWORD; - bcopy(target_response, - (char *)req->attrs[1].attr_value, - min(responseLength, sizeof (req->attrs[1].attr_value))); - /* A target response is an MD5 hash thus its length has to be 16. */ - req->attrs[1].attr_value_len = responseLength; - - req->attrs[2].attr_type_code = RAD_CHAP_CHALLENGE; - bcopy(challenge, - (char *)req->attrs[2].attr_value, - min(challengeLength, sizeof (req->attrs[2].attr_value))); - req->attrs[2].attr_value_len = challengeLength; - - /* 3 attributes associated with each RADIUS packet. */ - req->num_of_attrs = 3; -} - -/* - * See radius_packet.h. - */ -int -snd_radius_request(int sd, - iscsi_ipaddr_t rsvr_ip_addr, - uint32_t rsvr_port, - radius_packet_data_t *req_data) -{ - int i; /* Loop counter. */ - int data_len; - int len; - ushort_t total_length; /* Has to be 2 octets in size */ - uint8_t *ptr; /* Pointer to RADIUS packet data */ - uint8_t *length_ptr; /* Points to the Length field of the */ - /* packet. */ - uint8_t *data; /* RADIUS data to be sent */ - radius_attr_t *req_attr; /* Request attributes */ - radius_packet_t *packet; /* Outbound RADIUS packet */ - union { - struct sockaddr_in s_in4; - struct sockaddr_in6 s_in6; - } sa_rsvr; /* Socket address of the server */ - - /* - * Create a RADIUS packet with minimal length for now. - */ - total_length = MIN_RAD_PACKET_LEN; - data = (uint8_t *)malloc(MAX_RAD_PACKET_LEN); - packet = (radius_packet_t *)data; - packet->code = req_data->code; - packet->identifier = req_data->identifier; - bcopy(req_data->authenticator, packet->authenticator, - RAD_AUTHENTICATOR_LEN); - ptr = packet->data; - - /* Loop over all attributes of the request. */ - for (i = 0; i < req_data->num_of_attrs; i++) { - if (total_length > MAX_RAD_PACKET_LEN) { - /* The packet has exceed its maximum size. */ - free(data); - return (-1); - } - - req_attr = &req_data->attrs[i]; - *ptr++ = (req_attr->attr_type_code & 0xFF); - length_ptr = ptr; - /* Length is 2 octets - RFC 2865 section 3 */ - *ptr++ = 2; - total_length += 2; - - /* If the attribute is CHAP-Password, encode it. */ - if (req_attr->attr_type_code == RAD_CHAP_PASSWORD) { - /* - * Identifier plus CHAP response. RFC 2865 - * section 5.3. - */ - uint8_t encoded_chap_passwd[RAD_CHAP_PASSWD_STR_LEN + - RAD_IDENTIFIER_LEN + - 1]; - encode_chap_password - (req_data->identifier, - req_attr->attr_value_len, - req_attr->attr_value, - encoded_chap_passwd); - - req_attr->attr_value_len = RAD_CHAP_PASSWD_STR_LEN + - RAD_IDENTIFIER_LEN; - - bcopy(encoded_chap_passwd, - req_attr->attr_value, - req_attr->attr_value_len); - } - - len = req_attr->attr_value_len; - *length_ptr += len; - - bcopy(req_attr->attr_value, ptr, req_attr->attr_value_len); - ptr += req_attr->attr_value_len; - - total_length += len; - } /* Done looping over all attributes */ - - data_len = total_length; - total_length = htons(total_length); - bcopy(&total_length, packet->length, sizeof (ushort_t)); - - /* - * Send the packet to the RADIUS server. - */ - bzero((char *)&sa_rsvr, sizeof (sa_rsvr)); - if (rsvr_ip_addr.i_insize == sizeof (in_addr_t)) { - int ret; - - /* IPv4 */ - sa_rsvr.s_in4.sin_family = AF_INET; - sa_rsvr.s_in4.sin_addr.s_addr = - rsvr_ip_addr.i_addr.in4.s_addr; - /* - * sin_port is of type u_short (or ushort_t - POSIX compliant). - */ - sa_rsvr.s_in4.sin_port = htons((ushort_t)rsvr_port); - - ret = sendto(sd, data, data_len, 0, - (struct sockaddr *)&sa_rsvr.s_in4, - sizeof (struct sockaddr_in)); - free(data); - return (ret); - } else if (rsvr_ip_addr.i_insize == sizeof (in6_addr_t)) { - /* IPv6 */ - sa_rsvr.s_in6.sin6_family = AF_INET6; - bcopy(sa_rsvr.s_in6.sin6_addr.s6_addr, - rsvr_ip_addr.i_addr.in6.s6_addr, 16); - /* - * sin6_port is of type in_port_t (i.e., uint16_t). - */ - sa_rsvr.s_in6.sin6_port = htons((in_port_t)rsvr_port); - - free(data); - /* No IPv6 support for now. */ - return (-1); - } else { - /* Invalid IP address for RADIUS server. */ - free(data); - return (-1); - } -} - -/* - * See radius_packet.h. - */ -int -rcv_radius_response(int sd, - uint8_t *shared_secret, - uint32_t shared_secret_len, - uint8_t *req_authenticator, - radius_packet_data_t *resp_data) -{ - int poll_cnt = 0; - int rcv_len = 0; - radius_packet_t *packet; - MD5_CTX context; - uint8_t *tmp_data; - uint8_t md5_digest[16]; /* MD5 Digest Length 16 */ - uint16_t declared_len = 0; - ushort_t len; - - fd_set fdset; - struct timeval timeout; - - tmp_data = (uint8_t *)malloc(MAX_RAD_PACKET_LEN); - - /* - * Poll and receive RADIUS packet. - */ - poll_cnt = 0; - do { - timeout.tv_sec = RAD_RCV_TIMEOUT; - timeout.tv_usec = 0; - - FD_ZERO(&fdset); - FD_SET(sd, &fdset); - - if (select(sd+1, &fdset, NULL, NULL, &timeout) < 0) { - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } - - if (FD_ISSET(sd, &fdset)) { - rcv_len = recv(sd, tmp_data, MAX_RAD_PACKET_LEN, 0); - break; - } else { - poll_cnt++; - } - - } while (poll_cnt < RAD_RETRY_MAX); - - if (poll_cnt >= RAD_RETRY_MAX) { - free(tmp_data); - return (RAD_RSP_RCVD_TIMEOUT); - } - - if (rcv_len < 0) { - /* Socket error. */ - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } - - packet = (radius_packet_t *)tmp_data; - bcopy(packet->length, &len, sizeof (ushort_t)); - declared_len = ntohs(len); - - /* - * Check if the received packet length is within allowable range. - * RFC 2865 section 3. - */ - if (rcv_len < MIN_RAD_PACKET_LEN) { - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } else if (rcv_len > MAX_RAD_PACKET_LEN) { - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } - - /* - * Check if the declared packet length is within allowable range. - * RFC 2865 section 3. - */ - if (declared_len < MIN_RAD_PACKET_LEN) { - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } else if (declared_len > MAX_RAD_PACKET_LEN) { - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } - - /* - * Discard packet with received length shorter than declared - * length. RFC 2865 section 3. - */ - if (rcv_len < declared_len) { - free(tmp_data); - return (RAD_RSP_RCVD_PROTOCOL_ERR); - } - - /* - * Authenticate the incoming packet, using the following algorithm - * (RFC 2865 section 3): - * - * MD5(Code+ID+Length+RequestAuth+Attributes+Secret) - * - * Code = RADIUS packet code - * ID = RADIUS packet identifier - * Length = Declared length of the packet - * RequestAuth = The request authenticator - * Attributes = The response attributes - * Secret = The shared secret - */ - MD5Init(&context); - bzero(&md5_digest, 16); - MD5Update(&context, &packet->code, 1); - MD5Update(&context, &packet->identifier, 1); - MD5Update(&context, packet->length, 2); - MD5Update(&context, req_authenticator, RAD_AUTHENTICATOR_LEN); - /* Include response attributes only if there is a payload */ - if (declared_len > RAD_PACKET_HDR_LEN) { - /* Response Attributes */ - MD5Update(&context, packet->data, - declared_len - RAD_PACKET_HDR_LEN); - } - MD5Update(&context, shared_secret, shared_secret_len); - MD5Final(md5_digest, &context); - - if (bcmp(md5_digest, packet->authenticator, RAD_AUTHENTICATOR_LEN) - != 0) { - free(tmp_data); - return (RAD_RSP_RCVD_AUTH_FAILED); - } - - /* - * If the received length is greater than the declared length, - * trust the declared length and shorten the packet (i.e., to - * treat the octets outside the range of the Length field as - * padding - RFC 2865 section 3). - */ - if (rcv_len > declared_len) { - /* Clear the padding data. */ - bzero(tmp_data + declared_len, rcv_len - declared_len); - rcv_len = declared_len; - } - - /* - * Annotate the RADIUS packet data with the data we received from - * the server. - */ - resp_data->code = packet->code; - resp_data->identifier = packet->identifier; - - free(tmp_data); - return (RAD_RSP_RCVD_SUCCESS); -} - -static -void -encode_chap_password(int identifier, - int chap_passwd_len, - uint8_t *chap_passwd, - uint8_t *result) -{ - result[0] = (uint8_t)identifier; - bcopy(chap_passwd, &result[1], chap_passwd_len); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/radius.h b/usr/src/cmd/iscsi/iscsitgtd/radius.h deleted file mode 100644 index fdb9684475..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/radius.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _RADIUS_H -#define _RADIUS_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <netinet/in.h> -#include <sys/int_types.h> - -/* Packet type. RFC 2865 section 4. */ -#define RAD_ACCESS_REQ 1 /* Authentication Request */ -#define RAD_ACCESS_ACPT 2 /* Authentication Accepted */ -#define RAD_ACCESS_REJ 3 /* Authentication Rejected */ - -/* RADIUS Attribute Types. RFC 2865 section 5. */ -#define RAD_USER_NAME 1 -#define RAD_CHAP_PASSWORD 3 -#define RAD_CHAP_CHALLENGE 60 - -/* RFC 2865 Section 3. The Identifier field is one octet. */ -#define RAD_IDENTIFIER_LEN 1 - -/* RFC 2865 Section 5.3. The String field is 16 octets. */ -#define RAD_CHAP_PASSWD_STR_LEN 16 - -/* RFC 2865 Section 3. Authenticator field is 16 octets. */ -#define RAD_AUTHENTICATOR_LEN 16 - -/* RFC 2865 Section 5: 1-253 octets */ -#define MAX_RAD_ATTR_VALUE_LEN 253 - -/* RFC 2865 Section 3. Minimum length 20 octets. */ -#define MIN_RAD_PACKET_LEN 20 - -/* RFC 2865 Section 3. Maximum length 4096 octets. */ -#define MAX_RAD_PACKET_LEN 4096 - -/* Maximum RADIUS shared secret length (in fact there is no defined limit) */ -#define MAX_RAD_SHARED_SECRET_LEN 128 - -/* RFC 2865 Section 3. Minimum RADIUS shared secret length */ -#define MIN_RAD_SHARED_SECRET_LEN 16 - -/* Raw RADIUS packet. RFC 2865 section 3. */ -typedef struct radius_packet { - uint8_t code; /* RADIUS code, section 3, RFC 2865 */ - uint8_t identifier; /* 1 octet in length. RFC 2865 section 3 */ - uint8_t length[2]; /* 2 octets, or sizeof (u_short) */ - uint8_t authenticator[RAD_AUTHENTICATOR_LEN]; - uint8_t data[1]; -} radius_packet_t; - -/* Length of a RADIUS packet minus the payload */ -#define RAD_PACKET_HDR_LEN 20 - - -typedef enum chap_validation_status_type { - CHAP_VALIDATION_PASSED, /* CHAP validation passed */ - CHAP_VALIDATION_INVALID_RESPONSE, /* Invalid CHAP response */ - CHAP_VALIDATION_DUP_SECRET, /* Same CHAP secret used */ - /* for authentication in the */ - /* other direction */ - CHAP_VALIDATION_UNKNOWN_AUTH_METHOD, /* Unknown authentication */ - /* method */ - CHAP_VALIDATION_INTERNAL_ERROR, /* MISC internal error */ - CHAP_VALIDATION_RADIUS_ACCESS_ERROR, /* Problem accessing RADIUS */ - CHAP_VALIDATION_BAD_RADIUS_SECRET, /* Invalid RADIUS shared */ - /* secret */ - CHAP_VALIDATION_UNKNOWN_RADIUS_CODE /* Irrelevant or unknown */ - /* RADIUS packet code */ - /* returned */ -} chap_validation_status_type; - -typedef enum authentication_method_type { - RADIUS_AUTHENTICATION, - DIRECT_AUTHENTICATION -} authentication_method_type; - -typedef struct _IPAddress { - union { - struct in_addr in4; - struct in6_addr in6; - } i_addr; - /* i_insize determines which is valid in the union above */ - int i_insize; -} iscsi_ipaddr_t; - -typedef struct radius_config { - iscsi_ipaddr_t rad_svr_addr; /* IPv6 enabled */ - uint32_t rad_svr_port; - uint8_t rad_svr_shared_secret[MAX_RAD_SHARED_SECRET_LEN]; - uint32_t rad_svr_shared_secret_len; -} RADIUS_CONFIG; - -/* A total of RAD_RCV_TIMEOUT * RAD_RETRY_MAX seconds timeout. */ -#define RAD_RCV_TIMEOUT 5 /* Timeout for receiving RADIUS packet in */ - /* sec. */ -#define RAD_RETRY_MAX 2 /* Max. # of times to retry receiving */ - /* packet. */ - -/* Describes a RADIUS attribute */ -typedef struct radius_attr { - int attr_type_code; /* RADIUS attribute type code, */ - /* e.g. RAD_USER_PASSWORD, etc. */ - int attr_value_len; - uint8_t attr_value[MAX_RAD_ATTR_VALUE_LEN]; -} radius_attr_t; - -/* Describes data fields of a RADIUS packet. */ -typedef struct radius_packet_data { - uint8_t code; /* RADIUS code, section 3, RFC 2865. */ - uint8_t identifier; - uint8_t authenticator[RAD_AUTHENTICATOR_LEN]; - int num_of_attrs; - radius_attr_t attrs[4]; /* For this implementation each */ - /* outbound RADIUS packet will only */ - /* have 3 attributes associated with */ - /* it thus the chosen size should be */ - /* good enough. */ -} radius_packet_data_t; - -/* - * Data in this structure is set by the user agent and consumed by - * the driver. - */ -#define MAX_RAD_SHARED_SECRET_LEN 128 -typedef struct radius_props { - uint32_t r_vers; - uint32_t r_oid; - union { - struct in_addr u_in4; - struct in6_addr u_in6; - } r_addr; - /* - * r_insize indicates which of the previous structs is valid. - */ - int r_insize; - - uint32_t r_port; - uint8_t r_shared_secret[MAX_RAD_SHARED_SECRET_LEN]; - boolean_t r_radius_access; - boolean_t r_radius_config_valid; - uint32_t r_shared_secret_len; -} iscsi_radius_props_t; - -/* - * Send a request to a RADIUS server. - * - * Returns > 0 on success, <= 0 on failure . - * - */ -int -snd_radius_request(int sd, - iscsi_ipaddr_t rsvr_ip_addr, - uint32_t rsvr_port, - radius_packet_data_t *packet_data); - -#define RAD_RSP_RCVD_SUCCESS 0 -#define RAD_RSP_RCVD_NO_DATA 1 -#define RAD_RSP_RCVD_TIMEOUT 2 -#define RAD_RSP_RCVD_PROTOCOL_ERR 3 -#define RAD_RSP_RCVD_AUTH_FAILED 4 -/* - * Receives a response from a RADIUS server. - * - * Return receive status. - */ -int -rcv_radius_response(int sd, - uint8_t *shared_secret, - uint32_t shared_secret_len, - uint8_t *req_authenticator, - radius_packet_data_t *resp_data); - -/* - * Function: radius_chap_validate - * - * Description: To validate a target response given the - * associated challenge via the specified - * RADIUS server. - * - * Arguments: - * target_chap_name - The CHAP name of the target being authenticated. - * initiator_chap_name - The CHAP name of the authenticating initiator. - * challenge - The CHAP challenge to which the target responded. - * target_response - The target's CHAP response to be validated. - * identifier - The identifier associated with the CHAP challenge. - * radius_server_ip_address - The IP address of the RADIUS server. - * radius_server_port - The port number of the RADIUS server. - * radius_shared_secret - The shared secret for accessing the RADIUS server. - * radius_shared_secret_len - The length of the shared secret. - * - * Return: See chap_validation_status_type. - */ -chap_validation_status_type -radius_chap_validate(char *target_chap_name, - char *initiator_chap_name, - uint8_t *challenge, - uint32_t challengeLength, - uint8_t *target_response, - uint32_t responseLength, - uint8_t identifier, - iscsi_ipaddr_t rad_svr_ip_addr, - uint32_t rad_svr_port, - uint8_t *rad_svr_shared_secret, - uint32_t rad_svr_shared_secret_len); - - - -#ifdef __cplusplus -} -#endif - -#endif /* _RADIUS_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/sparcv9/Makefile b/usr/src/cmd/iscsi/iscsitgtd/sparcv9/Makefile deleted file mode 100644 index 69b08dbca6..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/sparcv9/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -#ident "%Z%%M% %I% %E% SMI" -# -# cmd/iscsi/iscsitgt/sparcv9/Makefile - -include ../Makefile.com -include ../../../Makefile.cmd.64 - -install: all $(ROOTUSRSBINPROG64) diff --git a/usr/src/cmd/iscsi/iscsitgtd/svc-iscsitgt b/usr/src/cmd/iscsi/iscsitgtd/svc-iscsitgt deleted file mode 100644 index 21829d18e0..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/svc-iscsitgt +++ /dev/null @@ -1,64 +0,0 @@ -#!/sbin/sh -# -# 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. -# - -. /lib/svc/share/smf_include.sh - -case "$1" in -'start') - if smf_is_nonglobalzone; then - /usr/sbin/svcadm disable -t svc:/system/iscsitgt - echo "The iSCSI target is not supported in a local zone" - sleep 5 & - exit $SMF_EXIT_OK - fi - - /usr/sbin/iscsitgtd - - if [ $? -ne 0 ]; then - echo "Failed to start iSCSI daemon" - exit 1 - fi - - if [ -x /usr/sbin/zfs ]; then - /usr/sbin/zfs share -a iscsi - fi - - ;; - -'stop') - # Kill any processes in the service contract - smf_kill_contract $2 TERM - [ $? -ne 0 ] && exit 1 - ;; - -*) - echo "Usage: $0 { start | stop }" - exit 1 - ;; -esac - -exit $SMF_EXIT_OK diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10.h b/usr/src/cmd/iscsi/iscsitgtd/t10.h deleted file mode 100644 index ad0732a5a6..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10.h +++ /dev/null @@ -1,663 +0,0 @@ -/* - * 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 _T10_H -#define _T10_H - -/* - * This header file describes the service level between the transport - * layer and the emulation portion. These procedure calls can be thought - * of as part of the T10 SAM-3 specification. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Here are the header files which are required to define references found - * in this file. No other header files are to be included. - */ -#include <pthread.h> -#include <sys/avl.h> -#include <signal.h> -#include <sys/scsi/generic/sense.h> - -#include "queue.h" - -#ifdef lint -/* - * lints sees aio_return64, but can't find it in the aio structure. To keep - * lint happy this define is used. - */ -#define aio_return64 aio_return -#endif - -typedef void *transport_t; -typedef void *t10_targ_handle_t; - -typedef void *t10_lun_handle_t; - -typedef void *emul_handle_t; -typedef void *emul_cmd_t; - -typedef enum { - ClearSet, - ResetTarget, - ResetLun, - InventoryChange, - CapacityChange, - DeviceOnline, - DeviceOffline -} TaskOp_t; - -/* - * For an explanation of the t10_cmd_state_t and t10_cmd_event_t - * see t10_sam.c:t10_cmd_state_machine() - */ -typedef enum { - T10_Cmd_S1_Free = 1, - T10_Cmd_S2_In, - T10_Cmd_S3_Trans, - T10_Cmd_S4_AIO, - T10_Cmd_S5_Wait, - T10_Cmd_S6_Freeing_In, - T10_Cmd_S7_Freeing_AIO -} t10_cmd_state_t; - -typedef enum { - T10_Cmd_T1 = 1, - T10_Cmd_T2, - T10_Cmd_T3, - T10_Cmd_T4, - T10_Cmd_T5, - T10_Cmd_T6, /* cancel */ - T10_Cmd_T7, - T10_Cmd_T8 /* shutdown */ -} t10_cmd_event_t; - -typedef enum { - lu_online, - lu_offline, - lu_errored -} t10_lu_state_t; - -/* - * The t10_cmd_t structure bridges the gap between the transport and - * emulation services. At certain times either the transport or emulation - * service needs to access the data stored within this structure. - * For now we'll just use macros which hide the reference, but in the - * future when the transport and emulation services are loadable modules - * these macros will become functions so that the structure can change - * inside of the T10 space and not cause compatibility issues. - */ -#define T10_MAX_OUT(cmd) (cmd->c_lu->l_targ->s_maxout) -#define T10_MMAP_AREA(cmd) (cmd->c_lu->l_common->l_mmap) -#define T10_PARAMS_AREA(cmd) trans_params_area(cmd) -#define T10_TRANS_ID(cmd) (cmd->c_trans_id) -#define T10_DATA(cmd) (cmd->c_data) -#define T10_DATA_LEN(cmd) (cmd->c_data_len) -#define T10_DATA_OFFSET(cmd) (cmd->c_offset) -#define T10_CMD_LAST(cmd) (cmd->c_last) -#define T10_CMD_STATUS(cmd) (cmd->c_cmd_status) -#define T10_CMD_RESID(cmd) (cmd->c_resid) -#define T10_SENSE_LEN(cmd) (cmd->c_cmd_sense_len) -#define T10_SENSE_DATA(cmd) (cmd->c_cmd_sense) -#define T10_PGR_TNAME(cmd) (cmd->c_lu->l_targ->s_targ_base) -#define T10_PGR_INAME(cmd) (cmd->c_lu->l_targ->s_i_name) - -#define T10_DEFAULT_TPG 1 - -/* - * []------------------------------------------------------------------[] - * | SAM-3 revision 14, section 4.9 -- Logical Unit Numbers | - * | The specification allows for 64-bit LUNs, but at this point | - * | most OSes don't support that many. Section 4.9.7, table 9 gives | - * | the Flat Space Addressing Method which allows for 16,383 LUNs. | - * | This will be the imposed maximum even though the code can support | - * | more. Raise this number if needed. | - * []------------------------------------------------------------------[] - */ -#define T10_MAX_LUNS 16383 - -/* - * SPC-3 Revision 21c, Section 6.4.2 Table 85 - * Version Descriptor Values - */ -#define T10_TRANS_ISCSI 0x960 /* iSCSI (no version claimed) */ -#define T10_TRANS_FC 0x8c0 /* FCP (no version claimed) */ - -typedef struct t10_aio { - /* - * This must be the first member of the structure. aioread/aiowrite - * take as one of the arguments an pointer to a aio_result_t - * structure. When the operation is complete the aio_return and - * aio_errno of that structure are updated. When aiowait() is - * called the address of that aio_result_t is returned. By having - * this structure at the beginning we can pass in the data_ptr - * structure address. The ste_aio_process thread will get everything - * it needs from the aiowait to send a message to the correct - * STE thread. Clear as mud? - */ - aio_result_t a_aio; - - void (*a_aio_cmplt)(emul_cmd_t id); - emul_cmd_t a_id; - struct t10_cmd *a_cmd; -} t10_aio_t; - -/* - * Bidirectional structure used to track requests from the transport - * and send reponse data from the emulation. - * - * The glue logic for t10_send_cmd will allocate this structure, fill in - * in with the provided data and put it on the LUN queue. The LUN thread - * will dequeue this request and call the appropriate LUN command interpreter. - */ -typedef struct t10_cmd { - /* - * Transport specific tracking value. If this value is non-zero it - * means this command was part of a previous command that wasn't - * completed. Currently this is only used for DATA_OUT (SCSI write op) - * commands. - */ - transport_t c_trans_id; - - t10_cmd_state_t c_state; - - /* - * Emulation specific tracking value. - */ - emul_cmd_t c_emul_id; - - /* - * Per I_T_L structure used to determine which command - * interpreter to call and which transport queue to send the response. - */ - struct t10_lu_impl *c_lu; - - /* - * Pointer to command buffer. No interpretation of data is - * done by the glue logic. Interpretation is done by the LUN - * emulation code. - */ - uint8_t *c_cdb; - size_t c_cdb_len; - - /* - * Optional offset into the command. If more than one response - * is required this value indicates where the data belongs. - */ - off_t c_offset; - - /* - * Data for transfer. - */ - char *c_data; - size_t c_data_len; - size_t c_resid; - - /* - * Indicates if this response is the last to be sent - * and will be followed closely by a complete message. Enables - * transports to phase collapse the final READ data PDU with - * completion PDU if possible. - */ - Boolean_t c_last; - - /* - * When the transport is finished sending the data it will - * call t10_cmd_destroy() which will cause the SAM-3 layer to - * call the emulation function stored here with this command - * pointer. The emulation code is responsible for freeing any - * memory it allocated. - */ - void (*c_emul_complete)(emul_handle_t id); - - /* - * During transitions from T10 layer to transport one of three - * messages are sent. The state machine needs access to these - * values to pass things along so we keep it here. - */ - msg_type_t c_msg; - - /* - * SCSI sense information. - */ - int c_cmd_status; - char *c_cmd_sense; - size_t c_cmd_sense_len; - - /* - * List of active commands at the ITL level. - */ - avl_tree_t c_cmd_avl; - - struct t10_cmd *c_cmd_next; -} t10_cmd_t; - -/* - * Each LU has a structure which contains common data for all I_T's who - * access this LU. - */ -typedef struct t10_lu_common { - /* - * Logic Unit Number - */ - int l_num; - - /* - * state of device - */ - t10_lu_state_t l_state; - - /* - * Internal ID which will be unique for all LUs. This will be - * used for log messages to help tracking details. - */ - int l_internal_num; - - /* - * Thread ID which is running this logical unit. This is currently - * used for only one purpose which is to locate this structure - * in case of a SIGBUS. It's possible for the underlying file system - * to run out of space for an mmap'd LU. The only means of notification - * the OS has is to send a SIGBUS. The thread only receives the memory - * address, so we look for our thread ID amongst all of the LU - * available. - */ - pthread_t l_thr_id; - - /* - * If we receive a SIGBUS the initiator needs to be notified that - * something bad has occurred. This means we need to know which - * command was being emulated so that we can find the appropriate - * transport. - * Special handling needs to be done if the thread is initializing - * the LU so we need a flag to indicate that fact. - */ - t10_cmd_t *l_curr; - Boolean_t l_curr_provo; - - /* - * The implementation uses a 16 byte EUI value for the GUID. - * Not only is this value used for SCSI INQUIRY data, but it - * is used to distinquish this common LUN from other LUNs in - * the AVL tree. - */ - uint8_t *l_guid; - size_t l_guid_len; - - /* - * Other common information which is needed for ever device - * type. - */ - int l_dtype; - char *l_pid, - *l_vid; - - /* - * Each dtype has different parameters that it uses. This - * is a place holder for storing a pointer to some structure which - * contains that information. - */ - void *l_dtype_params; - - /* - * Parameter information in XML format. - */ - tgt_node_t *l_root; - Boolean_t l_root_okay_to_free; - - /* - * File descriptor for the open file which is the backing store - * for this device. This can be a regular file or a character - * special device if we're acting as a bridge between transports. - */ - int l_fd; - - void *l_mmap; - off64_t l_size; - - Boolean_t l_fast_write_ack; - - /* - * AVL tree containing all I_T_L nexus' which are actively using - * this LUN. - */ - avl_tree_t l_all_open; - - /* - * Each I_T will place requests for command emulation on this - * queue. Common requests are msg_ste_cmd and msg_ste_shutdown - */ - target_queue_t *l_from_transports; - - /* - * Mutex used to lock access to the AVL tree. - */ - pthread_mutex_t l_common_mutex; - - /* - * When a target is looking to see if an existing LUN is opened - * a search of all LUNs needs to be done and will use this - * AVL node. This field is modified only by the AVL code. - */ - avl_node_t l_all_luns; -} t10_lu_common_t; - -/* - * Each I_T_L has a LU structure associated with it. - */ -typedef struct t10_lu_impl { - /* - * pointer to common area of LUN. - */ - t10_lu_common_t *l_common; - pthread_mutex_t l_mutex; - - /* - * Mutex to protect access to active commands - */ - pthread_mutex_t l_cmd_mutex; - pthread_cond_t l_cmd_cond; - Boolean_t l_wait_for_drain; - - avl_tree_t l_cmds; - - /* - * Queue for sending command results and R2T results back - * to the transport. - */ - target_queue_t *l_to_transport; - - /* - * Back pointer to target structure who created this LUN reference. - */ - struct t10_targ_impl *l_targ; - - struct scsi_cmd_table *l_cmd_table; - - /* - * Per LU methods for issuing commands and data to the - * DTYPE emulator. - */ - void (*l_cmd)(t10_cmd_t *cmd, uint8_t *cdb, - size_t cdb_len); - void (*l_data)(t10_cmd_t *cmd, emul_handle_t e, - size_t offset, char *data, size_t data_len); - - /* - * AVL node information for all other I_T nexus' who are referencing - * this LUN. This is used by the AVL code and *not* modified by - * this daemon directly. - */ - avl_node_t l_open_lu_node; - - /* - * AVL node information for all LUN's being access by this I_T nexus. - * This is used by the AVL code and *not* modified by this daemon - * directly. - */ - avl_node_t l_open_targ_node; - - /* - * Logical Unit Number. This value is used as the comparision value - * for the AVL search at the per target level. - */ - int l_targ_lun; - - Boolean_t l_dsense_enabled; - Boolean_t l_pgr_read; - - /* - * Statistics on a per ITL basis - */ - uint64_t l_cmds_read, - l_cmds_write, - l_sects_read, - l_sects_write; - - /* - * Each time a command is run the value of l_status is checked. - * If non-zero the command isn't executed and instead a transport - * complete message is sent with these values. This is commonly - * used to send UNIT ATTENTION for things like power on. - * -- Do we need some sort of stack to push and pop these values? - */ - int l_status, - l_asc, - l_ascq; -} t10_lu_impl_t; - -typedef struct t10_targ_impl { - char *s_i_name; - char *s_targ_base; - int s_targ_num; /* used in log messages */ - avl_tree_t s_open_lu; - pthread_mutex_t s_mutex; - - /* - * The transport layer will set the maximum output size - * it's able to deal with during a call to set_create_handle() - */ - size_t s_maxout; - - /* - * Target Port Set - */ - int s_tpgt; - - /* - * transport version number to use in standard inquiry data - */ - int s_trans_vers; - - /* - * Transport response queue. This queue will be stored in each - * lun that gets created. - */ - target_queue_t *s_to_transport; - - /* - * During a SCSI WRITE the emulation will call trans_rqst_datain. - * If the transport indicated data was available by using non-zero - * values for the optional data and length when t10_send_cmd was - * called this callback is used when the emulation requests data. - */ - void (*s_dataout_cb)(t10_cmd_t *, char *data, - size_t *data_len); - -} t10_targ_impl_t; - -typedef struct t10_shutdown { - t10_lu_impl_t *t_lu; - target_queue_t *t_q; -} t10_shutdown_t; - -typedef struct scsi_cmd_table { - void (*cmd_start)(struct t10_cmd *, uint8_t *, size_t); - void (*cmd_data)(struct t10_cmd *, emul_handle_t e, - size_t offset, char *data, size_t data_len); - void (*cmd_end)(emul_handle_t e); - char *cmd_name; -} scsi_cmd_table_t; - -typedef struct sam_device_table { - Boolean_t (*t_common_init)(t10_lu_common_t *); - void (*t_common_fini)(t10_lu_common_t *); - void (*t_per_init)(t10_lu_impl_t *); - void (*t_per_fini)(t10_lu_impl_t *); - void (*t_task_mgmt)(t10_lu_common_t *, TaskOp_t); - char *t_type_name; -} sam_device_table_t; - -typedef struct t10_conn_shutdown { - target_queue_t *t10_to_conn_q; - target_queue_t *conn_to_t10_q; -} t10_conn_shutdown_t; - -/* - * []---- - * | Interfaces - * []---- - */ - -extern target_queue_t *mgmtq; -void t10_init(target_queue_t *q); -void lu_buserr_handler(int sig, siginfo_t *sip, void *v); - -/* - * []------------------------------------------------------------------[] - * | Methods called by the transports | - * []------------------------------------------------------------------[] - */ -/* - * t10_handle_create -- create target handle to be used by transports - */ -t10_targ_handle_t -t10_handle_create(char *targ, char *init, int trans_vers, int tpg, int max_out, - target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *)); - -/* - * t10_handle_disable -- drains commands from emulation queues - */ -void -t10_handle_disable(t10_targ_handle_t t); - -/* - * t10_handle_destroy -- free resources used by handle - */ -int -t10_handle_destroy(t10_targ_handle_t t, Boolean_t wait); - -Boolean_t -t10_cmd_create(t10_targ_handle_t t, int lun_number, uint8_t *cdb, - size_t cdb_len, transport_t trans_id, t10_cmd_t **); - -/* - * t10_send_cmd -- send a command block to an target/LUN for emulation - */ -Boolean_t -t10_cmd_send(t10_targ_handle_t t, t10_cmd_t *cmd, - char *opt_data, size_t opt_data_len); - -Boolean_t -t10_cmd_data(t10_targ_handle_t t, t10_cmd_t *cmd, size_t offset, - char *data, size_t data_len); - -void -t10_cmd_done(t10_cmd_t *cmd); - -Boolean_t -t10_task_mgmt(t10_targ_handle_t t, TaskOp_t op, int opt_lun, void *tag); - -/* - * t10_cmd_shoot_event -- perform transition to the state of a T10 command - */ -void t10_cmd_shoot_event(t10_cmd_t *c, t10_cmd_event_t e); - -void t10_targ_stat(t10_targ_handle_t t, char **buf); - -/* - * t10_thick_provision -- management function used when creating a new lun - */ -Boolean_t t10_thick_provision(char *target, int lun, target_queue_t *q); - -/* - * []------------------------------------------------------------------[] - * | Methods called by the emulation routines | - * []------------------------------------------------------------------[] - */ - -t10_cmd_t *trans_cmd_dup(t10_cmd_t *cmd); - -/* - * trans_send_datain -- Emulation layer sending data to initiator - */ -Boolean_t trans_send_datain(t10_cmd_t *cmd, char *data, size_t data_len, - size_t offset, void (*callback)(emul_handle_t t), Boolean_t last, - emul_handle_t id); - -/* - * trans_rqst_dataout -- Emulation needs more data to complete request - */ -Boolean_t trans_rqst_dataout(t10_cmd_t *cmd, char *data, size_t data_len, - size_t offset, emul_cmd_t emul_id, void (*callback)(emul_handle_t e)); - -/* - * trans_send_complete -- Emulation has completed request w/ opt. sense data - */ -void trans_send_complete(t10_cmd_t *cmd, int t10_status); - -/* - * trans_aiowrite -- asynchronous write and kicks the aio wait thread - */ -void trans_aiowrite(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset, - t10_aio_t *taio); - -/* - * trans_aioread -- asynchronous read and kicks the aio wait thread - */ -void trans_aioread(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset, - t10_aio_t *taio); - -/* - * trans_params_area -- given a t10_cmd return the dtype params - */ -void *trans_params_area(t10_cmd_t *cmd); - -/* - * []------------------------------------------------------------------[] - * | Declaration of emulation entry points | - * []------------------------------------------------------------------[] - */ -Boolean_t sbc_common_init(t10_lu_common_t *lu); -void sbc_common_fini(t10_lu_common_t *lu); -void sbc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op); -void sbc_per_init(t10_lu_impl_t *itl); -void sbc_per_fini(t10_lu_impl_t *itl); -Boolean_t ssc_common_init(t10_lu_common_t *lu); -void ssc_common_fini(t10_lu_common_t *lu); -void ssc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op); -void ssc_per_init(t10_lu_impl_t *itl); -void ssc_per_fini(t10_lu_impl_t *itl); -Boolean_t raw_common_init(t10_lu_common_t *lu); -void raw_common_fini(t10_lu_common_t *lu); -void raw_per_init(t10_lu_impl_t *itl); -void raw_per_fini(t10_lu_impl_t *itl); -void raw_task_mgmt(t10_lu_common_t *lu, TaskOp_t op); -Boolean_t osd_common_init(t10_lu_common_t *lu); -void osd_common_fini(t10_lu_common_t *lu); -void osd_per_init(t10_lu_impl_t *itl); -void osd_per_fini(t10_lu_impl_t *itl); -void osd_task_mgmt(t10_lu_common_t *lu, TaskOp_t op); - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_osd.c b/usr/src/cmd/iscsi/iscsitgtd/t10_osd.c deleted file mode 100644 index 793175ed4f..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_osd.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * []------------------------------------------------------------------[] - * | Implementation of OSD emulation | - * | | - * | NOTE: At this point in time this file is nothing more than a | - * | place holder for the implementation. As the project evolves we'll | - * | add more and more functionality. | - * []------------------------------------------------------------------[] - */ -#include <sys/types.h> -#include <aio.h> -#include <sys/asynch.h> -#include <sys/mman.h> -#include <stddef.h> -#include <strings.h> -#include <unistd.h> -#include <assert.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/generic/mode.h> -#include <sys/scsi/generic/dad_mode.h> - -#include "t10.h" -#include "t10_spc.h" -#include "t10_osd.h" -#include "utility.h" - -/* - * Forward declarations - */ -static void osd_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -static void osd_data(t10_cmd_t *cmd, emul_handle_t e, size_t offset, - char *data, size_t data_len); -static scsi_cmd_table_t osd_table[]; -static void osd_list(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); - -/* - * []---- - * | osd_init_common -- Initialize LU data which is common to all I_T_Ls - * []---- - */ -/*ARGSUSED*/ -Boolean_t -osd_common_init(t10_lu_common_t *lu) -{ - osd_params_t *o; - char *str; - tgt_node_t *node = lu->l_root; - - if ((o = (osd_params_t *)calloc(1, sizeof (*o))) == NULL) - return (False); - - if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &str) == True) { - o->o_size = strtoll(str, NULL, 0); - free(str); - } else { - free(o); - return (False); - } - - lu->l_dtype_params = (void *)o; - return (True); -} - -/*ARGSUSED*/ -void -osd_common_fini(t10_lu_common_t *lu) -{ - free(lu->l_dtype_params); -} - -/* - * []---- - * | osd_init_per -- Initialize per I_T_L information - * []---- - */ -/*ARGSUSED*/ -void -osd_per_init(t10_lu_impl_t *itl) -{ - itl->l_cmd = osd_cmd; - itl->l_data = osd_data; - itl->l_cmd_table = osd_table; - - /* - * The first time an I_T nexus connects to a LU it is supposed - * to receive an unit attention upon the first command sent. - */ - itl->l_status = KEY_UNIT_ATTENTION; - itl->l_asc = SPC_ASC_PWR_ON; - itl->l_ascq = SPC_ASCQ_PWR_ON; -} - -/*ARGSUSED*/ -void -osd_per_fini(t10_lu_impl_t *itl) -{ -} - -/*ARGSUSED*/ -void -osd_task_mgmt(t10_lu_common_t *lu, TaskOp_t op) -{ -} - -/* - * []---- - * | osd_cmd -- start a SCSI command - * | - * | This routine is called from within the SAM-3 Task router. - * []---- - */ -static void -osd_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cmd_table_t *e; - - e = &cmd->c_lu->l_cmd_table[cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SBC%x LUN%d Cmd %s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name == NULL ? "(no name)" : e->cmd_name); -#endif - (*e->cmd_start)(cmd, cdb, cdb_len); -} - -/* - * []---- - * | osd_data -- Data phase for command. - * | - * | Normally this is only called for the WRITE command. Other commands - * | that have a data in phase will probably be short circuited when - * | we call trans_rqst_dataout() and the data is already available. - * | At least this is true for iSCSI. FC however will need a DataIn phase - * | for commands like MODE SELECT and PGROUT. - * []---- - */ -static void -osd_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - scsi_cmd_table_t *e; - - e = &cmd->c_lu->l_cmd_table[cmd->c_cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SBC%x LUN%d Data %s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name); -#endif - (*e->cmd_data)(cmd, id, offset, data, data_len); -} - -/* - * []------------------------------------------------------------------[] - * | SCSI Object-Based Storage Device Commands | - * | T10/1355-D | - * | The following functions implement the emulation of OSD type | - * | commands. | - * []------------------------------------------------------------------[] - */ -static void -osd_service_action(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - osd_generic_cdb_t *o; - uint16_t service_action; - - /* - * debug only -- no need to drop core if someone doesn't play right. - */ - assert(cdb_len == sizeof (*o)); - if (cdb_len != sizeof (*o)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, SPC_ASCQ_INVALID_CDB); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - o = (osd_generic_cdb_t *)cdb; - service_action = o->ocdb_basic.b_service_action[0] << 8 | - o->ocdb_basic.b_service_action[1]; - - queue_prt(mgmtq, Q_STE_NONIO, - "OSD%x LUN%d service=0x%x, options=0x%x, specific_opts=0x%x," - " fmt=0x%x", cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, service_action, o->ocdb_options, - o->ocdb_specific_opts, o->ocdb_fmt); - - switch (service_action) { - case OSD_APPEND: - case OSD_CREATE: - case OSD_CREATE_AND_WRITE: - case OSD_CREATE_COLLECTION: - case OSD_CREATE_PARTITION: - case OSD_FLUSH: - case OSD_FLUSH_COLLECTION: - case OSD_FLUSH_OSD: - case OSD_FLUSH_PARTITION: - case OSD_FORMAT_OSD: - case OSD_GET_ATTR: - case OSD_LIST: - osd_list(cmd, cdb, cdb_len); - break; - - case OSD_LIST_COLLECTION: - case OSD_PERFORM_SCSI: - case OSD_TASK_MGMT: - default: - spc_unsupported(cmd, cdb, cdb_len); - break; - } -} - -/* - * []---- - * | osd_list -- return a list of objects - * []---- - */ -static void -osd_list(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - osd_cmd_list_t *o = (osd_cmd_list_t *)cdb; - osd_obj_id_t part; - osd_list_param_t *data; - uint64_t len, alloc_len; - - part = (uint64_t)o->ocdb_partition_id[0] << 56 | - (uint64_t)o->ocdb_partition_id[1] << 48 | - (uint64_t)o->ocdb_partition_id[2] << 40 | - (uint64_t)o->ocdb_partition_id[3] << 32 | - (uint64_t)o->ocdb_partition_id[4] << 24 | - (uint64_t)o->ocdb_partition_id[5] << 16 | - (uint64_t)o->ocdb_partition_id[6] << 8 | - (uint64_t)o->ocdb_partition_id[7]; - len = (uint64_t)o->ocdb_length[0] << 56 | - (uint64_t)o->ocdb_length[1] << 48 | - (uint64_t)o->ocdb_length[2] << 40 | - (uint64_t)o->ocdb_length[3] << 32 | - (uint64_t)o->ocdb_length[4] << 24 | - (uint64_t)o->ocdb_length[5] << 16 | - (uint64_t)o->ocdb_length[6] << 8 | - (uint64_t)o->ocdb_length[7]; - - if (len == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - queue_prt(mgmtq, Q_STE_NONIO, "part=0x%llx, len=0x%llx", part, len); - alloc_len = MAX(sizeof (*data), len); - if ((data = calloc(1, alloc_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - data->op_length[7] = sizeof (*data) - 8; - if (part == OSD_PARTITION_ROOT) - data->op_root = 1; - - (void) trans_send_datain(cmd, (char *)data, sizeof (*data), 0, free, - True, (emul_handle_t)data); -} - -/* - * []------------------------------------------------------------------[] - * | Support related functions for OSD | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | Command table for OSD emulation. This is at the end of the file because - * | it's big and ugly. ;-) To make for fast translation to the appropriate - * | emulation routine we just have a big command table with all 256 possible - * | entries. Most will report STATUS_CHECK, unsupport operation. By doing - * | this we can avoid error checking for command range or the use of a switch - * | statement. - * []---- - */ -static scsi_cmd_table_t osd_table[] = { - /* 0x00 -- 0x0f */ - { spc_tur, NULL, NULL, "TEST_UNIT_READY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_request_sense, NULL, NULL, "REQUEST_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "READ" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "WRITE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x10 -- 0x1f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_inquiry, NULL, NULL, "INQUIRY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_mselect, spc_mselect_data, NULL, "MODE_SELECT" }, - { spc_unsupported, NULL, NULL, "RESERVE" }, - { spc_unsupported, NULL, NULL, "RELEASE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "MODE_SENSE" }, - { spc_unsupported, NULL, NULL, "START_STOP" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_send_diag, NULL, NULL, "SEND_DIAG" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x20 -- 0x2f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "READ_CAPACITY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "READ_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "WRITE_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x30 -- 0x3f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "SYNC_CACHE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x40 -- 0x4f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "LOG_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x50 -- 0x5f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "PERSISTENT_IN" }, - { spc_unsupported, NULL, NULL, "PERSISTENT_OUT" }, - - /* 0x60 -- 0x6f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x70 -- 0x7f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { osd_service_action, NULL, NULL, "SERVICE_ACTION" }, - - /* 0x80 -- 0x8f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "READ_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "WRITE_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x90 -- 0x9f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "SVC_ACTION_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xa0 - 0xaf */ - { spc_report_luns, NULL, NULL, "REPORT_LUNS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_report_tpgs, NULL, NULL, "REPORT_TPGS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xb0 -- 0xbf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xc0 -- 0xcf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xd0 -- 0xdf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xe0 -- 0xef */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xf0 -- 0xff */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, -}; diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_osd.h b/usr/src/cmd/iscsi/iscsitgtd/t10_osd.h deleted file mode 100644 index 3a6d4d64ef..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_osd.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _T10_OSD_H -#define _T10_OSD_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Defines and structures for Object-Base Storage Device emulation - */ - -/* - * OSD revision 10, section 4.6.2 - * Partition_ID and User_Object_ID value assignments - */ -#define OSD_PARTITION_ROOT 0x00LL -#define OSD_PARTITION_BASE 0x10000LL -#define OSD_USER_OBJ_ROOT 0x00LL -#define OSD_USER_OBJ_BASE 0x10000LL - -/* - * OSD revision 10, section 6.1 - * Commands for OSD type devices - */ -#define OSD_APPEND 0x8807 -#define OSD_CREATE 0x8802 -#define OSD_CREATE_AND_WRITE 0x8812 -#define OSD_CREATE_COLLECTION 0x8815 -#define OSD_CREATE_PARTITION 0x880b -#define OSD_FLUSH 0x8808 -#define OSD_FLUSH_COLLECTION 0x881a -#define OSD_FLUSH_OSD 0x881c -#define OSD_FLUSH_PARTITION 0x881b -#define OSD_FORMAT_OSD 0x8801 -#define OSD_GET_ATTR 0x880e -#define OSD_LIST 0x8803 -#define OSD_LIST_COLLECTION 0x8817 -#define OSD_PERFORM_SCSI 0x8f7e -#define OSD_TASK_MGMT 0x8f7f - -typedef uint64_t osd_obj_id_t; - -typedef struct osd_params { - uint64_t o_size; -} osd_params_t; - -/* - * OSD revision 10, section 5.1 - * OSD CDB Format -- basic OSD CDB - */ -typedef struct osd_cmd_basic { - uint8_t b_code, - b_control, - b_rsvd[5], - b_add_cdblen, - b_service_action[2]; -} osd_cmd_basic_t; - -/* - * OSD revision 10, section 5.2.1 - * OSD service action specific fields - * The specification doesn't repeat the fields found in the basic OSD CDB, - * but it's included here so that one structure contains everything. - */ -typedef struct osd_generic_cdb { - osd_cmd_basic_t ocdb_basic; - uint8_t ocdb_options; -#if defined(_BIT_FIELDS_LTOH) - uint8_t ocdb_specific_opts : 4, - ocdb_fmt : 2, - : 2; -#elif defined(_BIT_FIELDS_HTOL) - uint8_t : 2, - ocdb_fmt : 2, - ocdb_specific_opts : 4; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uint8_t ocdb_ts_control, - ocdb_rsvd1[3], - ocdb_partition_id[8], - ocdb_object_id[8], - ocdb_rsvd2[4], - ocdb_length[8], - ocdb_start_addr[8], - ocdb_attr_params[28], - ocdb_capability[80], - ocdb_security_params[40]; -} osd_generic_cdb_t; - -/* - * []------------------------------------------------------------------[] - * | OSD revision 10, section 6.13 -- LIST command | - * []------------------------------------------------------------------[] - */ -typedef struct osd_cmd_list { - osd_cmd_basic_t ocdb_basic; - uint8_t ocdb_rsvd1; -#if defined(_BIT_FIELDS_LTOH) - uint8_t ocdb_sort_order : 4, - ocdb_fmt : 2, - : 2; -#elif defined(_BIT_FIELDS_HTOL) - uint8_t : 2, - ocdb_fmt : 2, - ocdb_sort_order : 4; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uint8_t ocdb_ts_control, - ocdb_rsvd2[3], - ocdb_partition_id[8], - ocdb_rsvd3[8], - ocdb_list_id[4], - ocdb_length[8], - ocdb_object_id[8], - ocdb_attr_params[28], - ocdb_capability[80], - ocdb_security_params[40]; -} osd_cmd_list_t; - -/* ---- Table 66, LIST command parameter data ---- */ -typedef struct osd_list_param { - uint8_t op_length[8], - op_cont_obj_id[8], - op_list_id[4], - op_rsvd1[3]; -#if defined(_BIT_FIELDS_LTOH) - uint8_t op_root : 1, - op_lstchg : 1, - : 6; -#elif defined(_BIT_FIELDS_HTOL) - uint8_t : 6, - op_lstchg : 1, - op_root : 1; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - osd_obj_id_t op_list[1]; -} osd_list_param_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_OSD_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c b/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c deleted file mode 100644 index aa123b3cb8..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_raw_if.c +++ /dev/null @@ -1,1572 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * []------------------------------------------------------------------[] - * | Implementation of SBC-2 emulation | - * []------------------------------------------------------------------[] - */ -#include <sys/types.h> -#include <sys/asynch.h> -#include <sys/mman.h> -#include <stddef.h> -#include <strings.h> -#include <errno.h> -#include <unistd.h> -#include <sys/sysmacros.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/generic/mode.h> -#include <sys/scsi/generic/dad_mode.h> -#include <sys/scsi/impl/uscsi.h> - -#include "t10.h" -#include "t10_spc.h" -#include "utility.h" -#include "target.h" - -typedef struct raw_io { - t10_aio_t r_aio; - t10_cmd_t *r_cmd; - - uint8_t *r_cdb; - char *r_data; - size_t r_cdb_len, - r_data_len; - uint64_t r_offset, - r_lba; - size_t r_lba_cnt; - uint32_t r_status; -} raw_io_t; - -typedef struct raw_params { - uint64_t r_size; - int r_dtype; -} raw_params_t; - -typedef enum { RawDataToDevice, RawDataFromDevice, NoData } raw_direction_t; - -/* - * Forward declarations - */ -static scsi_cmd_table_t raw_table[]; -static void raw_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -static void raw_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, - char *data, size_t data_len); -static void raw_free_io(emul_handle_t id); -static void do_dataout(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len, - size_t opt_data_len); -static raw_io_t *do_datain(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len, - size_t data_len); -static int do_uscsi(t10_cmd_t *cmd, raw_io_t *io, raw_direction_t dir); -static void raw_read_cmplt(emul_handle_t id); -static void raw_write_cmplt(emul_handle_t e); - -/* - * []---- - * | raw_init_common -- Initialize LU data which is common to all I_T_Ls - * []---- - */ -Boolean_t -raw_common_init(t10_lu_common_t *lu) -{ - tgt_node_t *node = lu->l_root; - char *str; - raw_params_t *r; - - if ((r = (raw_params_t *)calloc(1, sizeof (*r))) == NULL) - return (False); - - if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &str) == True) { - r->r_size = strtoll(str, NULL, 0); - free(str); - } - lu->l_dtype_params = (void *)r; - return (True); -} - -void -raw_common_fini(t10_lu_common_t *lu) -{ - free(lu->l_dtype_params); -} - -/* - * []---- - * | raw_init_per -- Initialize per I_T_L information - * []---- - */ -void -raw_per_init(t10_lu_impl_t *itl) -{ - itl->l_cmd = raw_cmd; - itl->l_data = raw_data; - itl->l_cmd_table = raw_table; - - /* - * The first time an I_T nexus connects to a LU it is supposed - * to receive an unit attention upon the first command sent. - */ - itl->l_status = KEY_UNIT_ATTENTION; - itl->l_asc = 0x29; - itl->l_ascq = 0x01; -} - -/*ARGSUSED*/ -void -raw_per_fini(t10_lu_impl_t *itl) -{ -} - -/*ARGSUSED*/ -void -raw_task_mgmt(t10_lu_common_t *t, TaskOp_t op) -{ -} - -/* - * []---- - * | raw_cmd -- start a SCSI command - * | - * | This routine is called from within the SAM-3 Task router. - * []---- - */ -static void -raw_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cmd_table_t *e; -#ifdef FULL_DEBUG - char debug[80]; -#endif - - e = &cmd->c_lu->l_cmd_table[cdb[0]]; -#ifdef FULL_DEBUG - (void) snprintf(debug, sizeof (debug), "RAW%d Cmd %s\n", - cmd->c_lu->l_common->l_num, - e->cmd_name == NULL ? "(no name)" : e->cmd_name); - queue_str(mgmtq, Q_STE_IO, msg_log, debug); -#endif - (*e->cmd_start)(cmd, cdb, cdb_len); -} - -/* - * []---- - * | raw_data -- Data phase for command. - * | - * | Normally this is only called for the WRITE command. Other commands - * | that have a data in phase will probably be short circuited when - * | we call trans_rqst_dataout() and the data is already available. - * | At least this is true for iSCSI. FC however will need a DataIn phase - * | for commands like MODE SELECT and PGROUT. - * []---- - */ -static void -raw_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - scsi_cmd_table_t *e; -#ifdef FULL_DEBUG - char debug[80]; -#endif - - e = &cmd->c_lu->l_cmd_table[cmd->c_cdb[0]]; -#ifdef FULL_DEBUG - (void) snprintf(debug, sizeof (debug), "RAW%d Data %s\n", - cmd->c_lu->l_common->l_num, e->cmd_name); - queue_str(mgmtq, Q_STE_IO, msg_log, debug); -#endif - (*e->cmd_data)(cmd, id, offset, data, data_len); -} - -/* - * []------------------------------------------------------------------[] - * | The following methods handle special case requirements for the | - * | raw devices. | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | raw_read_tape -- handle SCSI reads from raw tape - * | - * | Need to handle reads from SCSI tape differently than LBA devices - * | for two reasons. - * | (1) The command block for tape reads is different than for - * | LBA devices. There's only a count field. - * | (2) Since tapes have records it's not possible to break up - * | the read operations in the same manner as LBA devices. - * | All of the data must first be read in from the device - * | and then broken up to fit the transport. This is a slower - * | approach, but nobody expects tapes to be quick. If speed - * | is needed a better approach would be to create a virtual - * | tape device and then stage out the data to the device later. - * []---- - */ -/*ARGSUSED*/ -static void -raw_read_tape(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - size_t req_len; - size_t xfer; - off_t offset = 0; - raw_io_t *io; - Boolean_t last; - t10_cmd_t *c; - - req_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; - if (cdb[1] & 0x1) - req_len *= 512; - - if (((io = do_datain(cmd, cdb, CDB_GROUP0, req_len)) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - while (offset < io->r_data_len) { - xfer = min(T10_MAX_OUT(cmd), io->r_data_len - offset); - last = ((offset + xfer) >= io->r_data_len) ? True : False; - if (last == True) - c = cmd; - else - c = trans_cmd_dup(cmd); - - if (trans_send_datain(c, io->r_data + offset, - xfer, offset, raw_free_io, last, io) == False) { - raw_free_io(io); - spc_sense_create(c, KEY_HARDWARE_ERROR, 0); - trans_send_complete(c, STATUS_CHECK); - return; - } - offset += xfer; - } -} - -/* - * []---- - * | raw_read -- emulation of SCSI READ command - * []---- - */ -/*ARGSUSED*/ -static void -raw_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /*LINTED*/ - union scsi_cdb *u = (union scsi_cdb *)cdb; - diskaddr_t addr; - off_t offset = 0; - uint32_t cnt; - uint32_t min; - raw_io_t *io; - uint64_t err_blkno; - int sense_len; - char debug[80]; - raw_params_t *r; - uchar_t addl_sense_len; - t10_cmd_t *c; - - if ((r = (raw_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - if (r->r_dtype == DTYPE_SEQUENTIAL) { - raw_read_tape(cmd, cdb, cdb_len); - return; - } - - switch (u->scc_cmd) { - case SCMD_READ: - /* - * SBC-2 Revision 16, section 5.5 - * Reserve bit checks - */ - if ((cdb[1] & 0xe0) || (cdb[5] & 0x38)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - addr = (diskaddr_t)(uint32_t)GETG0ADDR(u); - cnt = GETG0COUNT(u); - - /* - * SBC-2 Revision 16 - * Section: 5.5 READ(6) command - * A TRANSFER LENGTH field set to zero specifies - * that 256 logical blocks shall be read. - */ - if (cnt == 0) - cnt = 256; - break; - - case SCMD_READ_G1: - /* - * SBC-2 Revision 16, section 5.6 - * Reserve bit checks. - */ - if ((cdb[1] & 6) || cdb[6] || (cdb[9] & 0x38)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - addr = (diskaddr_t)(uint32_t)GETG1ADDR(u); - cnt = GETG1COUNT(u); - break; - - case SCMD_READ_G4: - /* - * SBC-2 Revision 16, section 5.8 - * Reserve bit checks - */ - if ((cdb[1] & 0x6) || (cdb[10] & 6) || cdb[14] || - (cdb[15] & 0x38)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - addr = GETG4LONGADDR(u); - cnt = GETG4COUNT(u); - break; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((addr + cnt) > r->r_size) { - - /* - * request exceed the capacity of disk - * set error block number to capacity + 1 - */ - err_blkno = r->r_size + 1; - - /* - * XXX: What's SBC-2 say about ASC/ASCQ here. Solaris - * doesn't care about these values when key is set - * to KEY_ILLEGAL_REQUEST. - */ - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - addl_sense_len = INFORMATION_SENSE_DESCR; - else - addl_sense_len = 0; - - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len); - spc_sense_info(cmd, err_blkno); - spc_sense_ascq(cmd, 0x21, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - - (void) snprintf(debug, sizeof (debug), - "RAW%d READ Illegal sector (0x%llx + 0x%x) > 0x%llx", - cmd->c_lu->l_common->l_num, addr, cnt, r->r_size); - queue_str(mgmtq, Q_STE_ERRS, msg_log, debug); - return; - } - - cmd->c_lu->l_cmds_read++; - cmd->c_lu->l_sects_read += cnt; - - if (cnt == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - do { - min = MIN((cnt * 512) - offset, T10_MAX_OUT(cmd)); - if ((offset + min) < (cnt * 512LL)) - c = trans_cmd_dup(cmd); - else - c = cmd; - if ((io = (raw_io_t *)calloc(1, sizeof (*io))) == NULL) { - - /* - * We're pretty much dead in the water. If we can't - * allocate memory. It's unlikey we'll be able to - * allocate a sense buffer or queue the command - * up to be sent back to the transport for delivery. - */ - spc_sense_create(c, KEY_HARDWARE_ERROR, 0); - trans_send_complete(c, STATUS_CHECK); - return; - } - - io->r_cmd = c; - io->r_lba = addr; - io->r_lba_cnt = cnt; - io->r_offset = offset; - io->r_data_len = min; - io->r_aio.a_aio_cmplt = raw_read_cmplt; - io->r_aio.a_id = io; - -#ifdef FULL_DEBUG - (void) snprintf(debug, sizeof (debug), - "RAW%d blk 0x%llx, cnt %d, offset 0x%llx, size %d", - c->c_lu->l_common->l_num, addr, cnt, io->r_offset, min); - queue_str(mgmtq, Q_STE_IO, msg_log, debug); -#endif - if ((io->r_data = (char *)malloc(min)) == NULL) { - err_blkno = addr + ((offset + 511) / 512); - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - sense_len = INFORMATION_SENSE_DESCR; - else - sense_len = 0; - spc_sense_create(c, KEY_HARDWARE_ERROR, - sense_len); - spc_sense_info(c, err_blkno); - trans_send_complete(c, STATUS_CHECK); - return; - } - trans_aioread(c, io->r_data, min, (addr * 512LL) + - (off_t)io->r_offset, &io->r_aio); - offset += min; - } while (offset < (off_t)(cnt * 512)); -} - -/* - * []---- - * | raw_read_cmplt -- Once we have the data, need to send it along. - * []---- - */ -static void -raw_read_cmplt(emul_handle_t id) -{ - raw_io_t *io = (raw_io_t *)id; - int sense_len; - uint64_t err_blkno; - t10_cmd_t *cmd = io->r_cmd; - Boolean_t last; - - if (io->r_aio.a_aio.aio_return != io->r_data_len) { - err_blkno = io->r_lba + ((io->r_offset + 511) / 512); - cmd->c_resid = (io->r_lba_cnt * 512) - io->r_offset; - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - sense_len = INFORMATION_SENSE_DESCR; - else - sense_len = 0; - spc_sense_create(cmd, KEY_HARDWARE_ERROR, sense_len); - spc_sense_info(cmd, err_blkno); - trans_send_complete(cmd, STATUS_CHECK); - raw_free_io(io); - return; - } - - last = ((io->r_offset + io->r_data_len) < (io->r_lba_cnt * 512LL)) ? - False : True; - if (trans_send_datain(cmd, io->r_data, io->r_data_len, - io->r_offset, raw_free_io, last, io) == False) { - raw_free_io(io); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -/*ARGSUSED*/ -static void -raw_write_tape(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - size_t request_len; - size_t xfer; - raw_io_t *io; - - request_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; - request_len *= (cdb[1] & 0x1) ? 512 : 1; - - if ((io = calloc(1, sizeof (*io))) == NULL) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if ((io->r_data = malloc(request_len)) == NULL) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } - io->r_data_len = request_len; - io->r_cmd = cmd; - - xfer = min(T10_MAX_OUT(cmd), request_len); - (void) trans_rqst_dataout(cmd, io->r_data, xfer, io->r_offset, io, - raw_free_io); -} - -/*ARGSUSED*/ -void -raw_write_tape_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - raw_io_t *io = (raw_io_t *)id; - size_t xfer; - - if ((io->r_offset + data_len) < io->r_data_len) { - io->r_offset += data_len; - xfer = min(T10_MAX_OUT(cmd), io->r_data_len - io->r_offset); - (void) trans_rqst_dataout(cmd, io->r_data + io->r_offset, xfer, - io->r_offset, io, raw_free_io); - return; - } else { - trans_send_complete(cmd, do_uscsi(cmd, io, RawDataToDevice)); - } -} - -/* - * []---- - * | raw_write -- implement a SCSI write command. - * []---- - */ -/*ARGSUSED*/ -static void -raw_write(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /*LINTED*/ - union scsi_cdb *cdbp = (union scsi_cdb *)cdb; - off_t addr; - uint64_t err_blkno; - uint32_t cnt; - uchar_t addl_sense_len; - char debug[80]; /* debug */ - raw_params_t *r; - raw_io_t *io; - size_t max_out; - - if ((r = (raw_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - if (r->r_dtype == DTYPE_SEQUENTIAL) { - raw_write_tape(cmd, cdb, cdb_len); - return; - } - - switch (cdb[0]) { - case SCMD_WRITE: - /* - * SBC-2 revision 16, section 5.24 - * Reserve bit checks. - */ - if ((cdb[1] & 0xe0) || (cdb[5] & 0x38)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (off_t)cdbp->g0_addr2 << 16 | - (off_t)cdbp->g0_addr1 << 8 | (off_t)cdbp->g0_addr0; - cnt = cdbp->g0_count0; - /* - * SBC-2 Revision 16/Section 5.24 WRITE(6) - * A TRANSFER LENGHT of 0 indicates that 256 logical blocks - * shall be written. - */ - if (cnt == 0) - cnt = 256; - break; - - case SCMD_WRITE_G1: - /* - * SBC-2 revision 16, section 5.25 - * Reserve bit checks. - */ - if ((cdb[1] & 0x6) || cdb[6] || (cdb[9] & 0x38)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (off_t)cdbp->g1_addr3 << 24 | - (off_t)cdbp->g1_addr2 << 16 | - (off_t)cdbp->g1_addr1 << 8 | - (off_t)cdbp->g1_addr0; - cnt = cdbp->g1_count1 << 8 | cdbp->g1_count0; - break; - - case SCMD_WRITE_G4: - /* - * SBC-2 revision 16, section 5.27 - * Reserve bit checks. - */ - if ((cdb[1] & 0x6) || cdb[14] || (cdb[15] & 0x38)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (off_t)(cdbp->g4_addr3 & 0xff) << 56 | - (off_t)(cdbp->g4_addr2 & 0xff) << 48 | - (off_t)(cdbp->g4_addr1 & 0xff) << 40 | - (off_t)(cdbp->g4_addr0 & 0xff) << 32 | - (off_t)(cdbp->g4_addtl_cdb_data3 & 0xff) << 24 | - (off_t)(cdbp->g4_addtl_cdb_data2 & 0xff) << 16 | - (off_t)(cdbp->g4_addtl_cdb_data1 & 0xff) << 8 | - (off_t)(cdbp->g4_addtl_cdb_data0 & 0xff); - cnt = cdbp->g4_count3 << 24 | cdbp->g4_count2 << 16 | - cdbp->g4_count1 << 8 | cdbp->g4_count0; - break; - - default: - queue_str(mgmtq, Q_STE_ERRS, msg_log, - "Unprocessed WRITE type"); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x24, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - - } - - if ((addr < 0) || ((addr + cnt) > r->r_size)) { - - /* - * request exceed the capacity of disk - * set error block number to capacity + 1 - */ - err_blkno = r->r_size + 1; - - /* - * XXX: What's SBC-2 say about ASC/ASCQ here. Solaris - * doesn't care about these values when key is set - * to KEY_ILLEGAL_REQUEST. - */ - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - addl_sense_len = INFORMATION_SENSE_DESCR; - else - addl_sense_len = 0; - - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len); - spc_sense_info(cmd, err_blkno); - spc_sense_ascq(cmd, 0x21, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - - (void) snprintf(debug, sizeof (debug), - "RAW%d WRITE Illegal sector (0x%llx + 0x%x) > 0x%llx", - cmd->c_lu->l_common->l_num, addr, cnt, r->r_size); - queue_str(mgmtq, Q_STE_ERRS, msg_log, debug); - return; - } - - if (cnt == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - io = (raw_io_t *)cmd->c_emul_id; - if (io == NULL) { - if ((io = (raw_io_t *)calloc(1, sizeof (*io))) == NULL) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - io->r_lba = addr; - io->r_lba_cnt = cnt; - io->r_cmd = cmd; - io->r_aio.a_aio_cmplt = raw_write_cmplt; - io->r_aio.a_id = io; - - /* - * Only update the statistics the first time through - * for this particular command. If the requested transfer - * is larger than the transport can handle this routine - * will be called many times. - */ - cmd->c_lu->l_cmds_write++; - cmd->c_lu->l_sects_write += cnt; - } - - /* - * If a transport sets the maximum output value to zero we'll - * just request the entire amount. Otherwise, transfer no more - * than the maximum output or the reminder, whichever is less. - */ - max_out = cmd->c_lu->l_targ->s_maxout; - io->r_data_len = max_out ? MIN(max_out, - (cnt * 512) - io->r_offset) : (cnt * 512); - -#ifdef FULL_DEBUG - (void) snprintf(debug, sizeof (debug), - "RAW%d blk 0x%llx, cnt %d, offset 0x%llx, size %d", - cmd->c_lu->l_common->l_num, addr, cnt, io->r_offset, - io->r_data_len); - queue_str(mgmtq, Q_STE_IO, msg_log, debug); -#endif - - if ((io->r_data = (char *)malloc(io->r_data_len)) == NULL) { - - /* - * NOTE: May need a different ASC code - */ - err_blkno = addr + ((io->r_offset + 511) / 512); - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - addl_sense_len = INFORMATION_SENSE_DESCR; - else - addl_sense_len = 0; - - spc_sense_create(cmd, KEY_HARDWARE_ERROR, addl_sense_len); - spc_sense_info(cmd, err_blkno); - trans_send_complete(cmd, STATUS_CHECK); - return; - - } - if (trans_rqst_dataout(cmd, io->r_data, io->r_data_len, io->r_offset, - io, raw_free_io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -/* - * []---- - * | raw_write_data -- store a chunk of data from the transport - * []---- - */ -/*ARGSUSED*/ -void -raw_write_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - raw_io_t *io = (raw_io_t *)id; - raw_params_t *r = T10_PARAMS_AREA(cmd); - - if (r == NULL) - return; - - if (r->r_dtype == DTYPE_SEQUENTIAL) { - raw_write_tape_data(cmd, id, offset, data, data_len); - return; - } - - trans_aiowrite(cmd, data, data_len, (io->r_lba * 512) + - (off_t)io->r_offset, &io->r_aio); -} - -/* - * []---- - * | raw_write_cmplt -- deal with end game of write - * | - * | See if all of the data for this write operation has been dealt - * | with. If so, send a final acknowledgement back to the transport. - * | If not, update the offset, calculate the next transfer size, and - * | start the process again. - * []--- - */ -static void -raw_write_cmplt(emul_handle_t e) -{ - raw_io_t *io = (raw_io_t *)e; - t10_cmd_t *cmd = io->r_cmd; - - if ((io->r_offset + io->r_data_len) < (io->r_lba_cnt * 512)) { - free(io->r_data); - - io->r_offset += io->r_data_len; - io->r_data_len = MIN(cmd->c_lu->l_targ->s_maxout, - (io->r_lba_cnt * 512) - io->r_offset); - raw_write(cmd, cmd->c_cdb, cmd->c_cdb_len); - return; - } - trans_send_complete(cmd, STATUS_GOOD); -} - -static void -raw_reserve(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP0, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_release(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP0, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_persist_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - uint32_t len; - - len = (cdb[7] << 8) | cdb[8]; - if ((io = do_datain(cmd, cdb, CDB_GROUP1, len)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } - } -} - -static void -raw_persist_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - size_t len; - - len = (cdb[5] << 24) | (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - do_dataout(cmd, cdb, cdb_len, len); -} - -/*ARGSUSED*/ -static void -raw_persist_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - raw_io_t *io = (raw_io_t *)id; - trans_send_complete(cmd, do_uscsi(cmd, io, RawDataToDevice)); -} - -static void -raw_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - int len; - - switch (cdb[0]) { - case SCMD_MODE_SENSE: - len = cdb[4]; - break; - - case SCMD_MODE_SENSE_G1: - len = (cdb[7] << 8) | cdb[8]; - break; - } - - if (((io = do_datain(cmd, cdb, CDB_GROUP0, len)) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -static void -raw_tur(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP0, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_request_sense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if (((io = do_datain(cmd, cdb, CDB_GROUP0, cdb[4])) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - } else { - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } - } -} - -static void -raw_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - uint32_t len; - struct scsi_inquiry inq; - raw_params_t *r; - - if ((r = (raw_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - len = (cdb[3] << 8) | cdb[4]; - if (((io = do_datain(cmd, cdb, CDB_GROUP0, len)) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((cdb[1] & 1) == 0) { - bcopy(io->r_data, &inq, sizeof (inq)); - r->r_dtype = inq.inq_dtype; - } - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -static void -raw_mselect(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - int len; - - switch (cdb[0]) { - case SCMD_MODE_SELECT: - len = cdb[4]; - cdb_len = CDB_GROUP0; - break; - - case SCMD_MODE_SELECT_G1: - len = (cdb[7] << 8) | cdb[8]; - cdb_len = CDB_GROUP1; - break; - } - do_dataout(cmd, cdb, cdb_len, len); -} - -/*ARGSUSED*/ -static void -raw_mselect_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - raw_io_t *io = (raw_io_t *)id; - trans_send_complete(cmd, do_uscsi(cmd, io, RawDataToDevice)); -} - -static void -raw_startstop(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP0, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_rewind(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP0, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_send_diag(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - int len; - - len = (cdb[3] << 8) | cdb[4]; - do_dataout(cmd, cdb, CDB_GROUP0, len); -} - -/*ARGSUSED*/ -static void -raw_send_diag_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, - char *data, size_t data_len) -{ - raw_io_t *io = (raw_io_t *)id; - trans_send_complete(cmd, do_uscsi(cmd, io, RawDataToDevice)); -} - -static void -raw_recap(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - struct scsi_capacity cap; - raw_io_t *io; - raw_params_t *r; - - if ((r = (raw_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - if (((io = do_datain(cmd, cdb, CDB_GROUP1, sizeof (cap))) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - bcopy(io->r_data, &cap, sizeof (cap)); - /* - * Currently there's a bug in ZFS which doesn't report a capacity - * for any of the volumes. This means that when using ZFS the - * administrator must supply the device size. - */ - if (cap.capacity != 0) - r->r_size = cap.capacity; - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -static void -raw_service_actiong4(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - uint32_t len; - struct scsi_capacity_16 cap16; - raw_params_t *r; - - if ((r = (raw_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - len = (cdb[10] << 24) | (cdb[11] << 16) | (cdb[12] << 8) | cdb[13]; - if (((io = do_datain(cmd, cdb, CDB_GROUP4, len)) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - bcopy(io->r_data, &cap16, sizeof (cap16)); - /* - * Currently there's a bug in ZFS which doesn't report a capacity - * for any of the volumes. This means that when using ZFS the - * administrator must supply the device size. - */ - if (cap16.sc_capacity != 0) - r->r_size = cap16.sc_capacity; - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -static void -raw_synccache(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP1, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_write_fm(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - if ((io = do_datain(cmd, cdb, CDB_GROUP0, 0)) == NULL) { - trans_send_complete(cmd, STATUS_CHECK); - } else { - trans_send_complete(cmd, io->r_status); - raw_free_io(io); - } -} - -static void -raw_report_tpgs(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - uint32_t len; - - len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - if (((io = do_datain(cmd, cdb, CDB_GROUP5, len)) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -static void -raw_read_limits(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - raw_io_t *io; - - /* - * spec defines this command to return 6 bytes of data - */ - if (((io = do_datain(cmd, cdb, CDB_GROUP0, 6)) == NULL) || - (io->r_status != STATUS_GOOD)) { - if (io != NULL) - raw_free_io(io); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (trans_send_datain(cmd, io->r_data, io->r_data_len, 0, - raw_free_io, True, io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -/* - * []------------------------------------------------------------------[] - * | Support related functions for raw devices | - * []------------------------------------------------------------------[] - */ - -static void -do_dataout(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len, size_t opt_data_len) -{ - char *opt_data = NULL; - raw_io_t *io; - - if ((io = calloc(1, sizeof (*io))) == NULL) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if ((opt_data_len != 0) && - ((opt_data = malloc(opt_data_len)) == NULL)) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - io->r_cdb = cdb; - io->r_cdb_len = cdb_len; - io->r_data = opt_data; - io->r_data_len = opt_data_len; - if (trans_rqst_dataout(cmd, opt_data, opt_data_len, 0, io, - raw_free_io) == False) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } -} - -static raw_io_t * -do_datain(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len, size_t data_len) -{ - raw_io_t *io; - - if ((io = calloc(1, sizeof (*io))) == NULL) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - return (NULL); - } - - io->r_cdb = cdb; - io->r_cdb_len = cdb_len; - io->r_data_len = data_len; - if ((data_len != 0) && ((io->r_data = malloc(data_len)) == NULL)) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - free(io); - return (NULL); - } - (void) do_uscsi(cmd, io, data_len == 0 ? NoData : RawDataFromDevice); - return (io); -} - -static int -do_uscsi(t10_cmd_t *cmd, raw_io_t *io, raw_direction_t dir) -{ - struct uscsi_cmd u; - uchar_t sense_buf[128]; - - bzero(&u, sizeof (u)); - u.uscsi_cdb = (caddr_t)io->r_cdb; - u.uscsi_cdblen = io->r_cdb_len; - u.uscsi_bufaddr = io->r_data; - u.uscsi_buflen = io->r_data_len; - u.uscsi_flags = ((dir == RawDataToDevice) ? USCSI_WRITE : - (dir == RawDataFromDevice) ? USCSI_READ : 0) | USCSI_RQENABLE; - u.uscsi_rqbuf = (char *)sense_buf; - u.uscsi_rqlen = sizeof (sense_buf); - - if ((ioctl(cmd->c_lu->l_common->l_fd, USCSICMD, &u) == 0) && - (u.uscsi_status == 0)) { - io->r_status = 0; - return (0); - } - queue_prt(mgmtq, Q_STE_ERRS, - "RAW%d LUN%d USCSICMD errno %d, cmd_status %d, rqstatus %d, " - "rqresid %d", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, errno, - u.uscsi_status, u.uscsi_rqstatus, u.uscsi_rqresid); - - if ((u.uscsi_rqlen - u.uscsi_rqresid) < - sizeof (struct scsi_extended_sense)) { - queue_prt(mgmtq, Q_STE_ERRS, - "RAW%x LUN%d -- No sense data, got=%d, needed=%d", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - u.uscsi_rqlen - u.uscsi_rqresid, - sizeof (struct scsi_extended_sense)); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - io->r_status = STATUS_CHECK; - return (STATUS_CHECK); - } else { - spc_sense_raw(cmd, sense_buf, u.uscsi_rqlen - u.uscsi_rqresid); - io->r_status = u.uscsi_status; - return (u.uscsi_status); - } -} - -static void -raw_free_io(emul_handle_t id) -{ - raw_io_t *io = (raw_io_t *)id; - - if (io->r_data_len) - free(io->r_data); - free(io); -} - -/* - * []---- - * | Command table for LBA emulation. This is at the end of the file because - * | it's big and ugly. ;-) To make for fast translation to the appropriate - * | emulation routine we just have a big command table with all 256 possible - * | entries. Most will report STATUS_CHECK, unsupport operation. By doing - * | this we can avoid error checking for command range. - * []---- - */ -static scsi_cmd_table_t raw_table[] = { - /* 0x00 -- 0x0f */ - { raw_tur, NULL, NULL, "TEST_UNIT_READY" }, - { raw_rewind, NULL, NULL, "REWIND" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_request_sense, NULL, NULL, "REQUEST_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_read_limits, NULL, NULL, "READ_LIMITS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_read, NULL, NULL, "READ" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_write, raw_write_data, NULL, "WRITE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x10 -- 0x1f */ - { raw_write_fm, NULL, NULL, "WRITE_FILEMARKS" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_inquiry, NULL, NULL, "INQUIRY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_mselect, raw_mselect_data, NULL, "MODE_SELECT" }, - { raw_reserve, NULL, NULL, "RESERVE" }, - { raw_release, NULL, NULL, "RELEASE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_msense, NULL, NULL, "MODE_SENSE" }, - { raw_startstop, NULL, NULL, "START_STOP" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_send_diag, raw_send_diag_data, NULL, "SEND_DIAG" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x20 -- 0x2f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_recap, NULL, NULL, "READ_CAPACITY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_read, NULL, NULL, "READ_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_write, raw_write_data, NULL, "WRITE_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x30 -- 0x3f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_synccache, NULL, NULL, "SYNC_CACHE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x40 -- 0x4f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x50 -- 0x5f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_mselect, raw_mselect_data, NULL, "MODE_SELECT" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_msense, NULL, NULL, "MODE_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_persist_in, NULL, NULL, "PERSISTENT_RESERVE_IN" }, - { raw_persist_out, raw_persist_data, NULL, "PERSISTENT_RESERVE_OUT" }, - - /* 0x60 -- 0x6f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x70 -- 0x7f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x80 -- 0x8f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_read, NULL, NULL, "READ_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_write, raw_write_data, NULL, "WRITE_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x90 -- 0x9f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_service_actiong4, NULL, NULL, "SVC_ACTION_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xa0 - 0xaf */ - { spc_report_luns, NULL, NULL, "REPORT_LUNS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { raw_report_tpgs, NULL, NULL, "REPORT_TPGS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xb0 -- 0xbf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xc0 -- 0xcf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xd0 -- 0xdf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xe0 -- 0xef */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xf0 -- 0xff */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, -}; diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c b/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c deleted file mode 100644 index a72fbaa946..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_sam.c +++ /dev/null @@ -1,2790 +0,0 @@ -/* - * 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. - */ - -#include <aio.h> -#include <sys/aio.h> -#include <sys/asynch.h> -#include <stdio.h> -#include <stddef.h> -#include <strings.h> -#include <pthread.h> -#include <sys/types.h> -#include <sys/statvfs.h> -#include <sys/avl.h> -#include <sys/param.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <assert.h> -#include <errno.h> -#include <unistd.h> -#include <signal.h> -#include <sys/ucontext.h> -#include <assert.h> -#include <umem.h> -#include <time.h> -#include <syslog.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> - -#include "target.h" -#include "queue.h" -#include "t10.h" -#include "t10_spc.h" -#include "utility.h" -#include "mgmt_scf.h" - -/* - * []------------------------------------------------------------------[] - * | This file contains methods which isolate a transport from device | - * | emulation. The first part of the file contains method which are | - * | called by the transport to start commands or deliver data. The | - * | transport does not know anything about what emulation is being | - * | done. The emulation layer receieves cdb's and nows nothing about | - * | the transport. This is how it should be. There are a few special | - * | cases to deal with transports which have a notion of immediate | - * | data, but we're isolating that from the emulation layer. | - * []------------------------------------------------------------------[] - */ - -#define MAX_AIO_CNT 256 - -/* - * Forward declarations - */ -static Boolean_t t10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *); -static void *lu_runner(void *v); -static Boolean_t t10_lu_initialize(t10_lu_common_t *lu, char *basedir); -static void *t10_aio_done(void *v); -static Boolean_t lu_remove_cmds(msg_t *m, void *v); -static void cmd_common_free(t10_cmd_t *cmd); -static Boolean_t load_params(t10_lu_common_t *lu, char *basedir); -static Boolean_t fallocate(int fd, off64_t len); -static t10_cmd_state_t t10_cmd_state_machine(t10_cmd_t *c, t10_cmd_event_t e); -static void clear_transport(transport_t t, t10_cmd_t *t10c); - -#ifdef FULL_DEBUG -static char *state_to_str(t10_cmd_state_t s); -#endif -static char *event_to_str(t10_cmd_event_t e); -/* ---- These are AVL comparison routines ---- */ -static int find_lu_by_num(const void *v1, const void *v2); -static int find_lu_by_guid(const void *v1, const void *v2); -static int find_lu_by_targ(const void *v1, const void *v2); -static int find_cmd_by_addr(const void *v1, const void *v2); -static sam_device_table_t sam_emul_table[]; - -/* - * Local variables - */ -static avl_tree_t lu_list; -static pthread_mutex_t lu_list_mutex; -static int lu_id; -target_queue_t *mgmtq; -static pthread_mutex_t t10_mutex; -static int t10_num; -static sema_t t10_sema; -static sema_t t10_aio_sema; - -/* - * Constants - */ -static const timespec_t usec = {0, 1000}; - -/* - * []---- - * | t10_init -- called once at the beginning of time to initialize globals - * []---- - */ -void -t10_init(target_queue_t *q) -{ - pthread_t junk; - - mgmtq = q; - (void) pthread_mutex_init(&lu_list_mutex, NULL); - (void) pthread_mutex_init(&t10_mutex, NULL); - (void) sema_init(&t10_sema, 0, USYNC_THREAD, NULL); - (void) sema_init(&t10_aio_sema, MAX_AIO_CNT, USYNC_THREAD, NULL); - avl_create(&lu_list, find_lu_by_guid, sizeof (t10_lu_common_t), - offsetof(t10_lu_common_t, l_all_luns)); - (void) pthread_create(&junk, NULL, t10_aio_done, NULL); -} - -/*ARGSUSED*/ -static void * -t10_aio_done(void *v) -{ - aio_result_t *result; - t10_aio_t *a; - t10_lu_impl_t *lu; - - do { - if (sema_wait(&t10_sema) != 0) { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM- sema_wait returned error\n"); - continue; - } - - if ((result = aiowait(NULL)) == (aio_result_t *)-1) { - if (errno == EINVAL) { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM- aiowait returned EINVAL\n"); - continue; - } else - break; - } else { - a = (t10_aio_t *)result; - (void) sema_post(&t10_aio_sema); - } - if ((a != NULL) && (a->a_aio_cmplt != NULL)) { - lu = a->a_cmd->c_lu; - (void) pthread_mutex_lock(&lu->l_cmd_mutex); - if (t10_cmd_state_machine(a->a_cmd, T10_Cmd_T4) != - T10_Cmd_S1_Free) { - (void) pthread_mutex_unlock(&lu->l_cmd_mutex); - (*a->a_aio_cmplt)(a->a_id); - } else - (void) pthread_mutex_unlock(&lu->l_cmd_mutex); - } else { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM aiowait returned results, but is NULL\n"); - } - /*CONSTANTCONDITION*/ - } while (1); - - return (NULL); -} - -/* - * []------------------------------------------------------------------[] - * | Methods called by transports to interface with SAM-3 | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | t10_handle_create -- Create the I_T nexus - * | - * | NOTES: - * | max_out can be set to 0 if the transport wishes to wait for all of - * | the data before receiving a DATAOUT message. Fibre Channel will most - * | likely set this to 0, whereas iSCSI will set max_out to the value - * | of MaxRecvDataSegment. - * | (*datain_cb)() is called, on the LU thread, when the emulation - * | module needs data *and* t10_send_cmd was called with opt_data_len, but - * | no opt_data. - * []---- - */ -t10_targ_handle_t -t10_handle_create(char *targ, char *init, int trans_vers, int tpg, int max_out, - target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *)) -{ - t10_targ_impl_t *t = calloc(1, sizeof (t10_targ_impl_t)); - - if (t == NULL) - return (NULL); - - (void) pthread_mutex_lock(&t10_mutex); - t->s_targ_num = t10_num++; - (void) pthread_mutex_unlock(&t10_mutex); - t->s_targ_base = strdup(targ); - t->s_i_name = strdup(init); - t->s_trans_vers = trans_vers; - t->s_maxout = max_out; - t->s_to_transport = tq; - t->s_dataout_cb = datain_cb; - - /* - * Once we actually support two or more transports it would be - * possible for a collision between the underlying transports - * target port group values since one wouldn't necessarily know - * anything about the other. We'll use the upper bits of the - * target port group value to separate them. - * If we were to support many transports and with one then running - * out of bit space we'd need to change the allocation method. Since - * these values aren't stored anywhere and just used by initiators - * to determine relative path numbering there's no issue with changing - * this later if need be. - */ - switch (trans_vers) { - case T10_TRANS_ISCSI: - t->s_tpgt = 0x0000 | tpg; - break; - - case T10_TRANS_FC: - t->s_tpgt = 0x8000 | tpg; - break; - } - - avl_create(&t->s_open_lu, find_lu_by_num, sizeof (t10_lu_impl_t), - offsetof(t10_lu_impl_t, l_open_targ_node)); - - (void) pthread_mutex_init(&t->s_mutex, NULL); - return ((t10_targ_handle_t)t); -} - -void -t10_handle_disable(t10_targ_handle_t tp) -{ - t10_targ_impl_t *t = (t10_targ_impl_t *)tp; - t10_lu_impl_t *l; - t10_shutdown_t s; - int lu_per_targ = 0; - - (void) pthread_mutex_lock(&t->s_mutex); - if (avl_numnodes(&t->s_open_lu) != 0) { - s.t_q = queue_alloc(); - l = avl_first(&t->s_open_lu); - while (l != NULL) { - - s.t_lu = l; - queue_message_set(l->l_common->l_from_transports, 0, - msg_shutdown, (void *)&s); - queue_message_free(queue_message_get(s.t_q)); - lu_per_targ++; - l = AVL_NEXT(&t->s_open_lu, l); - } - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x Sent %d shutdown requests for %s\n", - t->s_targ_num, lu_per_targ, t->s_targ_base); - queue_free(s.t_q, NULL); - } - (void) pthread_mutex_unlock(&t->s_mutex); -} - -int -t10_handle_destroy(t10_targ_handle_t tp, Boolean_t wait) -{ - t10_targ_impl_t *t = (t10_targ_impl_t *)tp; - t10_lu_impl_t *l; - t10_cmd_t *c; - t10_cmd_t *c2free; - int fast_free = 0; - - (void) pthread_mutex_lock(&t->s_mutex); - if (avl_numnodes(&t->s_open_lu) != 0) { - while ((l = avl_first(&t->s_open_lu)) != NULL) { - - (void) pthread_mutex_lock(&l->l_cmd_mutex); - if (avl_numnodes(&l->l_cmds) != 0) { - c = avl_first(&l->l_cmds); - while (c != NULL) { - c2free = c; - c = AVL_NEXT(&l->l_cmds, c); - /* - * Remove those commands which - * are waiting for a response from - * the initiator or have already - * been canceled by the transport. - * The initiator response won't - * arrive since the connection - * is shutting down. If the - * backing store is closed, then - * all the aio requests are - * canceled by libaio, we can - * free the t10_cmd in S4 or - * S7 state. - * - * Other commands will be freed as - * they are processed by the - * transport layer or AIO. - */ - if ((c2free->c_state == - T10_Cmd_S5_Wait) || - (c2free->c_state == - T10_Cmd_S6_Freeing_In)) { - t10_aio_t *a; - - a = (t10_aio_t *) - c2free->c_emul_id; - if (a != NULL) { - queue_prt(mgmtq, - Q_STE_NONIO, - "SAM%x ... " - "S5 or S6 Cmd %p, " - "errno/ret %d/%d\n", - t->s_targ_num, - c2free, - a->a_aio.aio_errno, - /*CSTYLED*/ - a->a_aio.aio_return); - } - fast_free++; - (void) t10_cmd_state_machine( - c2free, T10_Cmd_T8); - } else if ((c2free->c_state == - T10_Cmd_S4_AIO) || - (c2free->c_state == - T10_Cmd_S7_Freeing_AIO)) { - t10_aio_t *a; - - a = (t10_aio_t *) - c2free->c_emul_id; - if (a == NULL) { - continue; - } else if (a->a_aio.aio_errno == - ECANCELED) { - fast_free++; - /* - * Note, using T5 not T8 - * because S4 + T8 = S7 - * not S1, S1 is the - * desired result. - */ - /*CSTYLED*/ - (void) t10_cmd_state_machine(c2free, T10_Cmd_T5); - /* - * Account for this cmd - * in aio sema. - */ - (void) sema_post( - &t10_aio_sema); - } else { - queue_prt(mgmtq, - Q_STE_NONIO, - "SAM%x ... " - "S4 or S7 Cmd %p, " - "errno/ret %d/%d\n", - t->s_targ_num, - c2free, - a->a_aio.aio_errno, - /*CSTYLED*/ - a->a_aio.aio_return); - } - } else if (c2free->c_state == - T10_Cmd_S3_Trans) { - t10_aio_t *a; - - a = (t10_aio_t *) - c2free->c_emul_id; - if (a != NULL) { - queue_prt(mgmtq, - Q_STE_NONIO, - "SAM%x ... " - "S3 Cmd %p, " - "errno/ret %d/%d\n", - t->s_targ_num, - c2free, - a->a_aio.aio_errno, - /*CSTYLED*/ - a->a_aio.aio_return); - } - fast_free++; - (void) t10_cmd_state_machine( - c2free, T10_Cmd_T8); - } - } - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x FastFree %d ... " - "Waiting for %d cmds to drain\n", - t->s_targ_num, fast_free, - avl_numnodes(&l->l_cmds)); - - if (avl_numnodes(&l->l_cmds) != 0) { - l->l_wait_for_drain = True; - if (wait) { - while (l->l_wait_for_drain == - True) { - (void) pthread_cond_wait - (&l->l_cmd_cond, - &l->l_cmd_mutex); - } - assert( - avl_numnodes(&l->l_cmds) - == 0); - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x Commands drained\n", - t->s_targ_num); - } else { - (void) pthread_mutex_unlock( - &l->l_cmd_mutex); - (void) pthread_mutex_unlock( - &t->s_mutex); - (void) nanosleep(&usec, 0); - return (1); - } - } - } - avl_remove(&t->s_open_lu, l); - avl_destroy(&l->l_cmds); - (void) pthread_mutex_unlock(&l->l_cmd_mutex); - free(l); - } - } - avl_destroy(&t->s_open_lu); - (void) pthread_mutex_unlock(&t->s_mutex); - - (void) pthread_mutex_destroy(&t->s_mutex); - free(t->s_targ_base); - free(t->s_i_name); - free(t); - return (0); -} - -/* - * []---- - * | t10_cmd_create -- creates a command pointer - * | - * | If an error occurs, a sense condition buffer will be created that can - * | be sent back to the initiator. The only time this should occur is during - * | LU setup and we've run out of resources like not having enough file - * | descriptors to open the backing store. If the cmdp is NULL, then there's - * | not even enough memory to create a command buffer and the transport - * | should shutdown it's connection a cleanly as possible. - * []---- - */ -Boolean_t -t10_cmd_create(t10_targ_handle_t t, int lun_number, uint8_t *cdb, - size_t cdb_len, transport_t trans_id, t10_cmd_t **cmdp) -{ - t10_cmd_t *cmd = NULL; - - *cmdp = NULL; - if (t == NULL) - goto error; - - if ((cmd = umem_cache_alloc(t10_cmd_cache, UMEM_DEFAULT)) == NULL) - goto error; - - bzero(cmd, sizeof (*cmd)); - if ((cmd->c_cdb = malloc(cdb_len)) == NULL) - goto error; - - cmd->c_trans_id = trans_id; - *cmdp = cmd; - if (t10_find_lun((t10_targ_impl_t *)t, lun_number, cmd) == False) - goto error; - - (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex); - avl_add(&cmd->c_lu->l_cmds, (void *)cmd); - cmd->c_state = T10_Cmd_S1_Free; - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - bcopy(cdb, cmd->c_cdb, cdb_len); - cmd->c_cdb_len = cdb_len; - - return (True); - -error: - if (cmd && cmd->c_cdb) { - free(cmd->c_cdb); - cmd->c_cdb = NULL; - } - - /* - * If we haven't set up the argument pointer, then free the memory - * that had been allocated to the command. - */ - if (*cmdp == NULL) - umem_cache_free(t10_cmd_cache, cmd); - return (False); -} - -/* - * []---- - * | t10_send_cmd -- send the given command to appropriate LUN emulation - * | - * | NOTE: emul_id is only provided for DATA_OUT commands (write ops) - * | which have multiple phases to complete the request. The emulation - * | module will provide this value when it requests more data to be - * | sent. - * []---- - */ -/*ARGSUSED*/ -Boolean_t -t10_cmd_send(t10_targ_handle_t t, t10_cmd_t *cmd, char *opt_data, - size_t opt_data_len) -{ - if (cmd == NULL) - return (False); - - cmd->c_data = opt_data; - cmd->c_data_len = opt_data_len; - - t10_cmd_shoot_event(cmd, T10_Cmd_T1); - return (True); -} - -/*ARGSUSED*/ -Boolean_t -t10_cmd_data(t10_targ_handle_t t, t10_cmd_t *cmd, size_t offset, char *data, - size_t data_len) -{ - if (cmd == NULL) - return (False); - cmd->c_data = data; - cmd->c_data_len = data_len; - cmd->c_offset = offset; - - t10_cmd_shoot_event(cmd, T10_Cmd_T4); - return (True); -} - -void -t10_cmd_done(t10_cmd_t *cmd) -{ - if (cmd != NULL) - t10_cmd_shoot_event(cmd, T10_Cmd_T5); -} - -/* - * t10_cmd_state_machine -- State machine for T10 commands - * - * S1: Free - State on instantiation, or after successful - * completion of command - * S2: In - The command is currently being processed - * by the lu_runner() thread. Memory associated - * with the command must not be freed. Can't - * transition directly to Free state from threads - * other than lu_runner(). - * S3: Trans - Command has been handed off to transport layer - * S4: AIO - Command has been sent to AIO subsystem for - * further processing. - * S5: Wait - Waiting for response from Initiator. - * S6: Freeing_In - Free command while command in lu_runner. - * S7: Freeing_AIO - Free command while command is in AIO. - * - * The state transition table is as follows: - * - * +----------+---+---+---+---+---+----+ - * |S1 |S2 |S3 |S4 |S5 |S6 |S7 | - * ---+----------+---+---+---+---+--------+ - * S1|T4/5/6/8 |T1 | - | - | - | - | - | - * ---+----------+---+---+---+---+--------+ - * S2|T5/8 | - |T2 |T3 |T7 |T6 | - | - * ---+----------+---+---+---+---+--------+ - * S3|T5/8 |T4 | - | - |T7 |T6 | - | - * ---+----------+---+---+---+---+--------+ - * S4|T5 |T4 | - | - | - | - |T6/8| - * ---+----------+---+---+---+---+--------+ - * S5|T5/8 | - |T4 | - | - |T6 | - | - * ---+----------+---+---+---+---+--------+ - * S6|T2/4/5/6/8| - | - | - | - | - |T3 | - * ---+----------+---+---+---+---+--------+ - * S7|T4/5/8 | - | - | - | - | - |T6 | - * ---+----------+---+---+---+---+--------+ - * - * Events definitions: - * -T1: Command has been placed on LU queue for exection. - * -T2: Emulation completed to a point where the transport must - * take over and send data or CDB response out. - * -T3: Emulation requires data from storage subsystem via asynchronous - * I/O. - * -T4: One of the following events has caused the transition: - * - Response from initiator to R2T request. - * - Transport has data available to complete dataout request from T10. - * - AIO has completed read/write op. - * -T5: Command complete. Free resources. - * -T6: Cancel command. - * -T7: Transport has sent command to Initiator. - * -T8: Shutting down, cancel or complete as appropriate - */ -static t10_cmd_state_t -t10_cmd_state_machine(t10_cmd_t *c, t10_cmd_event_t e) -{ - t10_lu_impl_t *lu = c->c_lu; - - /* ---- Callers must already hold the mutex ---- */ - assert(pthread_mutex_trylock(&lu->l_cmd_mutex) != 0); - - switch (c->c_state) { - case T10_Cmd_S1_Free: - switch (e) { - case T10_Cmd_T1: - c->c_state = T10_Cmd_S2_In; - queue_message_set(c->c_lu->l_common->l_from_transports, - 0, msg_cmd_send, (void *)c); - break; - - case T10_Cmd_T4: - case T10_Cmd_T5: - case T10_Cmd_T6: /* warm reset */ - case T10_Cmd_T8: /* shutdown */ - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "Illegal event %s on %llx\n", event_to_str(e), - c->c_trans_id); - assert(0); - } - break; - - case T10_Cmd_S2_In: - switch (e) { - case T10_Cmd_T2: - c->c_state = T10_Cmd_S3_Trans; - queue_message_set(c->c_lu->l_to_transport, 0, - c->c_msg, (void *)c); - break; - - case T10_Cmd_T3: - c->c_state = T10_Cmd_S4_AIO; - (void) sema_post(&t10_sema); - break; - - case T10_Cmd_T5: - case T10_Cmd_T8: /* shutdown */ - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - case T10_Cmd_T6: - c->c_state = T10_Cmd_S6_Freeing_In; - break; - - case T10_Cmd_T7: - c->c_state = T10_Cmd_S5_Wait; - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "SAM: Illegal event %s on %llx\n", - event_to_str(e), c->c_trans_id); - assert(0); - } - break; - - case T10_Cmd_S3_Trans: - switch (e) { - case T10_Cmd_T4: - c->c_state = T10_Cmd_S2_In; - queue_message_set(lu->l_common->l_from_transports, 0, - msg_cmd_data_out, (void *)c); - break; - - case T10_Cmd_T5: - case T10_Cmd_T8: /* shutdown */ - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - case T10_Cmd_T6: - c->c_state = T10_Cmd_S6_Freeing_In; - break; - - case T10_Cmd_T7: - c->c_state = T10_Cmd_S5_Wait; - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "Illegal event %s -- %llx\n", event_to_str(e), - c->c_trans_id); - assert(0); - } - break; - - case T10_Cmd_S4_AIO: - switch (e) { - case T10_Cmd_T4: - c->c_state = T10_Cmd_S2_In; - break; - - case T10_Cmd_T5: - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - case T10_Cmd_T6: - case T10_Cmd_T8: /* shutdown */ - c->c_state = T10_Cmd_S7_Freeing_AIO; - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "Illegal event %s -- %llx\n", event_to_str(e), - c->c_trans_id); - assert(0); - } - break; - - case T10_Cmd_S5_Wait: - switch (e) { - case T10_Cmd_T4: - c->c_state = T10_Cmd_S3_Trans; - break; - - case T10_Cmd_T5: - case T10_Cmd_T8: /* shutdown */ - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - case T10_Cmd_T6: - c->c_state = T10_Cmd_S6_Freeing_In; - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "Illegal event %s -- %llx\n", event_to_str(e), - c->c_trans_id); - assert(0); - } - break; - - case T10_Cmd_S6_Freeing_In: - switch (e) { - case T10_Cmd_T2: - case T10_Cmd_T4: /* AIO complete */ - case T10_Cmd_T5: /* command complete */ - case T10_Cmd_T6: /* warm reset */ - case T10_Cmd_T8: /* shutdown */ - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - case T10_Cmd_T3: - c->c_state = T10_Cmd_S7_Freeing_AIO; - (void) sema_post(&t10_sema); - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "Illegal event %s -- %llx\n", event_to_str(e), - c->c_trans_id); - assert(0); - } - break; - - case T10_Cmd_S7_Freeing_AIO: - switch (e) { - case T10_Cmd_T4: /* AIO complete */ - case T10_Cmd_T5: /* command complete */ - case T10_Cmd_T8: - c->c_state = T10_Cmd_S1_Free; - cmd_common_free(c); - return (T10_Cmd_S1_Free); - - case T10_Cmd_T6: /* warm reset */ - queue_prt(mgmtq, Q_GEN_DETAILS, - "Event %s in T10_Cmd_S7_Freeing_AIO -- %llx\n", - event_to_str(e), c->c_trans_id); - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "Illegal event %s -- %llx\n", event_to_str(e), - c->c_trans_id); - assert(0); - } - break; - - default: - assert(0); - } - return (c->c_state); -} - -void -t10_cmd_shoot_event(t10_cmd_t *c, t10_cmd_event_t e) -{ - t10_lu_impl_t *lu; - - /* - * Since the transport may or may not have called into the T10 layer - * to allocate a command it's possible that this will be NULL. Instead - * of requiring every caller of this function to first check if the - * command pointer is null we'll do the check here. - */ - if (c == NULL) - return; - - lu = c->c_lu; - - /* - * If t10_cmd_create() fails for some reason other than lack - * of memory the extended status will be set for the transport - * to send out. There will not be any LU associated with this - * command, but the transport will still try to free it. - */ - if (!lu) { - assert(e == T10_Cmd_T5); - cmd_common_free(c); - return; - } - - (void) pthread_mutex_lock(&lu->l_cmd_mutex); - (void) t10_cmd_state_machine(c, e); - (void) pthread_mutex_unlock(&lu->l_cmd_mutex); -} - -/* - * []---- - * | t10_task_mgmt -- handle SAM-3 task management needs - * []---- - */ -/*ARGSUSED*/ -Boolean_t -t10_task_mgmt(t10_targ_handle_t t1, TaskOp_t op, int opt_lun, void *tag) -{ - t10_targ_impl_t *t = (t10_targ_impl_t *)t1; - t10_lu_impl_t search; - t10_lu_impl_t *lu; - - switch (op) { - case InventoryChange: - (void) pthread_mutex_lock(&t->s_mutex); - if ((lu = avl_first(&t->s_open_lu)) != NULL) { - do { - /*CSTYLED*/ - queue_message_set(lu->l_common->l_from_transports, - 0, msg_targ_inventory_change, (void *)lu); - } while ((lu = AVL_NEXT(&t->s_open_lu, lu)) != NULL); - } - (void) pthread_mutex_unlock(&t->s_mutex); - return (True); - - case ResetTarget: - (void) pthread_mutex_lock(&t->s_mutex); - if ((lu = avl_first(&t->s_open_lu)) != NULL) { - do { - /*CSTYLED*/ - queue_message_set(lu->l_common->l_from_transports, - Q_HIGH, msg_reset_lu, (void *)lu); - } while ((lu = AVL_NEXT(&t->s_open_lu, lu)) != NULL); - (void) pthread_mutex_unlock(&t->s_mutex); - return (True); - } else { - (void) pthread_mutex_unlock(&t->s_mutex); - return (False); - } - - case ResetLun: - search.l_targ_lun = opt_lun; - (void) pthread_mutex_lock(&t->s_mutex); - if ((lu = avl_find(&t->s_open_lu, (void *)&search, NULL)) != - NULL) { - queue_message_set(lu->l_common->l_from_transports, - Q_HIGH, msg_reset_lu, (void *)lu); - (void) pthread_mutex_unlock(&t->s_mutex); - return (True); - } else { - (void) pthread_mutex_unlock(&t->s_mutex); - return (False); - } - break; - - case CapacityChange: - search.l_targ_lun = opt_lun; - (void) pthread_mutex_lock(&t->s_mutex); - if ((lu = avl_find(&t->s_open_lu, (void *)&search, NULL)) != - NULL) { - queue_message_set(lu->l_common->l_from_transports, - Q_HIGH, msg_lu_capacity_change, - (void *)(uintptr_t)opt_lun); - (void) pthread_mutex_unlock(&t->s_mutex); - return (True); - } else { - (void) pthread_mutex_unlock(&t->s_mutex); - return (False); - } - break; - - default: - return (False); - } -} - - -/* - * []---- - * | t10_targ_stat -- Return stats on each LU associated with target. - * []---- - */ -void -t10_targ_stat(t10_targ_handle_t t1, char **buf) -{ - t10_targ_impl_t *t = (t10_targ_impl_t *)t1; - t10_lu_impl_t *itl; - char lb[32]; - char *p; - - /* - * It's possible for the management interfaces to request stats - * even though a connection is not up and running. - */ - if (t == NULL) - return; - - (void) pthread_mutex_lock(&t->s_mutex); - itl = avl_first(&t->s_open_lu); - while (itl) { - tgt_buf_add_tag(buf, XML_ELEMENT_LUN, Tag_Start); - (void) snprintf(lb, sizeof (lb), "%d", itl->l_common->l_num); - tgt_buf_add_tag(buf, lb, Tag_String); - - (void) snprintf(lb, sizeof (lb), "%lld", itl->l_cmds_read); - tgt_buf_add(buf, XML_ELEMENT_READCMDS, lb); - (void) snprintf(lb, sizeof (lb), "%lld", itl->l_cmds_write); - tgt_buf_add(buf, XML_ELEMENT_WRITECMDS, lb); - (void) snprintf(lb, sizeof (lb), "%lld", itl->l_sects_read); - tgt_buf_add(buf, XML_ELEMENT_READBLKS, lb); - (void) snprintf(lb, sizeof (lb), "%lld", itl->l_sects_write); - tgt_buf_add(buf, XML_ELEMENT_WRITEBLKS, lb); - - switch (itl->l_common->l_state) { - case lu_online: - p = TGT_STATUS_ONLINE; - break; - case lu_offline: - p = TGT_STATUS_OFFLINE; - break; - case lu_errored: - p = TGT_STATUS_ERRORED; - break; - } - tgt_buf_add(buf, XML_ELEMENT_STATUS, p); - - tgt_buf_add_tag(buf, XML_ELEMENT_LUN, Tag_End); - itl = AVL_NEXT(&t->s_open_lu, itl); - } - (void) pthread_mutex_unlock(&t->s_mutex); -} - -/* - * []---- - * | t10_thick_provision -- fill the backing store with real blocks - * | - * | The backing store is initially created as a hole-y file. The only - * | thing wrong with leaving the files hole-y is that if a system - * | administrator over provisions the storage at some point a client - * | will attempt to write to a block and receive an error unless the - * | administrator adds more backing store before that event. Now, depending - * | on the client a write error isn't fatal. However, for file systems - * | like UFS and ZFS, they can not currently deal with getting a write - * | error when it's their metadata and panic. That's not good. The concept - * | of "Thin Provisioning" is relatively new so we'll normally preallocate - * | the space, but have the option of doing the "Thin Provisioning". - * []---- - */ -Boolean_t -t10_thick_provision(char *target, int lun, target_queue_t *q) -{ - t10_targ_handle_t t; - t10_cmd_t *cmd = NULL; - uint8_t cdb[16]; /* ---- fake buffer ---- */ - diskaddr_t offset = 0; - size_t size; - size_t sync_size; - msg_t *m = NULL; - target_queue_t *rq = NULL; - char path[MAXPATHLEN]; - char *local_name; - tgt_node_t *n1; - Boolean_t rval = False; - struct statvfs fs; - - /* - * To guarantee that everything has been setup correctly - * we'll just use the standard interfaces. Otherwise we'd need - * to duplicate the code and therefore offer the chance of - * having something fixed/change in one location that isn't - * in another. Obvious right? - */ - if ((t = t10_handle_create(target, "", 0, 0, 0, q, NULL)) == NULL) { - queue_prt(mgmtq, Q_STE_ERRS, "STE%x Failed to create handle\n", - lun); - return (False); - } - if (t10_cmd_create(t, lun, cdb, sizeof (cdb), 0, &cmd) == False) { - queue_prt(mgmtq, Q_STE_ERRS, "STE%x Failed to create cmd\n", - lun); - goto error; - } - - /* - * Attempt to see if there is enough space currently for the LU. - * The initialization might still fail with out of space because someone - * else is consuming space while the initialization is occuring. - * Nothing we can do about that. - */ - if (fstatvfs(cmd->c_lu->l_common->l_fd, &fs) != 0) { - queue_prt(mgmtq, Q_STE_ERRS, "STE%x statvfs failed for LU\n", - lun); - goto error; - } else if ((fs.f_frsize * fs.f_bfree) < cmd->c_lu->l_common->l_size) { - queue_prt(mgmtq, Q_STE_ERRS, "STE%x Not enough space for LU\n", - lun); - goto error; - } - - if (fallocate(cmd->c_lu->l_common->l_fd, cmd->c_lu->l_common->l_size) == - False) { - /* - * The lu_runner will use this buffer to copy data. - */ - sync_size = 1024 * 1024; - if ((cmd->c_data = malloc(sync_size)) == NULL) - goto error; - - while ((offset < cmd->c_lu->l_common->l_size) && (rq == NULL)) { - size = min(cmd->c_lu->l_common->l_size - offset, - sync_size); - cmd->c_offset = offset; - cmd->c_data_len = size; - /*CSTYLED*/ - queue_message_set(cmd->c_lu->l_common->l_from_transports, 0, - msg_thick_provo, (void *)cmd); - while ((m = queue_message_get(q)) != NULL) { - switch (m->msg_type) { - case msg_thick_provo: - if ((int)(intptr_t)m->msg_data != 0) { - - /* - * An error occurred during - * initialization which mean we - * need to remove this target. - */ - queue_prt(mgmtq, Q_STE_ERRS, - "STE%x received data " - "error at 0x%llx\n", lun, - offset); - goto error; - } - break; - - case msg_shutdown: - queue_prt(mgmtq, Q_STE_NONIO, - "---- Thick provo got shutdown\n"); - rq = (target_queue_t *)m->msg_data; - queue_message_free(m); - continue; /* don't use break */ - - default: - assert(0); - } - break; - } - queue_message_free(m); - offset += size; - } - } else { - queue_prt(mgmtq, Q_STE_NONIO, "STE%x fallocate worked\n", - lun); - } - - /* - * A forced shutdown is still considered a successful completion. - * Write errors and malloc failures constitute a failure. - */ - rval = True; - - /* ---- Completed successfully ---- */ - if (rq == NULL) { - - /* - * Now that the initialization is complete, update the params - * file to indicate the status is online. Once done, send a - * message to the LU thread indicating same. - */ - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", - target_basedir, cmd->c_lu->l_targ->s_targ_base, PARAMBASE, - lun); - - cmd->c_lu->l_common->l_state = lu_online; - if ((n1 = tgt_node_find(cmd->c_lu->l_common->l_root, - XML_ELEMENT_STATUS)) == NULL) { - queue_prt(mgmtq, Q_STE_ERRS, - "STE%x couldn't find <status>\n", lun); - goto error; - } - - if (tgt_update_value_str(n1, XML_ELEMENT_STATUS, - TGT_STATUS_ONLINE) == False) { - queue_prt(mgmtq, Q_STE_ERRS, - "STE%x Could update <status> to online\n", lun); - goto error; - } - - local_name = get_local_name(cmd->c_lu->l_targ->s_targ_base); - if (local_name == NULL) - goto error; - - (void) mgmt_param_save2scf(cmd->c_lu->l_common->l_root, - local_name, lun); - free(local_name); - queue_message_set(cmd->c_lu->l_common->l_from_transports, 0, - msg_lu_online, 0); - } - -error: - if (cmd != NULL) { - if (cmd->c_data != NULL) - free(cmd->c_data); - t10_cmd_shoot_event(cmd, T10_Cmd_T5); - } - if (t != NULL) { - t10_handle_disable(t); - (void) t10_handle_destroy(t, True); - } - if (rq != NULL) { - queue_message_set(rq, 0, msg_shutdown_rsp, 0); - } - - return (rval); -} - -/* - * []------------------------------------------------------------------[] - * | Methods called by emulation modules to interface with SAM-3 | - * []------------------------------------------------------------------[] - */ - -/* - * trans_cmd_dup -- Duplicate a T10 command buffer - * - * During read operations with transports that restrict transfer sizes the - * emulation code has two options. - * (1) It could transfer a chunk of data and wait until the - * transport has sent that out. Notification coming through - * the callback mechanism. If the command structure is not - * duplicated it would need to wait since the command structure - * contains the data pointer and offset values which the transport - * needs. - * (2) Use this routine to duplicate the command structure such - * that the emulation layer can send all of the data in chunks - * without waiting. - * For obvious performance reasons it's best to send all of the chunks - * without waiting. - * - * It's expected that the emulation layer will not call this routine for the - * last outgoing packet since the command structure will not be of futher - * use. - */ -t10_cmd_t * -trans_cmd_dup(t10_cmd_t *cmd) -{ - t10_cmd_t *c; - - if ((c = umem_cache_alloc(t10_cmd_cache, UMEM_DEFAULT)) == NULL) - return (NULL); - bcopy(cmd, c, sizeof (*c)); - c->c_cmd_next = NULL; - if ((c->c_cdb = (uint8_t *)malloc(c->c_cdb_len)) == NULL) { - umem_cache_free(t10_cmd_cache, c); - return (NULL); - } - bcopy(cmd->c_cdb, c->c_cdb, c->c_cdb_len); - - (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex); - c->c_state = T10_Cmd_S2_In; - avl_add(&c->c_lu->l_cmds, (void *)c); - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - - return (c); -} - -/* - * []---- - * | trans_send_datain -- send data to transport - * | - * | NOTES: - * | (1) offset is only valid when a transport has set max_out to a non-zero - * | value. - * | (2) The emulation code must free the memory, if it was allocated, when - * | the transport is finished with it. The callback routine is used - * | to provide the emulation code the notification. The callback will - * | not be run on the same thread as the emulation code so appropriate - * | locking may be required by the emulation code. - * | (3) If the boolean 'last' is True it means that the transport can - * | assume the data out is finished with a CMD_SUCCESS and no futher - * | communication from the emulation layer will occur. - * []---- - */ -Boolean_t -trans_send_datain(t10_cmd_t *c, char *data, size_t data_len, size_t offset, - void (*callback)(emul_handle_t e), Boolean_t last, emul_handle_t id) -{ -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SAM%x LUN%d DataIn 0x%x, offset 0x%x, Last %s\n", - c->c_lu->l_targ->s_targ_num, c->c_lu->l_common->l_num, - data_len, offset, last == True ? "true" : "false"); -#endif - - c->c_emul_complete = callback; - c->c_emul_id = id; - c->c_data = data; - c->c_data_len = data_len; - c->c_offset = offset; - c->c_last = last; - c->c_msg = msg_cmd_data_in; - - t10_cmd_shoot_event(c, T10_Cmd_T2); - return (True); -} - -/* - * []---- - * | trans_rqst_dataout -- Request data from transport for command - * | - * | If the transport has indicated that data is immediately available, - * | which is common for iSCSI, then we'll copy that data into the buffer - * | and call the emulation modules datain function directly. - * []---- - */ -Boolean_t -trans_rqst_dataout(t10_cmd_t *cmd, char *data, size_t data_len, size_t offset, - emul_cmd_t emul_id, void (*callback)(emul_handle_t e)) -{ - size_t max_xfer; - - cmd->c_emul_complete = callback; - cmd->c_emul_id = emul_id; - - /* - * Transport supports immediate data on writes. Currently - * on the iSCSI protocol has this feature. - * XXX Should all of this be done in the transport? - */ - if (cmd->c_data_len) { -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SAM%x LUN%d DataOut rqst w/ immed, data_len 0x%x\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, data_len); -#endif - if (cmd->c_data == NULL) { - - /* - * When there's data available, but no buffer it - * means the transport has decided to leave the - * data on the socket and will read it in - * when called. - */ - max_xfer = data_len; - assert(cmd->c_lu->l_targ->s_dataout_cb != NULL); - (*cmd->c_lu->l_targ->s_dataout_cb)(cmd, data, - &max_xfer); - - } else { - - /* - * The data is already in the command buffer so - * we need to copy it out. - */ - max_xfer = MIN(cmd->c_data_len - cmd->c_resid, - data_len); - bcopy(cmd->c_data + cmd->c_resid, data, max_xfer); - cmd->c_resid = cmd->c_data_len - max_xfer; - - /* - * It's expected since the transport allocated - * the space, this routine will free the memory - * instead. - */ - (*cmd->c_lu->l_targ->s_dataout_cb)(cmd, data, - &max_xfer); - cmd->c_data = NULL; - - } - cmd->c_data_len = 0; - (*cmd->c_lu->l_data)(cmd, emul_id, offset, data, max_xfer); - return (True); - } - -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SAM%x LUN%d DataOut Rqst data_len 0x%x\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, data_len); -#endif - - assert(cmd->c_data == NULL); - - cmd->c_data = data; - cmd->c_data_len = data_len; - cmd->c_offset = offset; - cmd->c_resid = 0; - - /* - * Short cut. There's no reason to call the transport if the - * emulation code hasn't requested any data. If that's the - * case just call the emulation codes data function. - */ - if (data_len == 0) - (*cmd->c_lu->l_data)(cmd, emul_id, offset, data, max_xfer); - else { - cmd->c_msg = msg_cmd_data_rqst; - t10_cmd_shoot_event(cmd, T10_Cmd_T2); - } - return (True); -} - -/* - * []---- - * | trans_send_complete -- notify transport command has finished. - * | - * | This routine is called either for when the emulation has completed - * | a command which doesn't have a data in phase so we can't use the 'last' - * | flag or there's been an error. - * | The sense data is expected to be created by calling spc_create_sense(), - * | the memory for that sense data will be freed when the transport calls - * | t10_destroy_cmd(). - * | - * | NOTE [1]: If the t10_status equals STATUS_BUSY the command queue for this - * | ITL will be examined. If there are commands in progress the status will - * | be changed to STATUS_QFULL - * | - * | NOTE [2]: Do not access 'cmd' after calling this function. The transport - * | may receive the command, act on it, and then call - * | t10_cmd_shoot_state(cmd, T10_Cmd_T5) before this function returns - * | thereby allowing 'cmd' to be freed and the space reallocated. - * []---- - */ -void -trans_send_complete(t10_cmd_t *cmd, int t10_status) -{ -#ifdef FULL_DEBUG - struct scsi_extended_sense e; -#endif - - (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex); - /* - * XXX Get the exact chapter and verse from the T10 documents. - * translate a STATUS_BUSY to STATUS_QFULL if there are outstanding - * commands in the queue. - */ - if ((t10_status == STATUS_BUSY) && - (avl_numnodes(&cmd->c_lu->l_cmds) != 0)) { - t10_status = STATUS_QFULL; - } - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - - cmd->c_cmd_status = t10_status; - cmd->c_last = True; - cmd->c_data_len = 0; - cmd->c_data = 0; - cmd->c_msg = msg_cmd_cmplt; - -#ifdef FULL_DEBUG - if (t10_status != STATUS_GOOD) { - if (cmd->c_cmd_sense != NULL) { - bcopy(&cmd->c_cmd_sense[2], &e, sizeof (e)); - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x LUN%d key_sense=0x%x, " - "ASC=0x%x, ASCQ=0x%x\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - e.es_key, e.es_add_code, e.es_qual_code); - } else { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x LUN%d key_sense=0x%x\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, t10_status); - } - } -#endif - - t10_cmd_shoot_event(cmd, T10_Cmd_T2); -} - -void -trans_aiowrite(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset, - t10_aio_t *taio) -{ - taio->a_cmd = cmd; - - (void) sema_wait(&t10_aio_sema); - (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex); - if (aiowrite(cmd->c_lu->l_common->l_fd, data, data_len, offset, 0, - &taio->a_aio) == -1) { - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - (void) sema_post(&t10_aio_sema); - taio->a_aio.aio_return = -1; - (*taio->a_aio_cmplt)(taio->a_id); - } else { - (void) t10_cmd_state_machine(cmd, T10_Cmd_T3); - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - } -} - -void -trans_aioread(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset, - t10_aio_t *taio) -{ - taio->a_cmd = cmd; - - (void) sema_wait(&t10_aio_sema); - (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex); - if (aioread(cmd->c_lu->l_common->l_fd, data, data_len, offset, 0, - &taio->a_aio) == -1) { - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - (void) sema_post(&t10_aio_sema); - taio->a_aio.aio_return = -1; - (*taio->a_aio_cmplt)(taio->a_id); - } else { - (void) t10_cmd_state_machine(cmd, T10_Cmd_T3); - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - } -} - -/* - * []---- - * | trans_params_area -- return dtype params using a command pointer - * | - * | Lock down the ITL structure from change so that we can cleanly access - * | the params area. This is needed to deal with the transport closing - * | a connection while commands are in flight. When those commands finish - * | cleanup work needs to be done. Yet, the logical unit common area - * | can already be released since it doesn't know there's something to wait - * | for. - * []---- - */ -void * -trans_params_area(t10_cmd_t *cmd) -{ - void *p = NULL; - - (void) pthread_mutex_lock(&cmd->c_lu->l_mutex); - if (cmd->c_lu->l_common != NULL) - p = cmd->c_lu->l_common->l_dtype_params; - (void) pthread_mutex_unlock(&cmd->c_lu->l_mutex); - return (p); -} - -/* - * []------------------------------------------------------------------[] - * | Support routines for Routing and Task Management | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | t10_find_lun -- Locate a per target LUN structure - * | - * | Finds per I_T_L structure. If this is the first time that this structure - * | has been accessed we allocate the structure and add it to the global - * | LUN structure. If that structure has never been accessed before it is - * | created along with a thread to handle the queue. - * []---- - */ -/*ARGSUSED*/ -static Boolean_t -t10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *cmd) -{ - t10_lu_impl_t *l = NULL; - t10_lu_impl_t search; - avl_index_t wc = 0; /* where common */ - avl_index_t wt = 0; /* where target */ - char *guid = NULL; - char *str; - char *dataset = NULL; - char *local_name = NULL; - t10_lu_common_t lc; - t10_lu_common_t *common = NULL; - tgt_node_t *n = NULL; - tgt_node_t *n1; - tgt_node_t *targ; - tgt_node_t *ll; - char path[MAXPATHLEN]; - Boolean_t okay_to_free = True; - - bzero(&lc, sizeof (lc)); - - /* - * Only l_num is used by the AVL search routines so that's - * the only thing we'll set. - */ - search.l_targ_lun = lun; - - (void) pthread_mutex_lock(&t->s_mutex); - if ((l = avl_find(&t->s_open_lu, (void *)&search, &wt)) != NULL) { - - /* - * This should be the normal fast path. At some point it - * might be good to look at optimizing this even more. - * If we know for example that the LUN numbers are sequential - * and there's fewer than 64 an array of pointers would be - * even faster than an AVL tree and not take up to much space. - */ - cmd->c_lu = l; - (void) pthread_mutex_unlock(&t->s_mutex); - return (True); - } - (void) pthread_mutex_unlock(&t->s_mutex); - - /* - * First access for this I_T_L so we need to allocate space for it. - */ - if ((l = calloc(1, sizeof (*l))) == NULL) { - cmd->c_cmd_status = STATUS_CHECK; - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - return (False); - } - - /* - * Initialize the various local fields. Certain fields will not be - * initialized until we've got the common LUN pointer. - */ - (void) pthread_mutex_init(&l->l_cmd_mutex, NULL); - (void) pthread_mutex_init(&l->l_mutex, NULL); - (void) pthread_cond_init(&l->l_cmd_cond, NULL); - avl_create(&l->l_cmds, find_cmd_by_addr, sizeof (t10_cmd_t), - offsetof(t10_cmd_t, c_cmd_avl)); - - l->l_wait_for_drain = False; - l->l_to_transport = t->s_to_transport; - l->l_targ = t; - l->l_targ_lun = lun; - - targ = NULL; - - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - if ((tgt_find_value_str(targ, XML_ELEMENT_INAME, &str) == - True) && (strcmp(str, t->s_targ_base) == 0)) { - local_name = strdup(targ->x_value); - free(str); - break; - } else if (str) { - free(str); - str = NULL; - } - } - if (local_name == NULL) - goto error; - - if ((ll = tgt_node_next(targ, XML_ELEMENT_LUNLIST, NULL)) == NULL) - goto error; - n = NULL; - while ((n = tgt_node_next(ll, XML_ELEMENT_LUN, n)) != NULL) { - if (strtol(n->x_value, NULL, 0) == lun) - break; - } - if (n == NULL) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - /* ---- ACCESS DENIED - INVALID LU IDENTIFIER ---- */ - spc_sense_ascq(cmd, 0x20, 0x9); - goto error; - } - - (void) pthread_mutex_lock(&lu_list_mutex); - - if (tgt_find_value_str(n, XML_ELEMENT_GUID, &guid) == False) { - /* - * Set the targ variable back to NULL to indicate that we don't - * have an incore copy of the information. If the guid is 0, - * we'll update that value and update the ZFS property if targ - * is not NULL, otherwise will update parameter file. - */ - targ = NULL; - - /* - * To locate the common LUN structure we need to find the GUID - * for this LUN. That's the only parsing this section of code - * will do to the params file. - */ - - if (mgmt_get_param(&n, local_name, lun) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - /* --- LUN no longer exists --- */ - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - okay_to_free = True; - - if (tgt_find_value_str(n, XML_ELEMENT_GUID, &guid) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - - } else - okay_to_free = False; - - if ((strcmp(guid, "0") == 0) || (strcmp(guid, "0x0") == 0)) { - free(guid); - /* - * Create the GUID with NAA IEEE Registered Extended - * designator format. - */ - if (util_create_guid(&guid, SPC_INQUIRY_ID_TYPE_NAA) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - if ((n1 = tgt_node_find(n, XML_ELEMENT_GUID)) == NULL) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - if (tgt_update_value_str(n1, XML_ELEMENT_GUID, guid) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - if (targ != NULL) { - /* - * Get the dataset for this shareiscsi target - */ - if (tgt_find_value_str(targ, XML_ELEMENT_ALIAS, - &dataset) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - goto error; - } - - /* - * Set the ZFS persisted shareiscsi options - */ - if (put_zfs_shareiscsi(dataset, targ) != ERR_SUCCESS) { - (void) pthread_mutex_unlock(&lu_list_mutex); - goto error; - } - - free(dataset); - dataset = NULL; - - } else if (mgmt_param_save2scf(n, local_name, lun) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - } - - if (tgt_xml_decode(guid, &lc.l_guid, &lc.l_guid_len) == False) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - - /* - * See if the common LUN for this GUID already exists. - */ - wc = 0; - if ((common = avl_find(&lu_list, (void *)&lc, &wc)) == NULL) { - - /* - * The GUID wasn't found, so create a new LUN structure - * and thread. - */ - if ((common = calloc(1, sizeof (*common))) == NULL) { - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - - common->l_from_transports = queue_alloc(); - common->l_num = lun; - common->l_internal_num = lu_id++; - common->l_guid = lc.l_guid; - common->l_guid_len = lc.l_guid_len; - common->l_fd = -1; /* not open yet */ - common->l_mmap = MAP_FAILED; - common->l_root = n; - common->l_root_okay_to_free = okay_to_free; - n = NULL; - - (void) pthread_mutex_init(&common->l_common_mutex, NULL); - - (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, - t->s_targ_base); - if (t10_lu_initialize(common, path) == False) { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x FAILED to initialize LU %d\n", - t->s_targ_num, lun); - (void) pthread_mutex_unlock(&lu_list_mutex); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - goto error; - } - - avl_create(&common->l_all_open, find_lu_by_targ, - sizeof (t10_lu_impl_t), - offsetof(t10_lu_impl_t, l_open_lu_node)); - - avl_insert(&lu_list, (void *)common, wc); - (void) pthread_create(&common->l_thr_id, NULL, lu_runner, - (void *)common); - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x LU[%d.%d] Created new LU thread 0x%x\n", - t->s_targ_num, common->l_internal_num, common->l_num, - common->l_thr_id); - - } else { - - /* - * If there's a common LU structure already we free - * the guid which was created for the search. If an error - * occurs the guid space will be freed in the error handling - * code. If a new LU is created though we don't free the guid - * since the LU needs the information. - */ - free(lc.l_guid); - - /* - * A similar condition exists with the xml tree. If there's - * already a common LU then this node *may* have been created - * here if it's not a ZVOL. If it is a ZVOL tree then it will - * have the same address as that found in l_root so don't - * free it. - */ - if (okay_to_free == True) { - tgt_node_free(n); - n = NULL; - } - lc.l_guid = NULL; - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x Found existing LU[%d.%d]\n", t->s_targ_num, - common->l_internal_num, common->l_num); - } - (void) pthread_mutex_lock(&common->l_common_mutex); - (void) avl_find(&common->l_all_open, (void *)l, &wc); - avl_insert(&common->l_all_open, (void *)l, wc); - (void) pthread_mutex_unlock(&common->l_common_mutex); - - (void) pthread_mutex_unlock(&lu_list_mutex); - - /* - * Now add this I_T_L to the targets list of open LUNs so that - * in the future we can get access through the AVL tree. - * We wait to add the LU to the target list until now so that we don't - * have to delete the node in case an error occurs. - */ - (void) pthread_mutex_lock(&t->s_mutex); - avl_insert(&t->s_open_lu, (void *)l, wt); - (void) pthread_mutex_unlock(&t->s_mutex); - - (void) pthread_mutex_lock(&l->l_mutex); - l->l_common = common; - (void) pthread_mutex_unlock(&l->l_mutex); - - /* - * The common LU thread is responsible for filling in the command - * functions and table. - */ - queue_message_set(common->l_from_transports, 0, msg_lu_add, (void *)l); - - free(guid); - free(local_name); - - cmd->c_lu = l; - return (True); - -error: - cmd->c_cmd_status = STATUS_CHECK; - if (guid) - free(guid); - if (n) - tgt_node_free(n); - if (l) - free(l); - if (lc.l_guid) - free(lc.l_guid); - if (common) - free(common); - if (dataset) - free(dataset); - return (False); -} - -static Boolean_t -t10_lu_initialize(t10_lu_common_t *lu, char *basedir) -{ - char *str = NULL; - int dtype; - - if (load_params(lu, basedir) == False) - return (False); - - if (tgt_find_value_str(lu->l_root, XML_ELEMENT_DTYPE, &str) == True) { - for (dtype = 0; sam_emul_table[dtype].t_type_name != NULL; - dtype++) { - if (strcmp(sam_emul_table[dtype].t_type_name, - str) == 0) { - lu->l_dtype = dtype; - if ((*sam_emul_table[dtype].t_common_init)(lu) - == False) - goto error; - else - break; - } - } - free(str); - } else - goto error; - - return (True); -error: - if (str != NULL) - free(str); - return (False); -} - -/* - * []---- - * | lu_runner -- The workhorse for each LU - * | - * | This routine is the guts of the Task Router and Task Set for SAM-3. - * []---- - */ -static void * -lu_runner(void *v) -{ - t10_lu_common_t *lu = (t10_lu_common_t *)v; - msg_t *m; - t10_lu_impl_t *itl; - t10_cmd_t *cmd; - char *data; - char *path; - size_t data_len; - size_t new_size; - size_t offset; - ssize_t cc; - void *provo_err; - t10_shutdown_t *s; - t10_aio_t *a; - - util_title(mgmtq, Q_STE_NONIO, lu->l_internal_num, "Start LU"); - - while ((m = queue_message_get(lu->l_from_transports)) != NULL) { - - switch (m->msg_type) { - case msg_cmd_send: - cmd = (t10_cmd_t *)m->msg_data; - - if (cmd->c_lu->l_status) { - spc_sense_create(cmd, cmd->c_lu->l_status, 0); - spc_sense_ascq(cmd, cmd->c_lu->l_asc, - cmd->c_lu->l_ascq); - /* - * Clear out the per LU values before - * calling trans_send_complete(). It's - * possible for the transport to handle - * this command and free it before returning. - */ - cmd->c_lu->l_status = 0; - cmd->c_lu->l_asc = 0; - cmd->c_lu->l_ascq = 0; - trans_send_complete(cmd, STATUS_CHECK); - } else { - lu->l_curr = cmd; - (*cmd->c_lu->l_cmd) - (cmd, cmd->c_cdb, cmd->c_cdb_len); - lu->l_curr = NULL; - } - break; - - case msg_cmd_data_out: - cmd = (t10_cmd_t *)m->msg_data; - data = cmd->c_data; - data_len = cmd->c_data_len; - offset = cmd->c_offset; - - /* - * We clear the c_data_len here because if the - * emulation routine processes the data and still - * needs more it will call trans_rqst_datain() - * which will look at c_data_len to see if there - * was immediate data available from the transport. - * In this case we've already processed the data - * and need to request more from the transport. - * c_data is set to NULL because there's an assert - * in trans_rqst_datain() checking that c_data is - * indeed null. - */ - cmd->c_data_len = 0; - cmd->c_data = NULL; - - lu->l_curr = cmd; - (*cmd->c_lu->l_data)(cmd, cmd->c_emul_id, - offset, data, data_len); - lu->l_curr = NULL; - break; - - case msg_lu_aio_done: - a = (t10_aio_t *)m->msg_data; - (*a->a_aio_cmplt)(a->a_id); - break; - - case msg_lu_add: - itl = (t10_lu_impl_t *)m->msg_data; - (*sam_emul_table[lu->l_dtype].t_per_init)(itl); - break; - - case msg_reset_lu: - (void) pthread_mutex_lock(&lu->l_common_mutex); - itl = avl_first(&lu->l_all_open); - while (itl != NULL) { - /* - * The current implementation is that we - * have a shared queue for each LU. That means - * if we reset a LU all I_T nexus' must - * receive a CHECK_CONDITION on their next - * command. - */ - (*sam_emul_table[lu->l_dtype].t_per_fini)(itl); - (*sam_emul_table[lu->l_dtype].t_per_init)(itl); - - itl = AVL_NEXT(&lu->l_all_open, itl); - } - (void) pthread_mutex_unlock(&lu->l_common_mutex); - break; - - case msg_shutdown: - s = (t10_shutdown_t *)m->msg_data; - - itl = s->t_lu; - (void) pthread_mutex_lock(&lu_list_mutex); - (void) pthread_mutex_lock(&lu->l_common_mutex); - assert(avl_find(&lu->l_all_open, (void *)itl, NULL) != - NULL); - queue_walker_free(lu->l_from_transports, - lu_remove_cmds, (void *)itl); - (*sam_emul_table[lu->l_dtype].t_per_fini)(itl); - avl_remove(&lu->l_all_open, (void *)itl); - - if (avl_numnodes(&lu->l_all_open) == 0) { - /* - * Close backing store. - */ - queue_prt(mgmtq, Q_STE_NONIO, - "LU_%x No remaining targets for LU(%d)\n", - lu->l_internal_num, lu->l_fd); - if (lu->l_mmap != MAP_FAILED) - (void) munmap(lu->l_mmap, - lu->l_size); - if (close(lu->l_fd) != 0) - queue_prt(mgmtq, Q_STE_ERRS, - "LU_%x Failed to close fd, " - "errno=%d\n", lu->l_internal_num, - errno); - else - lu->l_fd = -1; - /*CSTYLED*/ - (*sam_emul_table[lu->l_dtype].t_common_fini)(lu); - - avl_remove(&lu_list, (void *)lu); - util_title(mgmtq, Q_STE_NONIO, - lu->l_internal_num, "End LU"); - queue_free(lu->l_from_transports, NULL); - (void) pthread_mutex_unlock( - &lu->l_common_mutex); - (void) pthread_mutex_unlock(&lu_list_mutex); - if (lu->l_root_okay_to_free == True) - tgt_node_free(lu->l_root); - free(lu->l_pid); - free(lu->l_vid); - free(lu->l_guid); - free(lu); - queue_message_free(m); - queue_message_set(mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - /* - * Send the response after all the work here - * is done. - */ - queue_message_set(s->t_q, 0, msg_shutdown_rsp, - (void *)(uintptr_t)itl->l_targ_lun); - pthread_exit(NULL); - } - queue_message_set(s->t_q, 0, msg_shutdown_rsp, - (void *)(uintptr_t)itl->l_targ_lun); - (void) pthread_mutex_unlock(&lu->l_common_mutex); - (void) pthread_mutex_unlock(&lu_list_mutex); - break; - - case msg_targ_inventory_change: - itl = (t10_lu_impl_t *)m->msg_data; - itl->l_status = KEY_UNIT_ATTENTION; - /* - * SPC-3 revision 21c, section 4.5.6, Table 28 - * When LU inventory changes need to report - * a REPORTED LUNS DATA HAS CHANGED event. - */ - itl->l_asc = 0x3f; - itl->l_ascq = 0x0e; - queue_prt(mgmtq, Q_STE_NONIO, - "LU_%x Received InventoryChange for %d\n", - lu->l_internal_num, itl->l_common->l_num); - break; - - case msg_thick_provo: - cmd = (t10_cmd_t *)m->msg_data; - if (lu->l_mmap != MAP_FAILED) { - - /* - * If the file at c_offset is currently - * unallocated we'll read in that buffer - * which will be zeros and then write it - * back out which will force the underlying - * filesystem to allocate the blocks. - * If someone has already issued a write - * to this area we'll then just cause a - * useless, but safe read/write to occur. - */ - lu->l_curr = cmd; - lu->l_curr_provo = True; - bcopy((char *)lu->l_mmap + cmd->c_offset, - cmd->c_data, cmd->c_data_len); - cmd->c_lu->l_cmds_read++; - cmd->c_lu->l_sects_read += - cmd->c_data_len / 512; - bcopy(cmd->c_data, - (char *)lu->l_mmap + cmd->c_offset, - cmd->c_data_len); - cmd->c_lu->l_cmds_write++; - cmd->c_lu->l_sects_write += - cmd->c_data_len / 512; - lu->l_curr = NULL; - lu->l_curr_provo = False; - provo_err = 0; - - } else { - if ((cc = pread(lu->l_fd, cmd->c_data, - cmd->c_data_len, cmd->c_offset)) < 0) { - queue_prt(mgmtq, Q_STE_ERRS, - "LU_%x pread errno=%d\n", - lu->l_num, errno); - } else if (pwrite(lu->l_fd, cmd->c_data, cc, - cmd->c_offset) != cc) { - queue_prt(mgmtq, Q_STE_ERRS, - "LU_%x pwrite errno=%d\n", - lu->l_num, errno); - } - provo_err = (cc == cmd->c_data_len) ? - (void *)0 : (void *)1; - } - /* - * acknowledge this op and wait for next - */ - queue_message_set(cmd->c_lu->l_to_transport, 0, - msg_thick_provo, provo_err); - break; - - case msg_lu_capacity_change: - new_size = lseek(lu->l_fd, 0, SEEK_END); - queue_prt(mgmtq, Q_STE_NONIO, - "LU_%x Capacity Change from 0x%llx to 0x%llx\n", - lu->l_internal_num, lu->l_size, new_size); - if ((path = malloc(MAXPATHLEN)) == NULL) - break; - - (void) snprintf(path, MAXPATHLEN, "%s/%s", - target_basedir, itl->l_targ->s_targ_base); - (void) load_params(lu, path); - free(path); - (*sam_emul_table[lu->l_dtype].t_task_mgmt)(lu, - CapacityChange); - (void) pthread_mutex_lock(&lu->l_common_mutex); - itl = avl_first(&lu->l_all_open); - while (itl != NULL) { - itl->l_status = KEY_UNIT_ATTENTION; - itl->l_asc = SPC_ASC_CAP_CHANGE; - itl->l_ascq = SPC_ASCQ_CAP_CHANGE; - itl = AVL_NEXT(&lu->l_all_open, itl); - } - (void) pthread_mutex_unlock(&lu->l_common_mutex); - break; - - case msg_lu_online: - queue_prt(mgmtq, Q_STE_NONIO, - "LU_%x Received online event\n", - lu->l_internal_num); - if ((path = malloc(MAXPATHLEN)) == NULL) - break; - - (void) pthread_mutex_lock(&lu->l_common_mutex); - itl = avl_first(&lu->l_all_open); - (void) pthread_mutex_unlock(&lu->l_common_mutex); - (void) snprintf(path, MAXPATHLEN, "%s/%s", - target_basedir, itl->l_targ->s_targ_base); - (void) load_params(lu, path); - free(path); - (*sam_emul_table[lu->l_dtype].t_task_mgmt)(lu, - DeviceOnline); - (void) pthread_mutex_lock(&lu->l_common_mutex); - itl = avl_first(&lu->l_all_open); - while (itl != NULL) { - (*sam_emul_table[lu->l_dtype].t_per_init)(itl); - itl = AVL_NEXT(&lu->l_all_open, itl); - } - (void) pthread_mutex_unlock(&lu->l_common_mutex); - break; - - } - queue_message_free(m); - } - - return (NULL); -} - -/* - * []---- - * | lu_buserr_handler -- deal with SIGBUS on mmap'd files - * | - * | Normally SIGBUS's are a real bad thing. With this project, which uses - * | mmap'd files that start out as hole-y, can represent more space than - * | the underlying storage has available. This is good and considered a - * | feature for "Thin Provisioning". However, this means that if the - * | administrator isn't on the ball the storage can fill up. Because of the - * | asynchronous nature of writing to a mmap'd file the OS will send a SIGBUS - * | to the thread which caused the problem. The thread will then locate its - * | data structure and in turn signal the initiator that a problem occurred. - * | Since we can't restart we're we left off because the out of space - * | condition is still present another thread is started to handle other - * | commands for the logical unit. The current thread will then exit. - * | - * | NOTE: - * | If for any reason this routine doesn't find what's it's expecting to - * | assert() will be called to create a core. This routine will only recover - * | from the expected case of a SIGBUS, otherwise something real bad has - * | happened and we need to see the core. - * []---- - */ -/*ARGSUSED*/ -void -lu_buserr_handler(int sig, siginfo_t *sip, void *v) -{ - t10_lu_common_t *lu; - pthread_t id = pthread_self(); - char *fa; - - if (pthread_mutex_trylock(&lu_list_mutex) != 0) { - assert(0); - } - lu = avl_first(&lu_list); - while (lu != NULL) { - if (lu->l_thr_id == id) - break; - lu = AVL_NEXT(&lu_list, lu); - } - (void) pthread_mutex_unlock(&lu_list_mutex); - - if ((lu == NULL) || (lu->l_curr == NULL)) { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x BUS ERROR and couldn't find logical unit\n", - lu->l_num); - assert(0); -#ifdef NDEBUG - return; -#endif - } - - if (lu->l_mmap == MAP_FAILED) { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x BUS ERROR and device not mmap'd\n", lu->l_num); - assert(0); -#ifdef NDEBUG - return; -#endif - } - - fa = (char *)sip->__data.__fault.__addr; - if ((fa < (char *)lu->l_mmap) || - (fa > ((char *)lu->l_mmap + lu->l_size))) { - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x BUS ERROR occurred outsize of mmap bounds\n", - lu->l_num); - assert(0); -#ifdef NDEBUG - return; -#endif - } - - if (lu->l_curr_provo == True) { - lu->l_curr_provo = False; - queue_message_set(lu->l_curr->c_lu->l_to_transport, 0, - msg_thick_provo, (void *)1); - } else { - spc_sense_create(lu->l_curr, KEY_MEDIUM_ERROR, 0); - spc_sense_ascq(lu->l_curr, SPC_ASC_WRITE_ERROR, - SPC_ASCQ_WRITE_ERROR); - trans_send_complete(lu->l_curr, STATUS_CHECK); - } - - queue_prt(mgmtq, Q_STE_ERRS, - "SAM%x Caught an out-of-space issue\n", lu->l_num); - - /* - * Now restart another thread to pick up where we've left off with - * processing commands for this logical unit. - */ - (void) pthread_create(&lu->l_thr_id, NULL, lu_runner, (void *)lu); - pthread_exit((void *)0); -} - - -/* - * []---- - * | lu_remove_cmds -- look for and free commands - * []---- - */ -static Boolean_t -lu_remove_cmds(msg_t *m, void *v) -{ - t10_lu_impl_t *lu = (t10_lu_impl_t *)v; - t10_cmd_t *c; - - switch (m->msg_type) { - case msg_cmd_send: - case msg_cmd_data_out: - c = (t10_cmd_t *)m->msg_data; - if (lu == NULL) { - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x canceled command during lu_remove\n", - c->c_lu->l_targ->s_targ_num); - t10_cmd_shoot_event(c, T10_Cmd_T6); - return (True); - } - if (c->c_lu == lu) { - queue_prt(mgmtq, Q_STE_NONIO, - "SAM%x LUN %d, removed command during lu_remove\n", - c->c_lu->l_targ->s_targ_num, lu->l_common->l_num); - t10_cmd_shoot_event(c, T10_Cmd_T5); - return (True); - } - break; - } - return (False); -} - -/* - * []---- - * | load_params -- load parameters and open LU backing store - * | - * | This routine can be called multiple times and will free and release - * | previous resources. - * []---- - */ -static Boolean_t -load_params(t10_lu_common_t *lu, char *basedir) -{ - char file[MAXPATHLEN]; - char *str; - int oflags = O_RDWR|O_LARGEFILE|O_NDELAY; - Boolean_t mmap_lun = False; - tgt_node_t *node = NULL; - int version_maj = XML_VERS_LUN_MAJ; - int version_min = XML_VERS_LUN_MIN; - - /* - * Clean up from previous call to this function. This occurs if - * the LU has grown since it was last opened. - */ - if (lu->l_mmap != MAP_FAILED) - (void) munmap(lu->l_mmap, lu->l_size); - if (lu->l_fd != -1) { - (void) close(lu->l_fd); - lu->l_fd = -1; - } - - node = lu->l_root; - - if (validate_version(node, &version_maj, &version_min) == False) - (void) fprintf(stderr, "Failed version check\n"); - - if (tgt_find_value_str(node, XML_ELEMENT_PID, &lu->l_pid) == False) - goto error; - - if (tgt_find_value_str(node, XML_ELEMENT_VID, &lu->l_vid) == False) - goto error; - - /* - * If there's no <status> tag it just means this is an older param - * file and there's no need to treat it as an error. Just mark - * the device as online. - */ - if (tgt_find_value_str(node, XML_ELEMENT_STATUS, &str) == True) { - if (strcmp(str, TGT_STATUS_ONLINE) == 0) - lu->l_state = lu_online; - else if (strcmp(str, TGT_STATUS_OFFLINE) == 0) - lu->l_state = lu_offline; - else if (strcmp(str, TGT_STATUS_ERRORED) == 0) - lu->l_state = lu_errored; - free(str); - } else - lu->l_state = lu_online; - - /* - * If offline, we need to check to see if there's an initialization - * thread running for this lun. If not, start one. - */ - if ((lu->l_state == lu_offline) && - (thick_provo_chk_thr(strrchr(basedir, '/') + 1, lu->l_num) == - False)) { - queue_prt(mgmtq, Q_STE_NONIO, - "LU_%d No initialization thread running\n", lu->l_num); - if (thin_provisioning == False) { - thick_provo_t *tp; - pthread_t junk; - - if ((tp = calloc(1, sizeof (*tp))) != NULL) { - tp->targ_name = strdup(strrchr(basedir, '/')) + - 1; - tp->lun = lu->l_num; - tp->q = queue_alloc(); - (void) pthread_create(&junk, NULL, - thick_provo_start, tp); - /* ---- wait for start message ---- */ - queue_message_free(queue_message_get(tp->q)); - } - } - } - - /* - * The default is to disable the fast write acknowledgement which - * can be overridden in a couple of ways. First, see if the global - * fast-write-ack is enabled, then check the per logical unit flags. - * The per LU bit is settable via a SCSI command. - */ - lu->l_fast_write_ack = False; - (void) tgt_find_value_boolean(main_config, XML_ELEMENT_FAST, - &lu->l_fast_write_ack); - (void) tgt_find_value_boolean(node, XML_ELEMENT_FAST, - &lu->l_fast_write_ack); - if (lu->l_fast_write_ack == False) - oflags |= O_SYNC; - - /* - * Object-based Storage Devices currently use directories to - * represent the partitions and files in those directories to - * represent user objects and collections. Therefore, there's - * not just a single file to be opened, but potentially thousands. - * Therefore, stop here if we've got an OSD dtype. - */ - if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &str) == False) - goto error; - if (strcmp(str, TGT_TYPE_OSD) == 0) { - free(str); - return (True); - } else - free(str); - - if (tgt_find_value_str(node, XML_ELEMENT_BACK, &str) == True) { - lu->l_fd = open(str, oflags); - free(str); - if (lu->l_fd == -1) - goto error; - } else { - (void) snprintf(file, sizeof (file), "%s/%s%d", basedir, - LUNBASE, lu->l_num); - if ((lu->l_fd = open(file, oflags)) == -1) - goto error; - } - - (void) tgt_find_value_boolean(node, XML_ELEMENT_MMAP_LUN, &mmap_lun); - if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &str) == True) { - lu->l_size = strtoll(str, NULL, 0) * 512LL; - free(str); - } else - goto error; - - if (mmap_lun == True) { - /* - * st_size will be wrong if the device is a block device - * but that's okay since you can't mmap in a block device. - * A block device will fall back to using AIO operations. - */ - lu->l_mmap = mmap(0, lu->l_size, PROT_READ|PROT_WRITE, - MAP_SHARED|MAP_ALIGN, lu->l_fd, 0); - } else { - lu->l_mmap = MAP_FAILED; - } - return (True); -error: - if (lu->l_pid) { - free(lu->l_pid); - lu->l_pid = NULL; - } - if (lu->l_vid) { - free(lu->l_vid); - lu->l_vid = NULL; - } - if (lu->l_fd != -1) { - (void) close(lu->l_fd); - lu->l_fd = -1; - } - return (False); -} - -/* - * []---- - * | cmd_common_free -- frees data stored in the cmd - * | - * | NOTE: The mutex which protects c_state must be held when this routine - * | is called if there's a LU associated with this command. - * []---- - */ -static void -cmd_common_free(t10_cmd_t *c) -{ - t10_lu_impl_t *lu = c->c_lu; - - if (lu) { - assert(pthread_mutex_trylock(&lu->l_cmd_mutex) != 0); - /* command might be removed by t10_handle_destroy */ - if (avl_find(&lu->l_cmds, c, NULL) == NULL) - return; - avl_remove(&lu->l_cmds, c); - } - - c->c_state = T10_Cmd_S1_Free; - c->c_data = 0; - c->c_data_len = 0; - - clear_transport(c->c_trans_id, c); - - if (c->c_emul_complete != NULL) { - (*c->c_emul_complete)(c->c_emul_id); - c->c_emul_complete = NULL; - } - if (c->c_cdb) { - free(c->c_cdb); - c->c_cdb = NULL; - } - if (c->c_cmd_sense) { - free(c->c_cmd_sense); - c->c_cmd_sense = NULL; - } - if (lu && (lu->l_wait_for_drain == True) && - (avl_numnodes(&lu->l_cmds) == 0)) { - lu->l_wait_for_drain = False; - (void) pthread_cond_signal(&lu->l_cmd_cond); - } - umem_cache_free(t10_cmd_cache, c); -} - -/* - * clear_transport -- Remove the transports reference to the T10 command - * - * This should be a function pointer stored in the t10_lu_impl structure. - * The only reason it's not, is I wish to wait until we know a little more - * about the FC transport. There may be some other callbacks required for that - * transport and if so, I'll need to define a new method for passing in - * the callbacks to the t10_create_handle. The easiest way would probably - * have a structure. I'm concerned about supporting different versions, so - * wish to think about it some more before implementing. - * - * This function can be called on either the transport thread or the t10 - * thread. - */ -static void -clear_transport(transport_t t, t10_cmd_t *t10c) -{ - iscsi_cmd_t *c = (iscsi_cmd_t *)t; - - if (c) { - if (c->c_t10_dup != 0) { - c->c_t10_dup--; - } - if (c->c_t10_cmd != NULL) { - /* - * Find and unlink the cmd to be freed. - * The last entry's next ptr is NULL. - */ - if (c->c_t10_cmd == t10c) { - c->c_t10_cmd = t10c->c_cmd_next; - } else { - t10_cmd_t *t10cnxt = c->c_t10_cmd; - while (t10cnxt->c_cmd_next != NULL) { - if (t10cnxt->c_cmd_next == t10c) { - t10cnxt->c_cmd_next = - t10c->c_cmd_next; - break; - } - t10cnxt = t10cnxt->c_cmd_next; - } - } - } - } -} - -/* - * []---- - * | fallocate -- allocate blocks for file via file system interface - * | - * | This is a faster approach to allocating the blocks for a file. - * | Instead of reading and then writing each block which will force the - * | file system to allocate the data we simply ask the file system to - * | allocate the space. Unfortunately not all file systems support this - * | feature. - * []---- - */ -static Boolean_t -fallocate(int fd, off64_t len) -{ -#ifdef FALLOCATE_SUPPORTED -#if defined(_LARGEFILE64_SOURCE) && !defined(_LP64) - struct flock64 lck; - - lck.l_whence = 0; - lck.l_start = 0; - lck.l_len = len; - lck.l_type = F_WRLCK; - - if (fcntl(fd, F_ALLOCSP64, &lck) == -1) - return (False); - else - return (True); -#else - struct flock lck; - - lck.l_whence = 0; - lck.l_start = 0; - lck.l_len = len; - lck.l_type = F_WRLCK; - - if (fcntl(fd, F_ALLOCSP, &lck) == -1) - return (False); - else - return (True); -#endif -#else - return (False); -#endif -} - -/* - * []---- - * | find_lu_by_num -- AVL comparison which looks at LUN - * []---- - */ -static int -find_lu_by_num(const void *v1, const void *v2) -{ - t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1; - t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2; - - if (l1->l_targ_lun < l2->l_targ_lun) - return (-1); - if (l1->l_targ_lun > l2->l_targ_lun) - return (1); - return (0); -} - -/* - * []---- - * | find_lu_by_guid -- AVL comparison which looks at GUID - * []---- - */ -static int -find_lu_by_guid(const void *v1, const void *v2) -{ - t10_lu_common_t *l1 = (t10_lu_common_t *)v1; - t10_lu_common_t *l2 = (t10_lu_common_t *)v2; - int i; - - if (l1->l_guid_len != l2->l_guid_len) { - return ((l1->l_guid_len < l2->l_guid_len) ? -1 : 1); - } - for (i = 0; i < l1->l_guid_len; i++) { - if (l1->l_guid[i] != l2->l_guid[i]) { - return ((l1->l_guid[i] < l2->l_guid[i]) ? -1 : 1); - } - } - return (0); -} - -/* - * []---- - * | find_lu_by_targ -- AVL comparison which looks at the target - * | - * | NOTE: - * | The target value is the memory address of the per target structure. - * | Therefore, it's not persistent in any manner, nor can any association - * | be made between the target value and the initiator. It will be unique - * | however which is all that we're looking for. - * []---- - */ -static int -find_lu_by_targ(const void *v1, const void *v2) -{ - t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1; - t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2; - - if ((uint64_t)(uintptr_t)l1->l_targ < (uint64_t)(uintptr_t)l2->l_targ) - return (-1); - else if ((uint64_t)(uintptr_t)l1->l_targ > - (uint64_t)(uintptr_t)l2->l_targ) - return (1); - else - return (0); -} - -/* - * []---- - * | find_cmd_by_addr -- AVL comparison using the simplist of methods - * []---- - */ -static int -find_cmd_by_addr(const void *v1, const void *v2) -{ - uint64_t cmd1 = (uint64_t)(uintptr_t)v1; - uint64_t cmd2 = (uint64_t)(uintptr_t)v2; - - if (cmd1 < cmd2) - return (-1); - else if (cmd1 > cmd2) - return (1); - else - return (0); -} - -/*ARGSUSED*/ -static Boolean_t -sam_common_init(t10_lu_common_t *t) -{ - assert(0); - return (False); -} - -/*ARGSUSED*/ -static void -sam_common_fini(t10_lu_common_t *t) -{ - assert(0); -} - -#ifdef FULL_DEBUG -static char * -state_to_str(t10_cmd_state_t s) -{ - switch (s) { - case T10_Cmd_S1_Free: return ("FREE"); - case T10_Cmd_S2_In: return ("IN"); - case T10_Cmd_S3_Trans: return ("TRANS"); - case T10_Cmd_S4_AIO: return ("AIO"); - case T10_Cmd_S5_Wait: return ("WAIT"); - case T10_Cmd_S6_Freeing_In: return ("FREEING_IN"); - case T10_Cmd_S7_Freeing_AIO: return ("FREEING_AIO"); - } - return ("Invalid State"); -} -#endif - -static char * -event_to_str(t10_cmd_event_t e) -{ - switch (e) { - case T10_Cmd_T1: return ("T1"); - case T10_Cmd_T2: return ("T2"); - case T10_Cmd_T3: return ("T3"); - case T10_Cmd_T4: return ("T4"); - case T10_Cmd_T5: return ("T5"); - case T10_Cmd_T6: return ("T6"); - case T10_Cmd_T7: return ("T7"); - } - return ("Invalid Event"); -} - -/*ARGSUSED*/ -static void -sam_per_init(t10_lu_impl_t *t) -{ - assert(0); -} - -/*ARGSUSED*/ -static void -sam_per_fini(t10_lu_impl_t *t) -{ - assert(0); -} - -/*ARGSUSED*/ -static void -sam_task_mgmt(t10_lu_common_t *t, TaskOp_t op) -{ - assert(0); -} - -static sam_device_table_t sam_emul_table[] = { - /* 0x00: DTYPE_DIRECT */ - { sbc_common_init, sbc_common_fini, sbc_per_init, sbc_per_fini, - sbc_task_mgmt, TGT_TYPE_DISK }, - /* 0x01: DTYPE_SEQUENTIAL */ - { ssc_common_init, ssc_common_fini, ssc_per_init, ssc_per_fini, - ssc_task_mgmt, TGT_TYPE_TAPE }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - /* 0x11: DTYPE_OSD */ - { osd_common_init, osd_common_fini, osd_per_init, osd_per_fini, - osd_task_mgmt, TGT_TYPE_OSD }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - { sam_common_init, sam_common_fini, sam_per_init, sam_per_fini, - sam_task_mgmt, TGT_TYPE_INVALID }, - /* 0x1f: DTYPE_UNKNOWN */ - { raw_common_init, raw_common_fini, raw_per_init, raw_per_fini, - raw_task_mgmt, TGT_TYPE_RAW }, - /* End-of-Table marker */ - { 0, 0, 0, 0, 0, NULL } -}; diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c deleted file mode 100644 index 33f0da46e2..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.c +++ /dev/null @@ -1,2311 +0,0 @@ -/* - * 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. - */ - -/* - * []------------------------------------------------------------------[] - * | Implementation of SBC-2 emulation | - * []------------------------------------------------------------------[] - */ -#include <sys/types.h> -#include <aio.h> -#include <sys/asynch.h> -#include <sys/mman.h> -#include <stddef.h> -#include <strings.h> -#include <unistd.h> -#include <assert.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/generic/mode.h> -#include <sys/scsi/generic/dad_mode.h> - -#include "t10.h" -#include "t10_spc.h" -#include "t10_spc_pr.h" -#include "t10_sbc.h" -#include "utility.h" - -/* - * External declarations - */ -void sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_cmd_reserve6(t10_cmd_t *, uint8_t *, size_t); -void spc_cmd_release6(t10_cmd_t *, uint8_t *, size_t); -void spc_cmd_pr_in(t10_cmd_t *, uint8_t *, size_t); -void spc_cmd_pr_out(t10_cmd_t *, uint8_t *, size_t); -void spc_cmd_pr_out_data(t10_cmd_t *, emul_handle_t, size_t, char *, size_t); -void spc_pr_read(t10_cmd_t *); -Boolean_t spc_pgr_check(t10_cmd_t *, uint8_t *); -Boolean_t spc_npr_check(t10_cmd_t *, uint8_t *); - -/* - * Forward declarations - */ -static int sbc_mmap_overlap(const void *v1, const void *v2); -static void sbc_overlap_store(disk_io_t *io); -static void sbc_overlap_free(disk_io_t *io); -static void sbc_overlap_check(disk_io_t *io); -static void sbc_overlap_flush(disk_params_t *d); -static void sbc_data(t10_cmd_t *cmd, emul_handle_t e, size_t offset, - char *data, size_t data_len); -static disk_io_t *sbc_io_alloc(t10_cmd_t *c); -static void sbc_io_free(emul_handle_t e); -static void sbc_read_cmplt(emul_handle_t e); -static void sbc_write_cmplt(emul_handle_t e); -static void sbc_read_capacity16(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -static char *sense_page3(disk_params_t *d, char *buf, uint8_t pc); -static char *sense_page4(disk_params_t *d, char *buf, uint8_t pc); -static char *sense_cache(disk_params_t *d, char *buf, uint8_t pc); -static char *sense_mode_control(t10_lu_impl_t *lu, char *buf, uint8_t pc); -static char *sense_info_ctrl(char *buf, uint8_t pc); -static scsi_cmd_table_t lba_table[]; - -static long sbc_page_size; -/* - * []---- - * | sbc_init_common -- Initialize LU data which is common to all I_T_Ls - * []---- - */ -Boolean_t -sbc_common_init(t10_lu_common_t *lu) -{ - disk_params_t *d; - tgt_node_t *node = lu->l_root; - - sbc_page_size = sysconf(_SC_PAGESIZE); - - if ((d = (disk_params_t *)calloc(1, sizeof (*d))) == NULL) - return (False); - - (void) tgt_find_value_int(node, XML_ELEMENT_BPS, - (int *)&d->d_bytes_sect); - (void) tgt_find_value_int(node, XML_ELEMENT_HEADS, - (int *)&d->d_heads); - (void) tgt_find_value_int(node, XML_ELEMENT_SPT, - (int *)&d->d_spt); - (void) tgt_find_value_int(node, XML_ELEMENT_CYLINDERS, - (int *)&d->d_cyl); - (void) tgt_find_value_int(node, XML_ELEMENT_RPM, - (int *)&d->d_rpm); - (void) tgt_find_value_int(node, XML_ELEMENT_INTERLEAVE, - (int *)&d->d_interleave); - d->d_fast_write = lu->l_fast_write_ack; - d->d_size = lu->l_size / (uint64_t)d->d_bytes_sect; - d->d_state = lu->l_state; - - avl_create(&d->d_mmap_overlaps, sbc_mmap_overlap, - sizeof (disk_io_t), offsetof(disk_io_t, da_mmap_overlap)); - (void) pthread_mutex_init(&d->d_mutex, NULL); - (void) pthread_cond_init(&d->d_mmap_cond, NULL); - (void) pthread_cond_init(&d->d_io_cond, NULL); - if ((d->d_io_reserved = (disk_io_t *)calloc(1, sizeof (disk_io_t))) == - NULL) { - free(d); - return (False); - } - - lu->l_dtype_params = (void *)d; - return (True); -} - -void -sbc_common_fini(t10_lu_common_t *lu) -{ - disk_params_t *d = lu->l_dtype_params; - - sbc_overlap_flush(d); - avl_destroy(&d->d_mmap_overlaps); - free(d->d_io_reserved); - free(lu->l_dtype_params); -} - -void -sbc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op) -{ - disk_params_t *d = (disk_params_t *)lu->l_dtype_params; - - switch (op) { - case CapacityChange: - d->d_size = lu->l_size / (uint64_t)d->d_bytes_sect; - break; - - case DeviceOnline: - d->d_state = lu->l_state; - break; - } -} - -/* - * []---- - * | sbc_init_per -- Initialize per I_T_L information - * []---- - */ -void -sbc_per_init(t10_lu_impl_t *itl) -{ - disk_params_t *d = (disk_params_t *)itl->l_common->l_dtype_params; - - if (d->d_state == lu_online) { - itl->l_cmd = sbc_cmd; - itl->l_pgr_read = False; /* Look for PGR data */ - } - else - itl->l_cmd = spc_cmd_offline; - itl->l_data = sbc_data; - itl->l_cmd_table = lba_table; -} - -void -sbc_per_fini(t10_lu_impl_t *itl) -{ -} - -/* - * []---- - * | sbc_cmd -- start a SCSI command - * | - * | This routine is called from within the SAM-3 Task router. - * []---- - */ -void -sbc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cmd_table_t *e; - - /* - * Determine if there is persistent data for this I_T_L Nexus - */ - if (cmd->c_lu->l_pgr_read == False) { - spc_pr_read(cmd); - cmd->c_lu->l_pgr_read = True; - } - - e = &cmd->c_lu->l_cmd_table[cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SBC%x LUN%d Cmd %s id=%p\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name == NULL ? "(no name)" : e->cmd_name, cmd->c_trans_id); -#endif - (*e->cmd_start)(cmd, cdb, cdb_len); -} - -/* - * []---- - * | sbc_cmd_reserve -- Run commands when another I_T_L has a reservation - * []---- - */ -void -sbc_cmd_reserved(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - Boolean_t conflict = False; - - /* - * SPC-3, revision 23, Table 31 - * SPC commands that are allowed in the presence of various reservations - */ - switch (cdb[0]) { - case SCMD_INQUIRY: - case SCMD_LOG_SENSE_G1: - case SCMD_REPORT_LUNS: - case SCMD_REQUEST_SENSE: - case SCMD_MAINTENANCE_IN: /* REPORT TARGET PORT GROUPS (A3h/0Ah) */ - case SCMD_SVC_ACTION_IN_G5: /* READ MEDIA SERIAL NUMBER (ABh) */ - break; - default: - (void) pthread_rwlock_rdlock(&res->res_rwlock); - switch (res->res_type) { - case RT_NONE: - /* conflict = False; */ - break; - case RT_PGR: - conflict = spc_pgr_check(cmd, cdb); - break; - case RT_NPR: - conflict = spc_npr_check(cmd, cdb); - break; - default: - conflict = True; - break; - } - (void) pthread_rwlock_unlock(&res->res_rwlock); - } - - queue_prt(mgmtq, Q_PR_IO, - "PGR%x LUN%d CDB:%s - sbc_cmd_reserved(%s:%s)\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL - ? "(no name)" - : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name, - res->res_type == RT_PGR ? "PGR" : - res->res_type == RT_NPR ? "NPR" : - res->res_type == RT_NONE ? "" : "unknown", - conflict ? "Conflict" : "Allowed"); - - /* - * If no conflict at this point, allow command - */ - if (conflict == False) { - sbc_cmd(cmd, cdb, cdb_len); - } else { - trans_send_complete(cmd, STATUS_RESERVATION_CONFLICT); - } -} - -/* - * []---- - * | sbc_data -- Data phase for command. - * | - * | Normally this is only called for the WRITE command. Other commands - * | that have a data in phase will probably be short circuited when - * | we call trans_rqst_dataout() and the data is already available. - * | At least this is true for iSCSI. FC however will need a DataIn phase - * | for commands like MODE SELECT and PGROUT. - * []---- - */ -static void -sbc_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - scsi_cmd_table_t *e; - - e = &cmd->c_lu->l_cmd_table[cmd->c_cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SBC%x LUN%d Data %s id=%p\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name, cmd->c_trans_id); -#endif - if (*e->cmd_data != NULL) - (*e->cmd_data)(cmd, id, offset, data, data_len); -} - -/* - * []------------------------------------------------------------------[] - * | SCSI Block Commands - 2 | - * | T10/1417-D | - * | The following functions implement the emulation of SBC-2 type | - * | commands. | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | sbc_read -- emulation of SCSI READ command - * []---- - */ -/*ARGSUSED*/ -static void -sbc_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /*LINTED*/ - union scsi_cdb *u = (union scsi_cdb *)cdb; - diskaddr_t addr; - off_t offset = 0; - uint32_t cnt; - uint32_t min; - disk_io_t *io; - void *mmap_data = T10_MMAP_AREA(cmd); - uint64_t err_blkno; - disk_params_t *d; - uchar_t addl_sense_len; - t10_cmd_t *c; - iscsi_cmd_t *iscsi = (iscsi_cmd_t *)T10_TRANS_ID(cmd); - - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - switch (u->scc_cmd) { - case SCMD_READ: - /* - * SBC-2 Revision 16, section 5.5 - * Reserve bit checks - */ - if ((cdb[1] & 0xe0) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - addr = (diskaddr_t)(uint32_t)GETG0ADDR(u); - cnt = GETG0COUNT(u); - - /* - * SBC-2 Revision 16 - * Section: 5.5 READ(6) command - * A TRANSFER LENGTH field set to zero specifies - * that 256 logical blocks shall be read. - */ - if (cnt == 0) - cnt = 256; - break; - - case SCMD_READ_G1: - /* - * SBC-2 Revision 16, section 5.6 - * Reserve bit checks. - */ - if ((cdb[1] & 6) || cdb[6] || - SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - addr = (diskaddr_t)(uint32_t)GETG1ADDR(u); - cnt = GETG1COUNT(u); - break; - - case SCMD_READ_G4: - /* - * SBC-2 Revision 16, section 5.8 - * Reserve bit checks - */ - if ((cdb[1] & 0x6) || cdb[14] || - SAM_CONTROL_BYTE_RESERVED(cdb[15])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - addr = GETG4LONGADDR(u); - cnt = GETG4COUNT(u); - break; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((addr + cnt) > d->d_size) { - - if (addr > d->d_size) - err_blkno = addr; - else - err_blkno = d->d_size; - - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - addl_sense_len = INFORMATION_SENSE_DESCR; - else - addl_sense_len = 0; - - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len); - spc_sense_info(cmd, err_blkno); - spc_sense_ascq(cmd, SPC_ASC_BLOCK_RANGE, SPC_ASCQ_BLOCK_RANGE); - trans_send_complete(cmd, STATUS_CHECK); - - queue_prt(mgmtq, Q_STE_ERRS, - "SBC%x LUN%d READ Illegal sector " - "(0x%llx + 0x%x) > 0x%ullx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - addr, cnt, d->d_size); - return; - } - - cmd->c_lu->l_cmds_read++; - cmd->c_lu->l_sects_read += cnt; - - if (cnt == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - do { - min = MIN((cnt * 512) - offset, T10_MAX_OUT(cmd)); - if ((offset + min) < (cnt * 512LL)) { - c = trans_cmd_dup(cmd); - /* dup failed, just finish the original command */ - if (c == NULL) { - c = cmd; - offset = (cnt * 512); - } - } else { - c = cmd; - } - - (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex); - /* dup count include the original cmd */ - iscsi->c_t10_dup++; - - /* - * Add the cmd to the list of t10 cmds for this iscsi cmd. - * But don't add the original t10 cmd twice. - */ - if (c != cmd) { - c->c_cmd_next = iscsi->c_t10_cmd; - iscsi->c_t10_cmd = c; - } - (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex); - - io = sbc_io_alloc(c); - - io->da_lba = addr; - io->da_lba_cnt = cnt; - io->da_offset = offset; - io->da_data_len = min; - -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SBC%x LUN%d blk 0x%llx, cnt %d, offset 0x%llx, size %d\n", - c->c_lu->l_targ->s_targ_num, c->c_lu->l_common->l_num, - addr, cnt, io->da_offset, min); -#endif - if (mmap_data != MAP_FAILED) { - - io->da_clear_overlap = True; - io->da_data_alloc = False; - io->da_aio.a_aio.aio_return = min; - io->da_data = (char *)mmap_data + (addr * 512LL) + - io->da_offset; - sbc_overlap_store(io); - sbc_read_cmplt((emul_handle_t)io); - - } else { - if ((io->da_data = (char *)malloc(min)) == NULL) { - trans_send_complete(c, STATUS_BUSY); - return; - } - io->da_clear_overlap = False; - io->da_data_alloc = True; - io->da_aio.a_aio_cmplt = sbc_read_cmplt; - io->da_aio.a_id = io; - trans_aioread(c, io->da_data, min, (addr * 512LL) + - (off_t)io->da_offset, &io->da_aio); - } - offset += min; - } while (offset < (off_t)(cnt * 512)); -} - -/* - * []---- - * | sbc_read_cmplt -- Once we have the data, need to send it along. - * []---- - */ -static void -sbc_read_cmplt(emul_handle_t id) -{ - disk_io_t *io = (disk_io_t *)id; - int sense_len; - uint64_t err_blkno; - t10_cmd_t *cmd = io->da_cmd; - Boolean_t last; - - last = (io->da_offset + io->da_data_len) < (io->da_lba_cnt * 512LL) ? - False : True; - - if (io->da_aio.a_aio.aio_return != io->da_data_len) { - err_blkno = io->da_lba + ((io->da_offset + 511) / 512); - cmd->c_resid = (io->da_lba_cnt * 512) - io->da_offset; - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - sense_len = INFORMATION_SENSE_DESCR; - else - sense_len = 0; - spc_sense_create(cmd, KEY_HARDWARE_ERROR, sense_len); - spc_sense_info(cmd, err_blkno); - if (last == True) { - trans_send_complete(cmd, STATUS_CHECK); - sbc_io_free(io); - } else { - t10_cmd_done(cmd); - } - return; - } - - if (trans_send_datain(cmd, io->da_data, io->da_data_len, io->da_offset, - sbc_io_free, last, io) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/* - * []---- - * | sbc_write -- implement a SCSI write command. - * []---- - */ -/*ARGSUSED*/ -static void -sbc_write(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - union scsi_cdb *u; - diskaddr_t addr; - uint64_t err_blkno; - uint32_t cnt; - uchar_t addl_sense_len; - disk_params_t *d; - disk_io_t *io; - size_t max_out; - void *mmap_area; - - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - /*LINTED*/ - u = (union scsi_cdb *)cdb; - - switch (u->scc_cmd) { - case SCMD_WRITE: - /* - * SBC-2 revision 16, section 5.24 - * Reserve bit checks. - */ - if ((cdb[1] & 0xe0) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (diskaddr_t)(uint32_t)GETG0ADDR(u); - cnt = GETG0COUNT(u); - /* - * SBC-2 Revision 16/Section 5.24 WRITE(6) - * A TRANSFER LENGHT of 0 indicates that 256 logical blocks - * shall be written. - */ - if (cnt == 0) - cnt = 256; - break; - - case SCMD_WRITE_G1: - /* - * SBC-2 revision 16, section 5.25 - * Reserve bit checks. - */ - if ((cdb[1] & 0x6) || cdb[6] || - SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (diskaddr_t)(uint32_t)GETG1ADDR(u); - cnt = GETG1COUNT(u); - break; - - case SCMD_WRITE_G4: - /* - * SBC-2 revision 16, section 5.27 - * Reserve bit checks. - */ - if ((cdb[1] & 0x6) || cdb[14] || - SAM_CONTROL_BYTE_RESERVED(cdb[15])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (diskaddr_t)GETG4LONGADDR(u); - cnt = GETG4COUNT(u); - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, "Unprocessed WRITE type\n"); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - - } - - if ((addr + cnt) > d->d_size) { - - if (addr > d->d_size) - err_blkno = addr; - else - err_blkno = d->d_size; - - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - addl_sense_len = INFORMATION_SENSE_DESCR; - else - addl_sense_len = 0; - - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len); - spc_sense_info(cmd, err_blkno); - spc_sense_ascq(cmd, SPC_ASC_BLOCK_RANGE, SPC_ASCQ_BLOCK_RANGE); - trans_send_complete(cmd, STATUS_CHECK); - - queue_prt(mgmtq, Q_STE_ERRS, - "SBC%x LUN%d WRITE Illegal sector " - "(0x%llx + 0x%x) > 0x%ullx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - addr, cnt, d->d_size); - return; - } - - if (cnt == 0) { - queue_prt(mgmtq, Q_STE_NONIO, - "SBC%x LUN%d WRITE zero block count for addr 0x%x\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - addr); - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - io = (disk_io_t *)cmd->c_emul_id; - if (io == NULL) { - io = sbc_io_alloc(cmd); - io->da_lba = addr; - io->da_lba_cnt = cnt; - io->da_clear_overlap = False; - io->da_aio.a_aio_cmplt = sbc_write_cmplt; - io->da_aio.a_id = io; - - /* - * Only update the statistics the first time through - * for this particular command. If the requested transfer - * is larger than the transport can handle this routine - * will be called many times. - */ - cmd->c_lu->l_cmds_write++; - cmd->c_lu->l_sects_write += cnt; - -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SBC%x LUN%d blk 0x%llx, cnt 0x%x\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - addr, cnt); -#endif - } - - /* - * If a transport sets the maximum output value to zero we'll - * just request the entire amount. Otherwise, transfer no more - * than the maximum output or the reminder, whichever is less. - */ - max_out = cmd->c_lu->l_targ->s_maxout; - io->da_data_len = max_out ? MIN(max_out, - (cnt * 512) - io->da_offset) : (cnt * 512); - - mmap_area = T10_MMAP_AREA(cmd); - if (mmap_area != MAP_FAILED) { - - io->da_data_alloc = False; - io->da_data = (char *)mmap_area + (addr * 512LL) + - io->da_offset; - sbc_overlap_check(io); - - } else if ((io->da_data = (char *)malloc(io->da_data_len)) == NULL) { - - trans_send_complete(cmd, STATUS_BUSY); - return; - - } else { - - io->da_data_alloc = True; - } - if (trans_rqst_dataout(cmd, io->da_data, io->da_data_len, - io->da_offset, io, sbc_io_free) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/* - * []---- - * | sbc_write_data -- store a chunk of data from the transport - * []---- - */ -/*ARGSUSED*/ -void -sbc_write_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - disk_io_t *io = (disk_io_t *)id; - disk_params_t *d; - - if (cmd->c_lu->l_common->l_mmap == MAP_FAILED) { - trans_aiowrite(cmd, data, data_len, (io->da_lba * 512) + - (off_t)io->da_offset, &io->da_aio); - } else { - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - if (d->d_fast_write == False) { - uint64_t sa; - size_t len; - - /* - * msync requires the address to be page aligned. - * That means we need to account for any alignment - * loss in the len field and access the full page. - */ - sa = (uint64_t)(intptr_t)data & ~(sbc_page_size - 1); - len = (((size_t)data & (sbc_page_size - 1)) + - data_len + sbc_page_size - 1) & - ~(sbc_page_size -1); - - /* - * We only need to worry about sync'ing the blocks - * in the mmap case because if the fast cache isn't - * enabled for AIO the file will be opened with F_SYNC - * which performs the correct action. - */ - if (msync((char *)(intptr_t)sa, len, MS_SYNC) == -1) { - perror("msync"); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - } - - /* - * Since the data has already been transfered from the - * transport to the mmap area we just need to call - * the complete routine. - */ - sbc_write_cmplt(id); - } -} - -/* - * []---- - * | sbc_write_cmplt -- deal with end game of write - * | - * | See if all of the data for this write operation has been dealt - * | with. If so, send a final acknowledgement back to the transport. - * | If not, update the offset, calculate the next transfer size, and - * | start the process again. - * []--- - */ -static void -sbc_write_cmplt(emul_handle_t e) -{ - disk_io_t *io = (disk_io_t *)e; - t10_cmd_t *cmd = io->da_cmd; - int sense_len; - uint64_t err_blkno; - - if ((cmd->c_lu->l_common->l_mmap == MAP_FAILED) && - (io->da_aio.a_aio.aio_return != io->da_data_len)) { - err_blkno = io->da_lba + ((io->da_offset + 511) / 512); - cmd->c_resid = (io->da_lba_cnt * 512) - io->da_offset; - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - sense_len = INFORMATION_SENSE_DESCR; - else - sense_len = 0; - - spc_sense_create(cmd, KEY_HARDWARE_ERROR, sense_len); - spc_sense_info(cmd, err_blkno); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((io->da_offset + io->da_data_len) < (io->da_lba_cnt * 512)) { - if (io->da_data_alloc == True) { - io->da_data_alloc = False; - free(io->da_data); - } - - io->da_offset += io->da_data_len; - io->da_data_len = MIN(cmd->c_lu->l_targ->s_maxout, - (io->da_lba_cnt * 512) - io->da_offset); - sbc_write(cmd, cmd->c_cdb, cmd->c_cdb_len); - return; - } - trans_send_complete(cmd, STATUS_GOOD); -} - -/*ARGSUSED*/ -void -sbc_startstop(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /* - * SBC-2 revision 16, section 5.17 - * Reserve bit checks - */ - if ((cdb[1] & 0xfe) || cdb[2] || cdb[3] || - (cdb[4] & ~(SBC_PWR_MASK|SBC_PWR_LOEJ|SBC_PWR_START)) || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * More reserve bit checks - */ - switch ((cdb[4] & SBC_PWR_MASK) >> SBC_PWR_SHFT) { - case SBC_PWR_START_VALID: - /* - * It's an error to ask that the media be ejected. - * - * NOTE: Look for method to pass the START bit - * along to underlying storage. If we're asked to - * stop the drive there's not much that we can do - * for the virtual storage, but maybe everything else - * has been requested to stop as well. - */ - if (cdb[4] & SBC_PWR_LOEJ) { - goto send_error; - } - break; - - case SBC_PWR_ACTIVE: - case SBC_PWR_IDLE: - case SBC_PWR_STANDBY: - case SBC_PWR_OBSOLETE: - break; - - case SBC_PWR_LU_CONTROL: - case SBC_PWR_FORCE_IDLE_0: - case SBC_PWR_FORCE_STANDBY_0: - break; - - default: -send_error: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((cdb[1] & 1) == 0) { - /* - * Immediate bit is not set, so go ahead a flush things. - */ - if (cmd->c_lu->l_common->l_mmap == MAP_FAILED) { - if (fsync(cmd->c_lu->l_common->l_fd) != 0) { - spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - } else { - if (msync(cmd->c_lu->l_common->l_mmap, - cmd->c_lu->l_common->l_size, MS_SYNC) == -1) { - spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - } - } - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | sbc_recap -- read capacity of device being emulated. - * []---- - */ -/*ARGSUSED*/ -void -sbc_recap(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - uint64_t capacity; - int len; - uint32_t lba; - struct scsi_capacity *cap; - disk_params_t *d; - disk_io_t *io; - - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - capacity = d->d_size; - - len = sizeof (struct scsi_capacity); - - /* - * SBC-2 Revision 16, section 5.10.1 - * Any of the following conditions will generate an error. - * (1) PMI bit is zero and LOGICAL block address is non-zero - * (2) Rserved bytes are not zero - * (3) Reseved bits are not zero - * (4) Reserved CONTROL bits are not zero - */ - if ((((cdb[8] & SBC_CAPACITY_PMI) == 0) && - (cdb[2] || cdb[3] || cdb[4] || cdb[5])) || - cdb[1] || cdb[6] || cdb[7] || (cdb[8] & ~SBC_CAPACITY_PMI) || - SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * if the device capacity larger than 32 bits then set - * the capacity of the device to all 0xf's. - * a device that supports LBAs larger than 32 bits which - * should be used read_capacity(16) comand to get the capacity. - * NOTE: the adjustment to subject one from the capacity is - * done below. - */ - if (capacity & 0xFFFFFFFF00000000ULL) - capacity = 0xFFFFFFFF; - - io = sbc_io_alloc(cmd); - - if ((cap = (struct scsi_capacity *)calloc(1, len)) == NULL) { - sbc_io_free(io); - trans_send_complete(cmd, STATUS_BUSY); - return; - } - io->da_data = (char *)cap; - io->da_data_alloc = True; - io->da_clear_overlap = False; - io->da_data_len = len; - - if (capacity != 0xFFFFFFFF) { - /* - * Look at the PMI information - */ - if (cdb[8] & SBC_CAPACITY_PMI) { - lba = cdb[2] << 24 | cdb[3] << 16 | - cdb[4] << 8 | cdb[5]; - if (lba >= capacity) - cap->capacity = htonl(0xffffffff); - else - cap->capacity = (capacity - 1); - } else { - cap->capacity = htonl(capacity - 1); - } - } else { - cap->capacity = htonl(capacity); - } - cap->lbasize = htonl(d->d_bytes_sect); - - if (trans_send_datain(cmd, io->da_data, io->da_data_len, 0, - sbc_io_free, True, io) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -void -sbc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - struct mode_header *mode_hdr; - char *np; - disk_params_t *d; - disk_io_t *io; - int rtn_len; - uint8_t pc; - struct block_descriptor bd; - - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - /* - * SPC-3 Revision 21c section 6.8 - * Reserve bit checks - */ - if ((cdb[1] & ~SPC_MODE_SENSE_DBD) || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Zero length causes a simple ack to occur. - */ - if (cdb[4] == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - io = sbc_io_alloc(cmd); - - /* - * Make sure that we have enough room in the data buffer. We'll - * only send back the amount requested though - */ - io->da_data_len = MAX(cdb[4], sizeof (struct mode_format) + - sizeof (struct mode_geometry) + - sizeof (struct mode_control_scsi3) + - sizeof (struct mode_cache_scsi3) + - sizeof (struct mode_info_ctrl) + (MODE_BLK_DESC_LENGTH * 5)); - if ((io->da_data = (char *)calloc(1, io->da_data_len)) == NULL) { - sbc_io_free(io); - trans_send_complete(cmd, STATUS_BUSY); - return; - } - io->da_clear_overlap = False; - io->da_data_alloc = True; - mode_hdr = (struct mode_header *)io->da_data; - - /* - * If DBD flag is set, then we should not send back the block - * descriptor details - */ - if (cdb[1] & SPC_MODE_SENSE_DBD) { - mode_hdr->length = sizeof (struct mode_header) - 1; - mode_hdr->bdesc_length = 0; - } - /* - * If DBD flag is zero, then we should add block descriptor details - */ - else { - /* - * We subtract one from the length because this value is not - * supposed to contain it's size. - */ - - mode_hdr->length = sizeof (struct mode_header) - 1 + - MODE_BLK_DESC_LENGTH; - mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH; - - /* - * Need to fill in the block size. Some initiators are starting - * to use this value, which is correct, instead of looking at - * the page3 data which is starting to become obsolete. - * - * We define the space for the structure on the stack and then - * copy it into the return area to avoid structure alignment - * issues. - */ - bzero(&bd, sizeof (bd)); - bd.blksize_hi = lobyte(hiword(d->d_bytes_sect)); - bd.blksize_mid = hibyte(loword(d->d_bytes_sect)); - bd.blksize_lo = lobyte(loword(d->d_bytes_sect)); - bcopy(&bd, io->da_data + sizeof (*mode_hdr), sizeof (bd)); - } - - /* - * cdb[2] contains page code, and page control field. So, we need - * to mask page control field, while checking for the page code. - * - * Page control specifies whether to report the current, changeable - * default or saved values. This parameter only applies to the - * mode page data itself. From spc-3 section 6.9.1: - * - * "The PC field only affects the mode parameters within the mode - * pages, however the PS, SPF, PAGE CODE field, SUBPAGE CODE field, - * and PAGE LENGTH field should return current values (i.e. as if - * PC is set to 00b). The mode parameter header and mode parameter - * block descriptor should return current values." - * - * Also: "Some SCSI target devices may not distinguish between - * current and saved mode parameters and report identical values - * in response to a PC field of either 0 or 3." Our implementation - * will treat 0 and 3 the same. - */ - pc = (cdb[2] & SPC_MODE_SENSE_PC_MASK) >> SPC_MODE_SENSE_PC_SHIFT; - - switch (cdb[2] & SPC_MODE_SENSE_PAGE_CODE_MASK) { - - case MODE_SENSE_PAGE3_CODE: - if ((d->d_heads == 0) && (d->d_cyl == 0) && (d->d_spt == 0)) { - sbc_io_free(io); - spc_unsupported(cmd, cdb, cdb_len); - return; - } - mode_hdr->length += sizeof (struct mode_format); - (void) sense_page3(d, - io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length, - pc); - break; - - case MODE_SENSE_PAGE4_CODE: - if ((d->d_heads == 0) && (d->d_cyl == 0) && (d->d_spt == 0)) { - sbc_io_free(io); - spc_unsupported(cmd, cdb, cdb_len); - return; - } - mode_hdr->length += sizeof (struct mode_geometry); - (void) sense_page4(d, - io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length, - pc); - break; - - case MODE_SENSE_CACHE: - mode_hdr->length += sizeof (struct mode_cache_scsi3); - (void) sense_cache(d, - io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length, - pc); - break; - - case MODE_SENSE_CONTROL: - mode_hdr->length += sizeof (struct mode_control_scsi3); - (void) sense_mode_control(cmd->c_lu, - io->da_data + sizeof (*mode_hdr) + mode_hdr->bdesc_length, - pc); - break; - - case MODE_SENSE_INFO_CTRL: - mode_hdr->length += sizeof (struct mode_info_ctrl); - (void) sense_info_ctrl(io->da_data + sizeof (*mode_hdr) + - mode_hdr->bdesc_length, pc); - break; - - case MODE_SENSE_SEND_ALL: - /* - * SPC-3 revision 21c - * Section 6.9.1 Table 97 - * "Return all subpage 00h mode pages in page_0 format" - */ - mode_hdr->length += sizeof (struct mode_cache_scsi3) + - sizeof (struct mode_control_scsi3) + - sizeof (struct mode_info_ctrl); - - if (d->d_heads && d->d_cyl && d->d_spt) - mode_hdr->length += sizeof (struct mode_format) + - sizeof (struct mode_geometry); - - np = io->da_data + sizeof (*mode_hdr) + - mode_hdr->bdesc_length; - if (io->da_data_len < (sizeof (struct mode_format) + - sizeof (struct mode_geometry) + - sizeof (struct mode_cache_scsi3) + - sizeof (struct mode_control_scsi3) + - sizeof (struct mode_info_ctrl))) { - - /* - * Believe it or not, there's an initiator out - * there which sends a mode sense request for all - * of the pages, without always sending a data-in - * size which is large enough. - * NOTE: Need to check the error key returned - * here and see if something else should be used. - */ - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - trans_send_complete(cmd, STATUS_CHECK); - - } else { - - /* - * If we don't have geometry then don't attempt - * report that information. - */ - rtn_len = sizeof (*mode_hdr) + mode_hdr->bdesc_length; - if (d->d_heads && d->d_cyl && d->d_spt) { - np = sense_page3(d, np, pc); - np = sense_page4(d, np, pc); - } - np = sense_cache(d, np, pc); - np = sense_mode_control(cmd->c_lu, np, pc); - (void) sense_info_ctrl(np, pc); - } - break; - - case 0x00: - /* - * SPC-3 Revision 21c, section 6.9.1 - * Table 97 -- Mode page code usage for all devices - * Page Code 00 == Vendor specific. We are going to return - * zeros. - */ - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "SBC%x LUN%d Unsupported mode_sense request 0x%x\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - cdb[2]); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - break; - } - - rtn_len = mode_hdr->length + 1; - rtn_len = MIN(rtn_len, cdb[4]); - if (trans_send_datain(cmd, io->da_data, rtn_len, 0, sbc_io_free, - True, io) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -void -sbc_synccache(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /* - * SBC-2 revision 16, section 5.18 - * Reserve bit checks - */ - if ((cdb[1] & ~(SBC_SYNC_CACHE_IMMED|SBC_SYNC_CACHE_NV)) || cdb[6] || - SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - } else { - /* - * SBC-3, revision 16, section 5.18 - * An IMMED bit set to one specifies that the device server - * shall return status as soon as the CDB has been validated. - */ - if (cdb[1] & SBC_SYNC_CACHE_IMMED) { - - /* - * Immediately return a status of GOOD. If an error - * occurs with the fsync/msync the next command will - * pick up an error. - */ - trans_send_complete(cmd, STATUS_GOOD); - if (cmd->c_lu->l_common->l_mmap == MAP_FAILED) { - if (fsync(cmd->c_lu->l_common->l_fd) == -1) { - cmd->c_lu->l_status = - KEY_HARDWARE_ERROR; - cmd->c_lu->l_asc = 0x00; - cmd->c_lu->l_ascq = 0x00; - } - } else { - if (msync(cmd->c_lu->l_common->l_mmap, - cmd->c_lu->l_common->l_size, MS_SYNC) == - -1) { - cmd->c_lu->l_status = - KEY_HARDWARE_ERROR; - cmd->c_lu->l_asc = 0x00; - cmd->c_lu->l_ascq = 0x00; - } - } - } else { - if (cmd->c_lu->l_common->l_mmap == MAP_FAILED) { - if (fsync(cmd->c_lu->l_common->l_fd) == -1) { - spc_sense_create(cmd, - KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } else - trans_send_complete(cmd, STATUS_GOOD); - } else { - if (msync(cmd->c_lu->l_common->l_mmap, - cmd->c_lu->l_common->l_size, MS_SYNC) == - -1) { - spc_sense_create(cmd, - KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - } else - trans_send_complete(cmd, STATUS_GOOD); - } - } - } -} - -/*ARGSUSED*/ -void -sbc_service_actiong4(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - switch (cdb[1] & SPC_GROUP4_SERVICE_ACTION_MASK) { - case SSVC_ACTION_READ_CAPACITY_G4: - sbc_read_capacity16(cmd, cdb, cdb_len); - break; - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x20, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - break; - } -} - -/*ARGSUSED*/ -static void -sbc_read_capacity16(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - uint64_t capacity; - uint64_t lba; - int rep_size; /* response data size */ - struct scsi_capacity_16 *cap16; - disk_params_t *d; - disk_io_t *io; - - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) - return; - - capacity = d->d_size; - /* - * READ_CAPACITY(16) command - */ - rep_size = cdb[10] << 24 | cdb[11] << 16 | cdb[12] << 8 | cdb[13]; - if (rep_size == 0) { - - /* - * A zero length field means we're done. - */ - trans_send_complete(cmd, STATUS_GOOD); - return; - } - rep_size = MIN(rep_size, sizeof (*cap16)); - - /* - * Reserve bit checks. - */ - if ((cdb[1] & ~SPC_GROUP4_SERVICE_ACTION_MASK) || - (cdb[14] & ~SBC_CAPACITY_PMI) || - SAM_CONTROL_BYTE_RESERVED(cdb[15])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - lba = (uint64_t)cdb[2] << 56 | (uint64_t)cdb[3] << 48 | - (uint64_t)cdb[4] << 40 | (uint64_t)cdb[5] << 32 | - (uint64_t)cdb[6] << 24 | (uint64_t)cdb[7] << 16 | - (uint64_t)cdb[8] << 8 | (uint64_t)cdb[9]; - - io = sbc_io_alloc(cmd); - - /* - * We'll malloc enough space for the structure so that we can - * set the values as we place. However, we'll set the transfer - * length to the minimum of the requested size and our structure. - * This is per SBC-2 revision 16, section 5.11.1 regarding - * ALLOCATION LENGTH. - */ - if ((cap16 = (struct scsi_capacity_16 *)calloc(1, sizeof (*cap16))) == - NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - io->da_data = (char *)cap16; - io->da_data_len = rep_size; - io->da_data_alloc = True; - io->da_clear_overlap = False; - - if (cdb[14] & SBC_CAPACITY_PMI) { - if (lba >= capacity) - cap16->sc_capacity = htonll(0xffffffffffffffffULL); - else - cap16->sc_capacity = htonll(capacity - 1); - } else { - cap16->sc_capacity = htonll(capacity - 1); - } - cap16->sc_lbasize = htonl(d->d_bytes_sect); - - if (trans_send_datain(cmd, io->da_data, io->da_data_len, 0, - sbc_io_free, True, io) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -sbc_verify(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /*LINTED*/ - union scsi_cdb *u = (union scsi_cdb *)cdb; - diskaddr_t addr; - uint32_t cnt; - uint32_t chk_size; - uint64_t sz; - uint64_t err_blkno; - Boolean_t bytchk; - char *chk_block; - disk_io_t *io; - disk_params_t *d; - uchar_t addl_sense_len; - - if ((d = (disk_params_t *)T10_PARAMS_AREA(cmd)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - /* - * Check the common reserved bits here and check the CONTROL byte - * in each specific section for the different CDB sizes. - * NOTE: If the VRPROTECT is non-zero we're required by SBC-3 - * to return an error since our emulation code doesn't have - * any protection information stored on the media that we can - * access. - */ - if ((cdb[1] & ~(SBC_VRPROTECT_MASK|SBC_DPO|SBC_BYTCHK)) || - (cdb[1] & SBC_VRPROTECT_MASK)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - bytchk = cdb[1] & SBC_BYTCHK ? True : False; - - switch (u->scc_cmd) { - case SCMD_VERIFY: - /* - * BYTE 6 of the VERIFY(10) contains bits: - * 0-4: Group number -- not supported must be zero - * 5-6: Reserved - * 7 : Restricted for MMC-4 - */ - if (cdb[6] || SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (diskaddr_t)(uint32_t)GETG1ADDR(u); - cnt = GETG1COUNT(u); - break; - - case SCMD_VERIFY_G4: - /* - * See VERIFY(10) above for definitions of what byte 14 - * contains. - */ - if (cdb[14] || SAM_CONTROL_BYTE_RESERVED(cdb[15])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = GETG4LONGADDR(u); - cnt = GETG4COUNT(u); - break; - - case SCMD_VERIFY_G5: - /* - * See VERIFY(10) above for definitions of what byte 10 - * contains. - */ - if (cdb[10] || SAM_CONTROL_BYTE_RESERVED(cdb[11])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - addr = (diskaddr_t)GETG5ADDR(u); - cnt = GETG5COUNT(u); - break; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((addr + cnt) > d->d_size) { - - if (addr > d->d_size) - err_blkno = addr; - else - err_blkno = d->d_size; - - if (err_blkno > FIXED_SENSE_ADDL_INFO_LEN) - addl_sense_len = INFORMATION_SENSE_DESCR; - else - addl_sense_len = 0; - - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, addl_sense_len); - spc_sense_info(cmd, err_blkno); - spc_sense_ascq(cmd, SPC_ASC_BLOCK_RANGE, SPC_ASCQ_BLOCK_RANGE); - trans_send_complete(cmd, STATUS_CHECK); - - queue_prt(mgmtq, Q_STE_ERRS, - "SBC%x LUN%d WRITE Illegal sector " - "(0x%llx + 0x%x) > 0x%ullx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - addr, cnt, d->d_size); - return; - } - - if (bytchk == False) { - /* - * With Byte Check being false all we need to do - * is make sure that we can read the data off of the - * media. - */ - chk_size = 1024 * 1024; - if ((chk_block = malloc(chk_size)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - while (cnt) { - sz = MIN(chk_size, cnt * 512); - /* - * Even if the device is mmap'd in use pread. This - * way we know directly if a read of the data has - * failed. - */ - if (pread(cmd->c_lu->l_common->l_fd, chk_block, sz, - addr * 512LL) != sz) { - spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0); - spc_sense_ascq(cmd, SPC_ASC_DATA_PATH, - SPC_ASCQ_DATA_PATH); - trans_send_complete(cmd, STATUS_CHECK); - free(chk_block); - return; - } - addr += sz / 512LL; - cnt -= sz / 512; - } - free(chk_block); - trans_send_complete(cmd, STATUS_GOOD); - } else { - - io = cmd->c_emul_id; - if (io == NULL) { - io = sbc_io_alloc(cmd); - io->da_lba = addr; - io->da_lba_cnt = cnt; - io->da_clear_overlap = False; - io->da_aio.a_aio_cmplt = sbc_write_cmplt; - io->da_aio.a_id = io; - } - - sz = cmd->c_lu->l_targ->s_maxout; - io->da_data_alloc = True; - io->da_data_len = sz ? MIN(sz, (cnt * 512) - io->da_offset) : - (cnt * 512); - - /* - * Since we're going to just check the data we don't wish - * to possibly change the on disk data. Therefore, even if - * the backing store is mmap'd in we allocate space for the - * data out buffer. - */ - if ((io->da_data = malloc(io->da_data_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - if (trans_rqst_dataout(cmd, io->da_data, io->da_data_len, - io->da_offset, io, sbc_io_free) == False) - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -sbc_verify_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - disk_io_t *io = (disk_io_t *)id; - char *on_disk_buf; - - if ((on_disk_buf = malloc(io->da_data_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - } - - if (pread(cmd->c_lu->l_common->l_fd, on_disk_buf, io->da_data_len, - io->da_offset + (io->da_lba * 512LL)) != io->da_data_len) { - spc_sense_create(cmd, KEY_MISCOMPARE, 0); - spc_sense_ascq(cmd, SPC_ASC_DATA_PATH, SPC_ASCQ_DATA_PATH); - trans_send_complete(cmd, STATUS_CHECK); - free(on_disk_buf); - sbc_io_free(io); - return; - } - if (bcmp(on_disk_buf, io->da_data, io->da_data_len) != 0) { - spc_sense_create(cmd, KEY_MISCOMPARE, 0); - spc_sense_ascq(cmd, SPC_ASC_MISCOMPARE, SPC_ASCQ_MISCOMPARE); - trans_send_complete(cmd, STATUS_CHECK); - free(on_disk_buf); - sbc_io_free(io); - return; - } - free(on_disk_buf); - io->da_offset += io->da_data_len; - if (io->da_offset < (io->da_lba_cnt * 512)) { - if (io->da_data_alloc == True) { - io->da_data_alloc = False; - free(io->da_data); - } - sbc_verify(cmd, cmd->c_cdb, cmd->c_cdb_len); - return; - } - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []------------------------------------------------------------------[] - * | Support related functions for SBC-2 | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | sense_page3 -- Create page3 sense code for Disk. - * | - * | This is a separate routine because this is called in two different - * | locations. - * []---- - */ -static char * -sense_page3(disk_params_t *d, char *buf, uint8_t pc) -{ - struct mode_format mode_fmt; - - bzero(&mode_fmt, sizeof (mode_fmt)); - - /* Page code and page length are always set */ - mode_fmt.mode_page.code = MODE_SENSE_PAGE3_CODE; - mode_fmt.mode_page.length = sizeof (struct mode_format) - - sizeof (struct mode_page); - - /* - * No modifiable values so we report all zeros for - * SPC_PC_MODIFIABLE_VALUES and all other page control values - * result in the same values as SPC_PC_CURRENT_VALUES. - */ - switch (pc) { - case SPC_PC_MODIFIABLE_VALUES: - /* Leave it blank */ - break; - case SPC_PC_CURRENT_VALUES: - case SPC_PC_DEFAULT_VALUES: - case SPC_PC_SAVED_VALUES: - mode_fmt.data_bytes_sect = htons(d->d_bytes_sect); - mode_fmt.sect_track = htons(d->d_spt); - mode_fmt.interleave = htons(d->d_interleave); - break; - } - - bcopy(&mode_fmt, buf, sizeof (mode_fmt)); - - return (buf + sizeof (mode_fmt)); -} - -/* - * []---- - * | sense_page4 -- Create page4 sense code for Disk. - * | - * | This is a separate routine because this is called in two different - * | locations. - * []---- - */ -static char * -sense_page4(disk_params_t *d, char *buf, uint8_t pc) -{ - struct mode_geometry mode_geom; - - bzero(&mode_geom, sizeof (mode_geom)); - - /* Page code and page length are always set */ - mode_geom.mode_page.code = MODE_SENSE_PAGE4_CODE; - mode_geom.mode_page.length = - sizeof (struct mode_geometry) - sizeof (struct mode_page); - - /* - * No modifiable values so we report all zeros for - * SPC_PC_MODIFIABLE_VALUES and all other page control values - * result in the same values as SPC_PC_CURRENT_VALUES. - */ - switch (pc) { - case SPC_PC_MODIFIABLE_VALUES: - /* Leave it blank */ - break; - case SPC_PC_CURRENT_VALUES: - case SPC_PC_DEFAULT_VALUES: - case SPC_PC_SAVED_VALUES: - mode_geom.heads = d->d_heads; - mode_geom.cyl_ub = d->d_cyl >> 16; - mode_geom.cyl_mb = d->d_cyl >> 8; - mode_geom.cyl_lb = d->d_cyl; - mode_geom.rpm = htons(d->d_rpm); - break; - } - - bcopy(&mode_geom, buf, sizeof (mode_geom)); - - return (buf + sizeof (mode_geom)); -} - -static char * -sense_cache(disk_params_t *d, char *buf, uint8_t pc) -{ - struct mode_cache_scsi3 mode_cache; - - bzero(&mode_cache, sizeof (mode_cache)); - - /* Page code and page length are always set */ - mode_cache.mode_page.code = MODE_SENSE_CACHE; - mode_cache.mode_page.length = sizeof (mode_cache) - - sizeof (struct mode_page); - - /* - * No modifiable values so we report all zeros for - * SPC_PC_MODIFIABLE_VALUES and all other page control values - * result in the same values as SPC_PC_CURRENT_VALUES. - * - * Technically wce is modifiable but not by using a mode - * select command. - */ - switch (pc) { - case SPC_PC_MODIFIABLE_VALUES: - /* Leave it blank */ - break; - case SPC_PC_CURRENT_VALUES: - case SPC_PC_DEFAULT_VALUES: - case SPC_PC_SAVED_VALUES: - mode_cache.wce = d->d_fast_write == True ? 1 : 0; - break; - } - - bcopy(&mode_cache, buf, sizeof (mode_cache)); - - return (buf + sizeof (mode_cache)); -} - -/* - * []---- - * | sense_mode_control -- Create mode control page for disk - * []---- - */ -static char * -sense_mode_control(t10_lu_impl_t *lu, char *buf, uint8_t pc) -{ - struct mode_control_scsi3 m; - - bzero(&m, sizeof (m)); - - /* Page code and page length are always set */ - m.mode_page.code = MODE_SENSE_CONTROL; - m.mode_page.length = sizeof (struct mode_control_scsi3) - - sizeof (struct mode_page); - - /* - * D_SENSE is modifiable so we need to reflect this in the - * SPC_PC_MODIFIABLE_VALUES page as well as report the default - * value of '0' in SPC_PC_DEFAULT_VALUES. - */ - switch (pc) { - case SPC_PC_MODIFIABLE_VALUES: - m.d_sense = 1; /* Modifiable */ - break; - case SPC_PC_DEFAULT_VALUES: - m.d_sense = 0; /* Default is disabled */ - m.que_mod = SPC_QUEUE_UNRESTRICTED; - break; - case SPC_PC_CURRENT_VALUES: - case SPC_PC_SAVED_VALUES: - m.d_sense = (lu->l_dsense_enabled == True) ? 1 : 0; - m.que_mod = SPC_QUEUE_UNRESTRICTED; - break; - } - - bcopy(&m, buf, sizeof (m)); - - return (buf + sizeof (m)); -} - -/* - * []---- - * | sense_info_ctrl -- Create mode information control page - * []---- - */ -static char * -sense_info_ctrl(char *buf, uint8_t pc) -{ - struct mode_info_ctrl info; - - bzero(&info, sizeof (info)); - - /* Page code and page length are always set */ - info.mode_page.code = MODE_SENSE_INFO_CTRL; - info.mode_page.length = sizeof (struct mode_info_ctrl) - - sizeof (struct mode_page); - - /* - * No modifiable values so we report all zeros for - * SPC_PC_MODIFIABLE_VALUES and all other page control values - * result in the same values as SPC_PC_CURRENT_VALUES. - */ - switch (pc) { - case SPC_PC_MODIFIABLE_VALUES: - /* Leave it blank */ - break; - case SPC_PC_CURRENT_VALUES: - case SPC_PC_DEFAULT_VALUES: - case SPC_PC_SAVED_VALUES: - break; - } - - bcopy(&info, buf, sizeof (info)); - - return (buf + sizeof (info)); -} - -/* - * []---- - * | sbc_io_alloc -- return a disk_io_t structure - * | - * | If the call to calloc fails we use the structure that was allocate - * | during the initial common initialization call. This will allow the - * | daemon to at least make progress. - * []---- - */ -static disk_io_t * -sbc_io_alloc(t10_cmd_t *c) -{ - disk_io_t *io; - disk_params_t *d = T10_PARAMS_AREA(c); - - if ((io = (disk_io_t *)calloc(1, sizeof (*io))) == NULL) { - (void) pthread_mutex_lock(&d->d_mutex); - if (d->d_io_used == True) { - d->d_io_need = True; - while (d->d_io_used == True) - (void) pthread_cond_wait(&d->d_io_cond, &d->d_mutex); - d->d_io_need = False; - } - d->d_io_used = True; - io = d->d_io_reserved; - (void) pthread_mutex_unlock(&d->d_mutex); - } - - io->da_cmd = c; - io->da_params = d; - /* Enable detecting a change in state of the aio operation */ - io->da_aio.a_aio.aio_return = AIO_INPROGRESS; - /* - * Save the io pointer in the t10 cmd now rather than later. It's - * needed during session shutdown processing to find the aio results - * for determining if libaio has canceled the cmd, in which case - * the cmd needs to be freed. - */ - c->c_emul_id = io; - - return (io); -} - -/* - * []---- - * | sbc_io_free -- free local i/o buffers when transport is finished - * | - * | If the io structure being free is the preallocated buffer see if - * | anyone is waiting for the buffer. If so, wake them up. - * []---- - */ -static void -sbc_io_free(emul_handle_t e) -{ - disk_io_t *io = (disk_io_t *)e; - - if (io->da_clear_overlap == True) - sbc_overlap_free(io); - - if (io->da_data_alloc == True) - free(io->da_data); - - if (io == io->da_params->d_io_reserved) { - (void) pthread_mutex_lock(&io->da_params->d_mutex); - io->da_params->d_io_used = False; - if (io->da_params->d_io_need == True) - (void) pthread_cond_signal(&io->da_params->d_io_cond); - (void) pthread_mutex_unlock(&io->da_params->d_mutex); - } else { - free(io); - } -} - -static int -sbc_mmap_overlap(const void *v1, const void *v2) -{ - disk_io_t *d1 = (disk_io_t *)v1; - disk_io_t *d2 = (disk_io_t *)v2; - - if ((d1->da_data + d1->da_data_len) < d2->da_data) - return (-1); - if (d1->da_data > (d2->da_data + d2->da_data_len)) - return (1); - return (0); -} - -static void -sbc_overlap_store(disk_io_t *io) -{ - disk_params_t *d = io->da_params; - avl_index_t where = 0; - - assert(d != NULL); - - (void) pthread_mutex_lock(&d->d_mutex); - (void) avl_find(&d->d_mmap_overlaps, (void *)io, &where); - avl_insert(&d->d_mmap_overlaps, (void *)io, where); - (void) pthread_mutex_unlock(&d->d_mutex); -} - -static void -sbc_overlap_free(disk_io_t *io) -{ - disk_params_t *d = io->da_params; - - assert(d != NULL); - - (void) pthread_mutex_lock(&d->d_mutex); - avl_remove(&d->d_mmap_overlaps, (void *)io); - if (d->d_mmap_paused == True) { - d->d_mmap_paused = False; - (void) pthread_cond_signal(&d->d_mmap_cond); - } - (void) pthread_mutex_unlock(&d->d_mutex); -} - -static void -sbc_overlap_check(disk_io_t *io) -{ - disk_params_t *d = io->da_params; - - assert(d != NULL); -recheck: - (void) pthread_mutex_lock(&d->d_mutex); - if (avl_find(&d->d_mmap_overlaps, (void *)io, NULL) != NULL) { - d->d_mmap_paused = True; - while (d->d_mmap_paused == True) - (void) pthread_cond_wait(&d->d_mmap_cond, - &d->d_mutex); - - /* - * After waiting on the condition variable the link - * list has changed because someone removed a command. - * So, drop the lock and reexamine the list. - */ - (void) pthread_mutex_unlock(&d->d_mutex); - goto recheck; - } - (void) pthread_mutex_unlock(&d->d_mutex); -} - -/* - * []---- - * | sbc_overlap_flush -- wait until everyone has reported in - * []---- - */ -static void -sbc_overlap_flush(disk_params_t *d) -{ - assert(d != NULL); -recheck: - (void) pthread_mutex_lock(&d->d_mutex); - if (avl_numnodes(&d->d_mmap_overlaps) != 0) { - d->d_mmap_paused = True; - while (d->d_mmap_paused == True) - (void) pthread_cond_wait(&d->d_mmap_cond, - &d->d_mutex); - - /* - * After waiting on the condition variable the link - * list has changed because someone removed a command. - * So, drop the lock and reexamine the list. - */ - (void) pthread_mutex_unlock(&d->d_mutex); - goto recheck; - } - (void) pthread_mutex_unlock(&d->d_mutex); -} - -/* - * []---- - * | Command table for LBA emulation. This is at the end of the file because - * | it's big and ugly. ;-) To make for fast translation to the appropriate - * | emulation routine we just have a big command table with all 256 possible - * | entries. Most will report STATUS_CHECK, unsupport operation. By doing - * | this we can avoid error checking for command range. - * []---- - */ -static scsi_cmd_table_t lba_table[] = { - /* 0x00 -- 0x0f */ - { spc_tur, NULL, NULL, "TEST_UNIT_READY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_request_sense, NULL, NULL, "REQUEST_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_read, NULL, sbc_read_cmplt, "READ" }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_write, sbc_write_data, sbc_write_cmplt, "WRITE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x10 -- 0x1f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_inquiry, NULL, NULL, "INQUIRY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_mselect, spc_mselect_data, NULL, "MODE_SELECT" }, - { spc_cmd_reserve6, NULL, NULL, "RESERVE(6)" }, - { spc_cmd_release6, NULL, NULL, "RELEASE(6)" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_msense, NULL, NULL, "MODE_SENSE" }, - { sbc_startstop, NULL, NULL, "START_STOP" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_send_diag, NULL, NULL, "SEND_DIAG" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x20 -- 0x2f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_recap, NULL, NULL, "READ_CAPACITY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_read, NULL, sbc_read_cmplt, "READ_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_write, sbc_write_data, sbc_write_cmplt, "WRITE_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_verify, sbc_verify_data, NULL, "VERIFY_G1" }, - - /* 0x30 -- 0x3f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_synccache, NULL, NULL, "SYNC_CACHE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x40 -- 0x4f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "LOG_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x50 -- 0x5f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_cmd_pr_in, NULL, NULL, "PERSISTENT_RESERVE_IN" }, - { spc_cmd_pr_out, spc_cmd_pr_out_data, NULL, "PERSISTENT_RESERVE_OUT" }, - - /* 0x60 -- 0x6f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x70 -- 0x7f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x80 -- 0x8f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_read, NULL, sbc_read_cmplt, "READ_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_write, sbc_write_data, sbc_write_cmplt, "WRITE_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_verify, sbc_verify_data, NULL, "VERIFY_G4" }, - - /* 0x90 -- 0x9f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_service_actiong4, NULL, NULL, "SVC_ACTION_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xa0 - 0xaf */ - { spc_report_luns, NULL, NULL, "REPORT_LUNS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_report_tpgs, NULL, NULL, "REPORT_TPGS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { sbc_verify, sbc_verify_data, NULL, "VERIFY_G5" }, - - /* 0xb0 -- 0xbf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xc0 -- 0xcf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xd0 -- 0xdf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xe0 -- 0xef */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xf0 -- 0xff */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, -}; diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h b/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h deleted file mode 100644 index 2a965b1159..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_sbc.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _T10_SBC_H -#define _T10_SBC_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * SBC-2 specific structures and defines - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define SBC_CAPACITY_PMI 0x01 - -#define SBC_SYNC_CACHE_IMMED 0x02 -#define SBC_SYNC_CACHE_NV 0x04 - -/* - * SBC-2 revision 16, section 5.20 - VERIFY command. - * Bits found in the CDB. - */ -/* --- Bits found in byte 1 --- */ -#define SBC_VRPROTECT_MASK 0xe0 -#define SBC_DPO 0x10 -#define SBC_BYTCHK 0x02 -/* --- Bits found in byte 6 --- */ -#define SBC_GROUP_MASK 0x1f - -/* - * SBC-2 revision 16, section 5.17 START_STOP - * Table 49 -- POWER CONDITION field - */ -#define SBC_PWR_MASK 0xf0 -#define SBC_PWR_SHFT 4 -#define SBC_PWR_START_VALID 0x00 -#define SBC_PWR_ACTIVE 0x01 -#define SBC_PWR_IDLE 0x02 -#define SBC_PWR_STANDBY 0x03 -#define SBC_PWR_OBSOLETE 0x05 /* JIST checks this one */ -#define SBC_PWR_LU_CONTROL 0x07 -#define SBC_PWR_FORCE_IDLE_0 0x0a -#define SBC_PWR_FORCE_STANDBY_0 0x0b -#define SBC_PWR_LOEJ 0x02 -#define SBC_PWR_START 0x01 - -typedef struct disk_params { - /* - * Size of LUN in blocks - */ - diskaddr_t d_size; - - /* - * Number of bytes per section. This will probably - * Become vary important for the T10 Data Integrity - * Stuff. - */ - uint32_t d_bytes_sect; - uint32_t d_heads, - d_spt, - d_cyl; - /* - * Another bogus values. - */ - uint32_t d_rpm, - d_interleave; - - /* - * This lock protects access to both the d_mmap_overlaps AVL tree - * and use of the reserved disk_io buffer when memory is exhausted. - */ - pthread_mutex_t d_mutex; - - /* - * When using mmap backing store it's possible for an application - * to issue a read and a write command of the same block without - * first waiting for the read to complete. Since we pass the address - * to the mmap area back to the transport and continue it's possible - * to start processing the write command which will change the data - * before the read has completed. To prevent this condition read - * commands store their data address and length into the avl tree. - * The write command will see if it's potential address is the same - * as one of the read commands. If so, the write command will pause - * until the read completes. - */ - avl_tree_t d_mmap_overlaps; - pthread_cond_t d_mmap_cond; - Boolean_t d_mmap_paused; - - pthread_cond_t d_io_cond; - Boolean_t d_io_need; - Boolean_t d_io_used; - struct disk_io *d_io_reserved; - - Boolean_t d_fast_write; - t10_lu_state_t d_state; - sbc_reserve_t d_sbc_reserve; -} disk_params_t; - -typedef struct disk_io { - /* - * This structure needs to be the first member. The first member - * of this structure is an aio_result_t. If we need to issue - * an aio request a generic handler is called for all aio requests. - * To allow this generic handler a means to callback to the appropriate - * emulation routines a generic header is used. The generic handler - * can cast the pointer returned from aiowait to a t10_aio_t structure. - * From there it can determine the call back routine and pass it - * a specific pointer. - */ - t10_aio_t da_aio; - - /* - * Communication with the SAM-3 layer requires us to send back this - * pointer which was passed in at the command start. - */ - t10_cmd_t *da_cmd; - - /* - * (1) During AIO operations we need to allocate space to hold the - * data. This pointer represents that data which will be freed - * from our callback (argument to trans_send_datain) after the - * transport has finished with it. - * (2) During mmap ops the memory address of the requested data block - * will be stored here along with the transfer size. This will - * be used by the overlap protection to see if we must hold - * off a write op. - */ - char *da_data; - size_t da_data_len; - - /* - * True if da_data has been malloc'd verses mmap and therefore - * we need to free it when the free routine is called. - */ - Boolean_t da_data_alloc; - - /* - * True if an overlap value was stored which needs to be cleared. - */ - Boolean_t da_clear_overlap; - - /* - * If we're breaking up the transfer to comply with max_out - * then da_offset indicates where in the transfer we're currently - * at. - */ - uint64_t da_offset; - - /* - * This is the LBA of a SCSI READ or WRITE command. Once decoded - * from the cdb we don't want to recompute it each time it's needed - * in the different phases. - */ - diskaddr_t da_lba; - size_t da_lba_cnt; - - disk_params_t *da_params; - - /* - * Normal command overlap protection is done by the SAM-3 layer. - * This overlap is to prevent a write op from changing data before - * an existing read op has transmitted the data. - */ - avl_node_t da_mmap_overlap; -} disk_io_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_SBC_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c deleted file mode 100644 index 6910e393a6..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.c +++ /dev/null @@ -1,1198 +0,0 @@ -/* - * 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. - */ - -/* - * []------------------------------------------------------------------[] - * | SPC-3 Support Functions | - * | These routines are not directly called by the SAM-3 layer. Those | - * | who write device emulation modules are free to call these routine | - * | to carry out housekeeping chores. | - * []------------------------------------------------------------------[] - */ - -#include <sys/types.h> -#include <sys/asynch.h> -#include <sys/param.h> -#include <strings.h> -#include <unistd.h> -#include <assert.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/mode.h> -#include <sys/scsi/generic/commands.h> - -#include "t10.h" -#include "t10_spc.h" -#include "target.h" - -void spc_free(emul_handle_t id); - -/* - * []---- - * | spc_unsupported -- generic routine to indicate we don't support this cmd - * []---- - */ -/*ARGSUSED*/ -void -spc_unsupported(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - char debug[80]; - - (void) snprintf(debug, sizeof (debug), - "SAM%d LUN%d Command 0x%x (%s) unsupported\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - cdb[0], cmd->c_lu->l_cmd_table[cdb[0]].cmd_name != NULL ? - cmd->c_lu->l_cmd_table[cdb[0]].cmd_name : "No description"); - queue_str(mgmtq, Q_STE_ERRS, msg_log, debug); - - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, 0x20, 0x00); - trans_send_complete(cmd, STATUS_CHECK); -} - -/* - * []---- - * | spc_tur -- test unit ready - * []---- - */ -/*ARGSUSED*/ -void -spc_tur(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /* - * SPC-3 Revision 21c, section 6.31 - * Reserve bit checks - */ - if (cdb[1] || cdb[2] || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - } else - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | spc_request_sense -- - * []---- - */ -/*ARGSUSED*/ -void -spc_request_sense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /* ---- Check for reserved bit conditions ---- */ - if ((cdb[1] & 0xfe) || cdb[2] || cdb[3] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - } else { - /* - * Since we always run with autosense enabled there's - * no sense data to return. That may change in the future - * if we decide to add such support, but for now return - * success always. - */ - spc_sense_create(cmd, 0, 0); - trans_send_complete(cmd, STATUS_GOOD); - } -} - -/* - * []---- - * | spc_inquiry -- Standard INQUIRY command - * []---- - */ -/*ARGSUSED*/ -void -spc_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - uint8_t *rsp_buf; - uint8_t *rbp; /* temporary var */ - uint8_t evpd; - struct scsi_inquiry *inq; - uint32_t len; - uint32_t page83_len; - uint32_t rqst_len; - uint32_t rtn_len; - struct vpd_hdr *vhp; - struct vpd_desc vd; - size_t scsi_len; - t10_lu_common_t *lu = cmd->c_lu->l_common; - void *v; - uint16_t *vdv; - extended_inq_data_t *eid; - - /* - * Information obtained from: - * SPC-3 Revision 21c - * Section 6.4.1 INQUIRY command - * Need to generate a CHECK CONDITION with ILLEGAL REQUEST - * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is - * true. - * (1) If the EVPD bit is not set, then the page code must be zero. - * (2) If any bit other than EVPD is set. - * (3) If any of the reserved bits in the CONTROL byte are set. - */ - /* - * SPC-3,4 keyword reserved: - * ...Receipts are not required to check reserved bits, bytes, words - * or fields for zero values. - * - * Ignore the check for reserved fields in the CDB byte 1. - */ - evpd = cdb[1] & 1; - if ((evpd == 0 && (cdb[2] != 0)) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - rqst_len = cdb[3] << 8 | cdb[4]; - /* - * Zero length is not an error and we should just acknowledge - * the operation. - */ - if (rqst_len == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - /* - * We send back a total of six Vital Product Data descriptors - * plus associated data. Three are EUI values, two are for AULA - * support being simple 4 byte values, and one is the IQN string. - * NOTE: The IQN string is just an artifact of when the target - * was created. Once FC support is added, the t_name would be - * either a "naa." or "eui." string. - */ - scsi_len = ((strlen(cmd->c_lu->l_targ->s_targ_base) + 1) + 3) & ~3; - page83_len = (sizeof (struct vpd_desc) * 6) + scsi_len + - (lu->l_guid_len * 3) + (sizeof (uint32_t) * 2); - - /* - * We always allocate enough space so that the code can create - * either the full inquiry data or page 0x83 data. - */ - len = sizeof (struct vpd_hdr) + page83_len; - len = max(rqst_len, max(sizeof (*inq), len)); - len = max(len, sizeof (*eid)); - - /* - * Allocate space with an alignment that will work for any casting. - */ - if ((v = memalign(sizeof (void *), len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - bzero(v, len); - rsp_buf = (uint8_t *)v; - - /* - * EVPD not set returns the standard inquiry data. - */ - if (evpd == 0) { - /* - * Return whatever is the smallest amount between the - * INQUIRY data or the amount requested. - * Version descriptor details also should be included - * with the inquiry response. So, rtn_len should consider - * version descriptor details in standard inquiry format - * as per SPC-3 Revision 23, Section 6.4.2 Table 81 - */ - - rtn_len = min(rqst_len, max(sizeof (*inq), - (SPC_INQ_VD_IDX + SPC_INQ_VD_LEN))); - - inq = (struct scsi_inquiry *)rsp_buf; - /* - * SPC-3 Revision 21c, Section 6.4.2 .. Table 82 -- Version - * This target will comply with T10/1416-D - */ - inq->inq_ansi = SPC_INQ_VERS_SPC_3; - - inq->inq_len = sizeof (*inq) - 4; - inq->inq_dtype = lu->l_dtype; - inq->inq_normaca = 0; - inq->inq_rdf = SPC_INQ_RDF; - inq->inq_cmdque = 1; - inq->inq_linked = 0; - - /* - * JIST Requires that we show support for hierarchical - * support (HiSup). - */ - inq->inq_hisup = 1; - - /* - * SPC-4, revision 1a, section 6.4.2 - * Stand INQUIRY Data - * To support MPxIO we enable ALUA support and identify - * all paths to this device as being active/optimized - * we defaults to symmertrical devices. - */ - inq->inq_tpgs = 1; - - (void) snprintf(inq->inq_vid, - sizeof (inq->inq_vid) + sizeof (inq->inq_pid) + - sizeof (inq->inq_revision), "%-8s%-16s%-4s", - lu->l_vid, lu->l_pid, - DEFAULT_REVISION); - - /* - * SPC-3 Revision 21c, section 6.4.2 - * Table 85 -- Version Descriptor values - * Starting at byte 58 there are up to 8 version - * descriptors which are 16bits in size. - * - * NOTE: The ordering of these values is according - * to the standard. First comes the architectural - * version and then followed by: physical transport, - * SCSI transport, primary command set version, and - * finally the device type command set. - */ - vdv = &((uint16_t *)v)[29]; - - /* SAM-3 T10/1561-D rev 14 */ - *vdv++ = htons(SPC_INQ_VD_SAM3); - - /* physical transport code unknown */ - *vdv++ = htons(0x0000); - - *vdv++ = htons(cmd->c_lu->l_targ->s_trans_vers); - - /* SPC ANSI X3.301:1997 */ - *vdv++ = htons(SPC_INQ_VD_SPC3); - - if (lu->l_dtype == DTYPE_DIRECT) { - /* SBC-2 T10/1417-D rev 5a */ - *vdv++ = htons(SPC_INQ_VD_SBC2); - } else if (lu->l_dtype == DTYPE_SEQUENTIAL) { - /* SSC-2 (no version) */ - *vdv++ = htons(SPC_INQ_VD_SSC3); - } else if (lu->l_dtype == DTYPE_OSD) { - /* OSD T10/1355-D revision 10 */ - *vdv++ = htons(SPC_INQ_VD_OSD); - } - - } else { - - /* ---- Common information returned with all page types ---- */ - rsp_buf[0] = lu->l_dtype; - rsp_buf[1] = cdb[2]; - - queue_prt(mgmtq, Q_STE_NONIO, "SPC%d INQUIRY Page%x request\n", - lu->l_num, cdb[2]); - switch (cdb[2]) { - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - - case SPC_INQ_PAGE0: - /* - * SPC-3 Revision 21c Section 7.6.10 - * EVPD page 0 returns information about which pages - * are supported. We support page 0x00 and 0x83. - * NOTE: The value found in byte[3] is the returned - * page length as defined by (n - 3) where 'n' is - * the last valid byte. In this case 5. - */ - rsp_buf[3] = 4; - rsp_buf[4] = SPC_INQ_PAGE0; - rsp_buf[5] = SPC_INQ_PAGE80; - rsp_buf[6] = SPC_INQ_PAGE83; - rsp_buf[7] = SPC_INQ_PAGE86; - - /* - * Return the smallest amount of data between the - * requested amount and the size of the Page83 data. - */ - rtn_len = min(rqst_len, sizeof (struct vpd_hdr) + - rsp_buf[3]); - break; - - case SPC_INQ_PAGE80: - /* - * Return the smallest amount of data between the - * requested amount and the size of the Page80 data. - */ - rtn_len = min(rqst_len, sizeof (struct vpd_hdr) + 4); - rsp_buf[3] = 4; - rsp_buf[4] = 0x20; - rsp_buf[5] = 0x20; - rsp_buf[6] = 0x20; - rsp_buf[7] = 0x20; - break; - - case SPC_INQ_PAGE83: - /* - * Return the smallest amount of data between the - * requested amount and the size of the Page83 data. - */ - rtn_len = min(rqst_len, sizeof (struct vpd_hdr) + - page83_len); - - /* - * Information obtained from: - * SPC-3 Revision 21c - * Section 7.6.4.1 - */ - - /* ---- VPD header ---- */ - vhp = (struct vpd_hdr *)v; - vhp->device_type = lu->l_dtype; - vhp->periph_qual = SPC_INQUIRY_PERIPH_CONN; - vhp->page_code = cdb[2]; - vhp->page_len[0] = hibyte(loword(page83_len)); - vhp->page_len[1] = lobyte(loword(page83_len)); - rbp = (uint8_t *)v + sizeof (*vhp); - - /* ---- VPD descriptor ---- */ - /* - * SPC-4 revision 1a, section 7.6.3.8 - * Target port group designator format - */ - /* initialize descriptor */ - bzero(&vd, sizeof (vd)); - vd.code_set = SPC_INQUIRY_CODE_SET_BINARY; - vd.id_type = SPC_INQUIRY_ID_TYPE_TARG_PORT; - vd.proto_id = SPC_INQUIRY_PROTOCOL_ISCSI; - vd.association = SPC_INQUIRY_ASSOC_TARGPORT; - vd.piv = 1; - vd.len = 4; - bcopy(&vd, rbp, sizeof (vd)); - rbp += sizeof (vd); - - len = SPC_DEFAULT_TPG; - rbp[2] = hibyte(loword(len)); - rbp[3] = lobyte(loword(len)); - rbp += vd.len; - - /* ---- VPD descriptor ---- */ - /* - * SPC-4, revision 1a, section 7.6.3.7 - * Relative target port designator format - */ - vd.code_set = SPC_INQUIRY_CODE_SET_BINARY; - vd.id_type = SPC_INQUIRY_ID_TYPE_RELATIVE; - vd.proto_id = SPC_INQUIRY_PROTOCOL_ISCSI; - vd.association = SPC_INQUIRY_ASSOC_TARGPORT; - vd.piv = 1; - vd.len = 4; - bcopy(&vd, rbp, sizeof (vd)); - rbp += sizeof (vd); - - rbp[2] = hibyte(loword(cmd->c_lu->l_targ->s_tpgt)); - rbp[3] = lobyte(loword(cmd->c_lu->l_targ->s_tpgt)); - rbp += vd.len; - - assert(lu->l_guid != NULL); - /* ---- VPD descriptor ---- */ - vd.code_set = SPC_INQUIRY_CODE_SET_BINARY; - vd.id_type = SUN_INQUIRY_ID_TYPE(lu->l_guid); - vd.proto_id = SPC_INQUIRY_PROTOCOL_ISCSI; - vd.association = SPC_INQUIRY_ASSOC_LUN; - /* - * If the ASSOCIATION field contains a value other - * than 01b or 10b, then the PIV bit contents are - * reserved. SPC-4 revision 11 section 7.6.3.1. - */ - vd.piv = 0; - vd.len = lu->l_guid_len; - bcopy(&vd, rbp, sizeof (vd)); - rbp += sizeof (vd); - - bcopy(lu->l_guid, &rbp[0], lu->l_guid_len); - rbp += lu->l_guid_len; - - /* ---- VPD descriptor ---- */ - vd.code_set = SPC_INQUIRY_CODE_SET_UTF8; - vd.id_type = SPC_INQUIRY_ID_TYPE_SCSI; - vd.proto_id = SPC_INQUIRY_PROTOCOL_ISCSI; - vd.association = SPC_INQUIRY_ASSOC_TARG; - vd.piv = 1; - vd.len = scsi_len; - bcopy(&vd, rbp, sizeof (vd)); - rbp += sizeof (vd); - - /* - * SPC-3 revision 23, section 7.6.3.11 - * Use the string length and not the scsi_len because - * we've rounded up the length to a multiple of four - * as required by the specification. - */ - bcopy(cmd->c_lu->l_targ->s_targ_base, &rbp[0], - strlen(cmd->c_lu->l_targ->s_targ_base)); - rbp += vd.len; - - /* ---- VPD descriptor ---- */ - vd.code_set = SPC_INQUIRY_CODE_SET_BINARY; - vd.id_type = SUN_INQUIRY_ID_TYPE(lu->l_guid); - vd.proto_id = SPC_INQUIRY_PROTOCOL_ISCSI; - vd.association = SPC_INQUIRY_ASSOC_TARG; - vd.piv = 1; - vd.len = lu->l_guid_len; - bcopy(&vd, rbp, sizeof (vd)); - rbp += sizeof (vd); - - /* - * XXX Is this right XXX - * Should we be using some other name. - */ - bcopy(lu->l_guid, &rbp[0], lu->l_guid_len); - rbp += lu->l_guid_len; - - /* ---- VPD descriptor ---- */ - vd.code_set = SPC_INQUIRY_CODE_SET_BINARY; - vd.id_type = SUN_INQUIRY_ID_TYPE(lu->l_guid); - vd.proto_id = SPC_INQUIRY_PROTOCOL_ISCSI; - vd.association = SPC_INQUIRY_ASSOC_TARGPORT; - vd.piv = 1; - vd.len = lu->l_guid_len; - bcopy(&vd, rbp, sizeof (vd)); - rbp += sizeof (vd); - - /* - * XXX Is this right XXX - * Should we be using some other name. - */ - bcopy(lu->l_guid, &rbp[0], lu->l_guid_len); - - /* - * rbp is updated here even though nobody will - * currently use it. Currently is the optertive word - * here. If for some reason we add another VDP - * then the pointer will be correct. - */ - rbp += lu->l_guid_len; - - break; - - case SPC_INQ_PAGE86: - /* - * Return the smallest amount of data between the - * requested amount and the size of the Page86 data. - */ - rtn_len = min(rqst_len, sizeof (*eid)); - eid = (extended_inq_data_t *)v; - eid->ei_hdr.device_type = lu->l_dtype; - eid->ei_hdr.page_code = cdb[2]; - eid->ei_hdr.page_len[1] = 60; /* defined by spec */ - - /* - * At this point in time we don't support any of the - * extended data attributes. We should support - * the task management bits though. - */ - break; - } - } - - if (trans_send_datain(cmd, (char *)rsp_buf, rtn_len, 0, spc_free, - True, rsp_buf) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/* - * []---- - * | spc_mselect -- Generic MODE SELECT command - * []---- - */ -/*ARGSUSED*/ -void -spc_mselect(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - char *buf; - - /* - * SPC-3 revision 21c, section 6.7 - * Reserve bit checks - */ - if ((cdb[1] & 0xee) || cdb[2] || cdb[3] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if (cdb[4] == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - if (((buf = (char *)calloc(1, cdb[4])) == NULL) || - (trans_rqst_dataout(cmd, buf, cdb[4], 0, buf, - spc_free) == False)) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/* - * []---- - * | spc_mselect_data -- DataIn phase of MODE SELECT command - * []---- - */ -/*ARGSUSED*/ -void -spc_mselect_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - struct mode_control_scsi3 mode_ctl_page; - struct mode_header hdr; - - bcopy(data, &hdr, sizeof (hdr)); - bcopy(data + sizeof (hdr) + hdr.bdesc_length, &mode_ctl_page, - sizeof (mode_ctl_page)); - - switch (mode_ctl_page.mode_page.code) { - case MODE_SENSE_CONTROL: - /* - * SPC-3 revision 21c, section 7.4.6 - * Table 239 describes the fields. We're only interested - * in the descriptor sense bit. - */ - if (mode_ctl_page.d_sense == 1) { - cmd->c_lu->l_dsense_enabled = True; - } else { - cmd->c_lu->l_dsense_enabled = False; - } - break; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | spc_report_luns -- - * []---- - */ -/*ARGSUSED*/ -void -spc_report_luns(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - int expected_data; - uint8_t *buf = NULL; - int entries = 0; - int len; - int len_network; - int select; - int lun_idx; - int lun_val; - char *str; - tgt_node_t *targ; - tgt_node_t *lun_list; - tgt_node_t *lun; - - /* - * SPC-3 Revision 21c section 6.21 - * Error checking. - */ - if (cdb[1] || cdb[3] || cdb[4] || - (cdb[2] & ~SPC_RPT_LUNS_SELECT_MASK) || cdb[5] || cdb[10] || - SAM_CONTROL_BYTE_RESERVED(cdb[11])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - expected_data = cdb[6] << 24 | cdb[7] << 16 | cdb[8] << 8 | cdb[9]; - if (expected_data < 16) { - /* - * The allocation length should be at least 16 according - * to SPC-3. - */ - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - select = cdb[2]; - - targ = NULL; - (void) pthread_rwlock_rdlock(&targ_config_mutex); - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &str) == - False) { - goto error; - } - if (strcmp(str, cmd->c_lu->l_targ->s_targ_base) == 0) { - free(str); - break; - } else - free(str); - } - if (!targ) - goto error; - if ((lun_list = tgt_node_next(targ, XML_ELEMENT_LUNLIST, NULL)) == NULL) - goto error; - - lun = NULL; - while ((lun = tgt_node_next(lun_list, XML_ELEMENT_LUN, lun)) != NULL) - entries++; - - - len = entries * SCSI_REPORTLUNS_ADDRESS_SIZE; - if ((buf = (uint8_t *)calloc(1, MAX(expected_data, len))) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - (void) pthread_rwlock_unlock(&targ_config_mutex); - return; - } - - len_network = htonl(len); - bcopy(&len_network, buf, sizeof (len_network)); - - if (expected_data >= (len + SCSI_REPORTLUNS_ADDRESS_SIZE)) { - - lun_idx = SCSI_REPORTLUNS_ADDRESS_SIZE; - lun = NULL; - while ((lun = tgt_node_next(lun_list, XML_ELEMENT_LUN, lun)) != - NULL) { - if (tgt_find_value_int(lun, XML_ELEMENT_LUN, - &lun_val) == False) - goto error; - if (spc_encode_lu_addr(&buf[lun_idx], select, - lun_val) == False) - continue; - lun_idx += SCSI_REPORTLUNS_ADDRESS_SIZE; - } - if (trans_send_datain(cmd, (char *)buf, - len + SCSI_REPORTLUNS_ADDRESS_SIZE, 0, spc_free, True, - buf) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } - } else { - /* - * This will return the size needed to complete this request - * and a implicit LUN zero. - */ - if (trans_send_datain(cmd, (char *)buf, 16, 0, spc_free, True, - buf) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } - } - (void) pthread_rwlock_unlock(&targ_config_mutex); - return; - -error: - (void) pthread_rwlock_unlock(&targ_config_mutex); - if (buf) - free(buf); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); -} - -/*ARGSUSED*/ -void -spc_report_tpgs(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - rtpg_hdr_t *r; - rtpg_desc_t *dp; - rtpg_targ_desc_t *tp; - int rqst_len; - int alloc_len; - int i; - t10_lu_common_t *lu = cmd->c_lu->l_common; - t10_lu_impl_t *lu_per; - - if (disable_tpgs == True) { - spc_unsupported(cmd, cdb, cdb_len); - return; - } - - /* - * Reserve bit checks - */ - if ((cdb[1] & 0xe0) || (cdb[1] & ~SPC_MI_SVC_MASK) || - ((cdb[1] & SPC_MI_SVC_MASK) != SPC_MI_SVC_RTPG) || - cdb[2] || cdb[3] || cdb[4] || cdb[5] || - cdb[10] || SAM_CONTROL_BYTE_RESERVED(cdb[11])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * We only have one target port group which it's size is - * accounted for in rtpg_hdr_t. Take the number of tgts - * and subtract one since the first is accounted for in - * rtpg_targ_desc_t - */ - (void) pthread_mutex_lock(&lu->l_common_mutex); - alloc_len = ((avl_numnodes(&lu->l_all_open) - 1) * - sizeof (rtpg_targ_desc_t)) + sizeof (rtpg_hdr_t); - (void) pthread_mutex_unlock(&lu->l_common_mutex); - - /* - * Make sure that we have enough room to store everything - * that we want to, but only returned the requested about - * of data which is why d->d_len is set to the request amount. - * A client could issue a REPORT_TPGS with a length of 4 bytes - * which would be just enough to see how much space is actually - * used. - */ - rqst_len = cdb[6] << 24 | cdb[7] << 16 | - cdb[8] << 8 | cdb[9]; - - if (rqst_len == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - if ((r = (rtpg_hdr_t *)calloc(1, alloc_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - i = alloc_len - sizeof (r->len); - r->len[0] = hibyte(hiword(i)); - r->len[1] = lobyte(hiword(i)); - r->len[2] = hibyte(loword(i)); - r->len[3] = lobyte(loword(i)); - dp = &r->desc_list[0]; - (void) pthread_mutex_lock(&lu->l_common_mutex); - dp->tpg_cnt = avl_numnodes(&lu->l_all_open); - (void) pthread_mutex_unlock(&lu->l_common_mutex); - dp->status_code = 0; - dp->access_state = 0; /* Active/optimized */ - dp->pref = 1; - dp->t_sup = 1; - dp->u_sup = 1; - dp->s_sup = 1; - dp->an_sup = 0; - dp->ao_sup = 1; - i = SPC_DEFAULT_TPG; - dp->tpg[0] = hibyte(loword(i)); - dp->tpg[1] = lobyte(loword(i)); - - tp = &dp->targ_list[0]; - (void) pthread_mutex_lock(&lu->l_common_mutex); - lu_per = avl_first(&lu->l_all_open); - do { - tp->rel_tpi[0] = hibyte(loword(lu_per->l_targ->s_tpgt)); - tp->rel_tpi[1] = lobyte(loword(lu_per->l_targ->s_tpgt)); - lu_per = AVL_NEXT(&lu->l_all_open, lu_per); - tp++; - } while (lu_per != NULL); - (void) pthread_mutex_unlock(&lu->l_common_mutex); - - if (trans_send_datain(cmd, (char *)r, MIN(rqst_len, alloc_len), 0, - spc_free, True, (char *)r) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -void -spc_send_diag(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - /* - * SPC-3 Revision 21c, section 6.27 - * Reserve bit checks - */ - if ((cdb[1] & ~SPC_SEND_DIAG_SELFTEST) || cdb[2] || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * There's no diagnostics to be run at this time. So, always - * return success. If, at some point in the future, it's determined - * that something can be done which is meaningful then place the - * code here. - */ - trans_send_complete(cmd, STATUS_GOOD); -} - -void -spc_free(emul_handle_t id) -{ - free(id); -} - -/* - * []---- - * | spc_cmd_offline -- return IN_PROGRESS for media related commands - * | - * | During LU initialization the device is in an offline state. When - * | offlined only non-media related commands are allowed to proceed. - * | TEST_UNIT_READY is considered a media command since it must return - * | a CHECK_CONDITION if a media command would do so. - * []---- - */ -void -spc_cmd_offline(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cmd_table_t *e; - int old_dtype; - - e = &cmd->c_lu->l_cmd_table[cdb[0]]; - - switch (cdb[0]) { - case SCMD_TEST_UNIT_READY: - case SCMD_START_STOP: - case SCMD_READ: - case SCMD_READ_G1: - case SCMD_READ_G4: - case SCMD_WRITE: - case SCMD_WRITE_G1: - case SCMD_WRITE_G4: -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SPC%x LUN%d Cmd %s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name == NULL ? "(no name)" : e->cmd_name); -#endif - spc_sense_create(cmd, KEY_NOT_READY, 0); - spc_sense_ascq(cmd, SPC_ASC_IN_PROG, SPC_ASCQ_IN_PROG); - trans_send_complete(cmd, STATUS_CHECK); - break; - - case SCMD_INQUIRY: - /* - * While the device is being initialized any inquiry commands - * will return an unknown device type. This will cause the - * transport to hold off further plumbing until the - * initialization is complete and we send the inventory change - * notice. - */ - old_dtype = cmd->c_lu->l_common->l_dtype; - cmd->c_lu->l_common->l_dtype = 0x1f; - (*e->cmd_start)(cmd, cdb, cdb_len); - cmd->c_lu->l_common->l_dtype = old_dtype; - break; - - default: - (*e->cmd_start)(cmd, cdb, cdb_len); - break; - } -} - -/* - * []---- - * | spc_sense_create -- allocate sense structure - * | - * | If additional header sense length is requested and the I_T_Q has - * | enabled descriptor sense data allocate the space. - * []---- - */ -void -spc_sense_create(t10_cmd_t *cmd, int sense_key, int addl_sense_len) -{ - char *buf; - int size; - - /* - * It's possible under certain conditions -- namely a malloc error - * when setting up a command -- that the pointer to the ITL structure - * isn't valid. If that's the case don't attempt to dereference it - * to look at the dsense_enabled flag. - */ - if ((cmd->c_lu != NULL) && (cmd->c_lu->l_dsense_enabled == True)) { - struct scsi_descr_sense_hdr d; - - if ((buf = (char *)calloc(1, - sizeof (d) + 2 + addl_sense_len)) == NULL) - return; - - size = sizeof (d) + addl_sense_len; - bzero(&d, sizeof (d)); - d.ds_class = CLASS_EXTENDED_SENSE; - d.ds_code = CODE_FMT_DESCR_CURRENT; - d.ds_key = sense_key; - d.ds_addl_sense_length = addl_sense_len; - bcopy(&d, &buf[2], sizeof (d)); - - } else { - struct scsi_extended_sense e; - - if ((buf = (char *)calloc(1, sizeof (e) + 2)) == NULL) - return; - size = sizeof (e); - bzero(&e, sizeof (e)); - e.es_class = CLASS_EXTENDED_SENSE; - e.es_code = CODE_FMT_FIXED_CURRENT; - e.es_key = sense_key; - bcopy(&e, &buf[2], size); - - } - - /* ---- First two bytes of the sense store the length ---- */ - buf[0] = hibyte(loword(size)); - buf[1] = lobyte(loword(size)); - - cmd->c_cmd_sense = buf; - cmd->c_cmd_sense_len = size + 2; -} - -/* - * []---- - * | spc_sense_raw -- copy an existing sense buffer for return. - * | - * | If an emulation module already has a sense buffer there's no need - * | to decode the sense data and call the various spc_sense_ routines - * | to reencode the information. - * []---- - */ -void -spc_sense_raw(t10_cmd_t *cmd, uchar_t *sense_buf, size_t sense_len) -{ - ushort_t s = (ushort_t)sense_len; - if ((cmd->c_cmd_sense = malloc(sense_len + 2)) == NULL) - return; - bcopy(sense_buf, &cmd->c_cmd_sense[2], sense_len); - cmd->c_cmd_sense[0] = hibyte(s); - cmd->c_cmd_sense[1] = lobyte(s); - cmd->c_cmd_sense_len = s + 2; -} - -void -spc_sense_ascq(t10_cmd_t *cmd, int asc, int ascq) -{ - struct scsi_extended_sense s; - struct scsi_descr_sense_hdr d; - - bcopy(&cmd->c_cmd_sense[2], &s, sizeof (s)); - - switch (s.es_code) { - case CODE_FMT_DESCR_CURRENT: - case CODE_FMT_DESCR_DEFERRED: - bcopy(&cmd->c_cmd_sense[2], &d, sizeof (d)); - d.ds_add_code = asc; - d.ds_qual_code = ascq; - bcopy(&d, &cmd->c_cmd_sense[2], sizeof (d)); - break; - - default: - s.es_add_code = asc; - s.es_qual_code = ascq; - bcopy(&s, &cmd->c_cmd_sense[2], sizeof (s)); - break; - } -} - -void -spc_sense_info(t10_cmd_t *cmd, uint64_t info) -{ - struct scsi_information_sense_descr isd; - struct scsi_extended_sense s; - char *p; - uint32_t fixed_info = (uint32_t)info; - - switch (cmd->c_cmd_sense[2] & 0x0f) { - case CODE_FMT_DESCR_CURRENT: - case CODE_FMT_DESCR_DEFERRED: - isd.isd_descr_type = DESCR_INFORMATION; - isd.isd_addl_length = 0x0a; - isd.isd_valid = 1; - isd.isd_information[0] = (info >> 56) & 0xff; - isd.isd_information[1] = (info >> 48) & 0xff; - isd.isd_information[2] = (info >> 40) & 0xff; - isd.isd_information[3] = (info >> 32) & 0xff; - isd.isd_information[4] = (info >> 24) & 0xff; - isd.isd_information[5] = (info >> 16) & 0xff; - isd.isd_information[6] = (info >> 8) & 0xff; - isd.isd_information[7] = info & 0xff; - p = &cmd->c_cmd_sense[2] + sizeof (struct scsi_descr_sense_hdr); - bcopy(&isd, p, sizeof (isd)); - break; - - case CODE_FMT_VENDOR_SPECIFIC: - case CODE_FMT_FIXED_CURRENT: - case CODE_FMT_FIXED_DEFERRED: - default: - bcopy(&cmd->c_cmd_sense[2], &s, sizeof (s)); - - s.es_valid = 1; - if (info > FIXED_SENSE_ADDL_INFO_LEN) { - s.es_info_1 = 0xff; - s.es_info_2 = 0xff; - s.es_info_3 = 0xff; - s.es_info_4 = 0xff; - } else { - s.es_info_1 = hibyte(hiword(fixed_info)); - s.es_info_2 = lobyte(hiword(fixed_info)); - s.es_info_3 = hibyte(loword(fixed_info)); - s.es_info_4 = lobyte(loword(fixed_info)); - } - bcopy(&s, &cmd->c_cmd_sense[2], sizeof (s)); - break; - } -} - -void -spc_sense_flags(t10_cmd_t *cmd, int flags) -{ - struct scsi_extended_sense s; - - bcopy(&cmd->c_cmd_sense[2], &s, sizeof (s)); - if (flags & SPC_SENSE_EOM) - s.es_eom = 1; - if (flags & SPC_SENSE_FM) - s.es_filmk = 1; - if (flags & SPC_SENSE_ILI) - s.es_ili = 1; - bcopy(&s, &cmd->c_cmd_sense[2], sizeof (s)); -} - -/* - * []---- - * | spc_decode_lu_addr -- Decodes LU addressing as specified in SAM-3 - * []---- - */ -Boolean_t -spc_decode_lu_addr(uint8_t *buf, int len, uint32_t *val) -{ - uint32_t lun; - - if (len < 2) - return (False); - - switch (buf[0] & SCSI_REPORTLUNS_ADDRESS_MASK) { - case SCSI_REPORTLUNS_ADDRESS_PERIPHERAL: - case SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE: - lun = ((buf[0] & 0x3f) << 8) | (buf[1] & 0xff); - break; - - /* - * Since we never encode a LUN using this method, we - * shouldn't receive it back. - */ - case SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT: - return (False); - - case SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT: - switch (buf[0] & SCSI_REPORTLUNS_ADDRESS_EXTENDED_MASK) { - case SCSI_REPORTLUNS_ADDRESS_EXTENDED_2B: - lun = buf[1] & 0xff; - break; - - case SCSI_REPORTLUNS_ADDRESS_EXTENDED_4B: - if (len < 4) - return (False); - lun = buf[1] << 16 | buf[2] << 8 | (buf[3] & 0xff); - break; - - case SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B: - if (len < 6) - return (False); - /* - * This should be able to handle a 40-bit LUN, - * but since our LUNs are only 32-bit we don't - * bother to decode buf[1]. This is okay since - * we generate the LUN in the first place. - */ - lun = buf[2] << 24 | buf[3] << 16 | - buf[4] << 8 | (buf[5] & 0xff); - break; - - case SCSI_REPORTLUNS_ADDRESS_EXTENDED_8B: - /* - * Since we current don't support larger than - * 32-bit LUNs we'll never create an extended - * address using this format. So, if we are to - * get this format in, just return an error. - */ - return (False); - - break; - } - } - *val = lun; - return (True); -} - -/* - * []---- - * | spc_encode_lu_addr -- encode, based on SAM-3/SPC-3 specs, a LUN - * | - * | NOTE: This routine only deals with 32-bit logical unit numbers. - * | If this program ever switches to using larger values we need to - * | simply deal with those formats. - * []---- - */ -Boolean_t -spc_encode_lu_addr(uint8_t *buf, int select_field, uint32_t lun) -{ - if (lun < 256) { - - /* - * SAM-3 revision 14, Section 4.9.6. - * No bus identifier for our luns. - */ - buf[0] = SCSI_REPORTLUNS_ADDRESS_PERIPHERAL; - buf[1] = lun; - - } else if (lun <= T10_MAX_LUNS) { - - /* - * SAM-3 revision 14, Section 4.9.7. - * 14-bit flat address space. - */ - buf[0] = SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE | (lun >> 8 & 0x3f); - buf[1] = lun & 0xff; - - } else if (select_field == SCSI_REPORTLUNS_SELECT_ALL) { - - buf[0] = SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT | - SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B; - /* - * 32-bit limitation. This format should be able to - * handle a 40-bit LUN. - */ - buf[1] = 0; - buf[2] = lun >> 24 & 0xff; - buf[3] = lun >> 16 & 0xff; - buf[4] = lun >> 8 & 0xff; - buf[5] = lun & 0xff; - } else - /* - * Either the user hasn't requested extended unit addressing - * or the LU is greater than 32bits. Since internally we - * only have 32bit numbers it's more likely that the initiator - * hasn't selected a correct report format. - */ - return (False); - return (True); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h b/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h deleted file mode 100644 index be93c43e29..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc.h +++ /dev/null @@ -1,460 +0,0 @@ -/* - * 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 _T10_SPC_H -#define _T10_SPC_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * []------------------------------------------------------------------[] - * | SPC-3 | - * []------------------------------------------------------------------[] - */ - -/* - * FIXED_SENSE_ADDL_INFO_LEN is the length of INFORMATION field - * in fixed format sense data - */ -#define FIXED_SENSE_ADDL_INFO_LEN 0xFFFFFFFF -#define INFORMATION_SENSE_DESCR sizeof (struct scsi_information_sense_descr) - -#include <sys/types.h> -#include <netinet/in.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/mode.h> - -/* - * SPC Command Functions - */ -void spc_tur(struct t10_cmd *cmd, uint8_t *cdb, size_t cdb_len); -void spc_request_sense(struct t10_cmd *cmd, uint8_t *cdb, size_t cdb_len); -void spc_unsupported(struct t10_cmd *cmd, uint8_t *cdb, size_t cdb_len); -void spc_inquiry(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_mselect(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_mselect_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, - char *data, size_t data_len); -void spc_report_luns(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_report_tpgs(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_startstop(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_send_diag(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); - -/* - * SPC Support Functions - */ -void spc_cmd_offline(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -void spc_sense_create(struct t10_cmd *cmd, int sense_key, int addl_sense_len); -void spc_sense_ascq(struct t10_cmd *cmd, int asc, int ascq); -void spc_sense_info(t10_cmd_t *cmd, uint64_t info); -void spc_sense_flags(t10_cmd_t *cmd, int flags); -void spc_sense_raw(t10_cmd_t *cmd, uchar_t *sense_buf, size_t sense_len); -Boolean_t spc_decode_lu_addr(uint8_t *buf, int len, uint32_t *val); -Boolean_t spc_encode_lu_addr(uint8_t *buf, int select_field, uint32_t lun); - -/* - * SPC flags to use when setting various sense code flags - */ -#define SPC_SENSE_EOM 0x01 -#define SPC_SENSE_FM 0x02 -#define SPC_SENSE_ILI 0x04 - -/* - * []------------------------------------------------------------------[] - * | SPC-3, revision 21c -- ASC/ASCQ values | - * | The full tables can be found in Appendix D (numerical order) or | - * | section 4.5.6 (alphabetical order). There are close to fifteen | - * | pages of values which will not be included here. Only those used | - * | by the code. | - * []------------------------------------------------------------------[] - */ -#define SPC_ASC_FM_DETECTED 0x00 /* file-mark detected */ -#define SPC_ASCQ_FM_DETECTED 0x01 - -#define SPC_ASC_EOP 0x00 /* end-of-partition/medium detected */ -#define SPC_ASCQ_EOP 0x02 - -#define SPC_ASC_IN_PROG 0x04 -#define SPC_ASCQ_IN_PROG 0x07 - -#define SPC_ASC_WRITE_ERROR 0x0c -#define SPC_ASCQ_WRITE_ERROR 0x00 - -#define SPC_ASC_PARAM_LIST_LEN 0x1a /* Parameter List Length Error */ -#define SPC_ASCQ_PARAM_LIST_LEN 0x00 - -#define SPC_ASC_MISCOMPARE 0x1d -#define SPC_ASCQ_MISCOMPARE 0x00 - -#define SPC_ASC_INVALID_LU 0x20 -#define SPC_ASCQ_INVALID_LU 0x09 - -#define SPC_ASC_BLOCK_RANGE 0x21 -#define SPC_ASCQ_BLOCK_RANGE 0x00 - -#define SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26 -#define SPC_ASCQ_INVALID_FIELD_IN_PARAMETER_LIST 0x00 - -#define SPC_ASC_INVALID_CDB 0x24 -#define SPC_ASCQ_INVALID_CDB 0x00 - -#define SPC_ASC_PARAMETERS_CHANGED 0x2a -#define SPC_ASCQ_RES_PREEMPTED 0x03 -#define SPC_ASCQ_RES_RELEASED 0x04 - -#define SPC_ASC_PWR_RESET 0x29 -#define SPC_ASCQ_PWR_RESET 0x00 - -#define SPC_ASC_PWR_ON 0x29 -#define SPC_ASCQ_PWR_ON 0x01 - -#define SPC_ASC_BUS_RESET 0x29 -#define SPC_ASCQ_BUS_RESET 0x02 - -#define SPC_ASC_CAP_CHANGE 0x2a -#define SPC_ASCQ_CAP_CHANGE 0x09 - -#define SPC_ASC_DATA_PATH 0x41 -#define SPC_ASCQ_DATA_PATH 0x00 - -#define SPC_ASC_MEMORY_OUT_OF 0x55 /* Auxillary Memory Out Of Space */ -#define SPC_ASCQ_MEMORY_OUT_OF 0x00 -#define SPC_ASCQ_RESERVATION_FAIL 0x02 - - -/* - * []------------------------------------------------------------------[] - * | SAM-3, revision 14, section 5.2 - Command descriptor block (CDB) | - * | | - * | "All CDBs shall contain a CONTROL byte (see table 21). The | - * | location of the CONTROL byte within a CDB depends on the CDB | - * | format (see SPC-3)." | - * | | - * | bits meaning | - * | 6-7 vendor specific (we don't use so must be zero) | - * | 3-5 reserved must be zero | - * | 2 NACA (currently we don't support so must be zero) | - * | 1 Obsolete | - * | 0 Link (currently we don't support so must be zero) | - * | | - * | So, this means the control byte must be zero and therefore if | - * | this macro returns a non-zero value the emulation code should | - * | return a CHECK CONDITION with status set to ILLEGAL REQUEST | - * | and the additional sense code set to INVALID FIELD IN CDB. | - * | | - * | In the future this will likely change with support routines | - * | added for dealing with NACA and Linked commands. | - * []------------------------------------------------------------------[] - */ -#define SAM_CONTROL_BYTE_RESERVED(byte) (byte) - -/* ---- Disable Block Descriptors ---- */ -#define SPC_MODE_SENSE_DBD 0x8 - -#define SPC_GROUP4_SERVICE_ACTION_MASK 0x1f - -#define SPC_SEND_DIAG_SELFTEST 0x04 - -/* - * []------------------------------------------------------------------[] - * | SPC-3 revision 21c, section 6.4 -- INQUIRY | - * | Various defines. The structure for the inquiry command can be | - * | found in /usr/include/sys/scsi/generic/inquiry.h | - * []------------------------------------------------------------------[] - */ -#define SPC_INQUIRY_CODE_SET_BINARY 1 -#define SPC_INQUIRY_CODE_SET_ASCII 2 -#define SPC_INQUIRY_CODE_SET_UTF8 3 - -/* ---- Table 82: Inquiry Version ---- */ -#define SPC_INQ_VERS_NONE 0x00 -#define SPC_INQ_VERS_OBSOLETE 0x02 -#define SPC_INQ_VERS_SPC_1 0x03 -#define SPC_INQ_VERS_SPC_2 0x04 -#define SPC_INQ_VERS_SPC_3 0x05 - -/* ---- INQUIRY Response Data Format field ---- */ -#define SPC_INQ_RDF 0x02 /* all other values are OBSOLETE */ - -/* - * Table 85 -- Version descriptor values - * There are many, many different values available, so we'll only include - * those that we actually use. - */ -#define SPC_INQ_VD_SAM3 0x0076 -#define SPC_INQ_VD_SPC3 0x0307 -#define SPC_INQ_VD_SBC2 0x0322 -#define SPC_INQ_VD_SSC3 0x0400 -#define SPC_INQ_VD_OSD 0x0355 - -/* --- Version Descriptor length details --- */ -#define SPC_INQ_VD_IDX 0x3A -#define SPC_INQ_VD_LEN 0x10 - -#define SPC_INQ_PAGE0 0x00 -#define SPC_INQ_PAGE80 0x80 -#define SPC_INQ_PAGE83 0x83 -#define SPC_INQ_PAGE86 0x86 - -/* ---- REPORT LUNS select report has valid values of 0, 1, or 2 ---- */ -#define SPC_RPT_LUNS_SELECT_MASK 0x03 - -/* ---- Table 293: IDENTIFIER TYPE field ---- */ -#define SPC_INQUIRY_ID_TYPE_T10ID 1 /* ref 7.6.4.3 */ -#define SPC_INQUIRY_ID_TYPE_EUI 2 /* ref 7.6.4.4 */ -#define SPC_INQUIRY_ID_TYPE_NAA 3 /* ref 7.6.4.5 */ -#define SPC_INQUIRY_ID_TYPE_RELATIVE 4 /* ref 7.6.4.6 */ -#define SPC_INQUIRY_ID_TYPE_TARG_PORT 5 /* ref 7.6.4.7 */ -#define SPC_INQUIRY_ID_TYPE_LUN 6 /* ref 7.6.4.8 */ -#define SPC_INQUIRY_ID_TYPE_MD5 7 /* ref 7.6.4.9 */ -#define SPC_INQUIRY_ID_TYPE_SCSI 8 /* ref 7.6.4.10 */ - -/* ---- Table 292: ASSOCIATION field ---- */ -#define SPC_INQUIRY_ASSOC_LUN 0 -#define SPC_INQUIRY_ASSOC_TARGPORT 1 -#define SPC_INQUIRY_ASSOC_TARG 2 - -/* ---- Table 80: Peripheral qualifier ---- */ -#define SPC_INQUIRY_PERIPH_CONN 0 -#define SPC_INQUIRY_PERIPH_DISCONN 1 -#define SPC_INQUIRY_PERIPH_INVALID 3 - -/* ---- Table 256: PROTOCOL IDENTIFIER values ---- */ -#define SPC_INQUIRY_PROTOCOL_FC 0 -#define SPC_INQUIRY_PROTOCOL_PSCSI 1 -#define SPC_INQUIRY_PROTOCOL_SSA 2 -#define SPC_INQUIRY_PROTOCOL_IEEE1394 3 -#define SPC_INQUIRY_PROTOCOL_SCSIRDMA 4 -#define SPC_INQUIRY_PROTOCOL_ISCSI 5 -#define SPC_INQUIRY_PROTOCOL_SAS 6 -#define SPC_INQUIRY_PROTOCOL_ADT 7 -#define SPC_INQUIRY_PROTOCOL_ATA 8 - -#define SPC_DEFAULT_TPG 1 - -/* - * SPC-3, revision 21c, section 7.6.5 - * Extended INQUIRY Data VPD page - */ -typedef struct extended_inq_data { - struct vpd_hdr ei_hdr; -#if defined(_BIT_FIELDS_LTOH) - uchar_t ei_ref_chk : 1, - ei_app_chk : 1, - ei_grd_chk : 1, - ei_rto : 1, - ei_rsvd1 : 4; - uchar_t ei_simpsup : 1, - ei_ordsup : 1, - ei_headsup : 1, - ei_prior_sup : 1, - ei_group_sup : 1, - ei_rsvd2 : 3; - uchar_t ei_v_sup : 1, - ei_nv_sup : 1, - ei_rsvd3 : 6; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t ei_ref_rsvd1 : 4, - ei_rto : 1, - ei_grd_chk : 1, - ei_app_chk : 1, - ei_ref_chk : 1; - uchar_t ei_rsvd2 : 2, - ei_group_sup : 1, - ei_prior_sup : 1, - ei_headsup : 1, - ei_ordsup : 1, - ei_simpsup : 1; - uchar_t ei_rsvd3 : 6, - ei_nv_sup : 1, - ei_v_sup : 1; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t ei_rsv4[57]; -} extended_inq_data_t; - - -/* - * []------------------------------------------------------------------[] - * | SPC-4 revision 1a, section 6.25 -- REPORT TARGET PORT GROUPS | - * | Structures and defines | - * []------------------------------------------------------------------[] - */ -/* - * The service action must be set to 0x0A. This command is really a - * MAINTENANCE_IN command with a specific service action. - */ -#define SPC_MI_SVC_MASK 0x1f -#define SPC_MI_SVC_RTPG 0x0a - -/* ---- Table 167: Target port descriptor format ---- */ -typedef struct rtpg_targ_desc { - uchar_t obsolete[2], - rel_tpi[2]; -} rtpg_targ_desc_t; - -/* ---- Table 164: Target port group descript format ---- */ -typedef struct rtpg_desc { -#if defined(_BIT_FIELDS_LTOH) - uchar_t access_state : 4, - : 3, - pref : 1; - uchar_t ao_sup : 1, - an_sup : 1, - s_sup : 1, - u_sup : 1, - : 3, - t_sup : 1; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t pref : 1, - : 3, - access_state : 4; - uchar_t t_sup : 1, - : 3, - u_sup : 1, - s_sup : 1, - an_sup : 1, - ao_sup : 1; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t tpg[2], - reserve_1, - status_code, - vendor_spec, - tpg_cnt; - rtpg_targ_desc_t targ_list[1]; -} rtpg_desc_t; - -/* ---- Table 163: parameter data format. ---- */ -typedef struct rtpg_data { - uchar_t len[4]; - rtpg_desc_t desc_list[1]; -} rtpg_hdr_t; - -/* - * []------------------------------------------------------------------[] - * | SPC-3, revision 21c, section 6.6 -- LOG_SENSE | - * | Structure and defines | - * []------------------------------------------------------------------[] - */ -#define SSC_LOG_SP 0x01 /* save parameters */ -#define SSC_LOG_PPC 0x02 /* parameter pointer control */ -#define SPC_LOG_PAGE_MASK 0x3f - -/* ---- section 7.2.1, Table 192: Log Parameter ---- */ -typedef struct spc_log_select_param { - char param_code[2]; -#if defined(_BIT_FIELDS_LTOH) - char lp : 1, /* list parameter */ - lbin : 1, - tmc : 2, /* threshold met criteria */ - etc : 1, /* enable threshold comparison */ - tsd : 1, /* target save disable */ - ds : 1, /* disable save */ - du : 1; /* disable update */ -#elif defined(_BIT_FIELDS_HTOL) - char du : 1, /* disable update */ - ds : 1, /* disable save */ - tsd : 1, /* target save disable */ - etc : 1, /* enable threshold comparison */ - tmc : 2, /* threshold met criteria */ - lbin : 1, - lp : 1; /* list parameter */ -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - char len; /* length of bytes to follow */ -} spc_log_select_param_t; - -/* ---- section 7.2.12, table 218: Supported log pages ---- */ -typedef struct spc_log_supported_pages { - char page_code, - resvd, - length[2], - list[1]; -} spc_log_supported_pages_t; - -/* - * []------------------------------------------------------------------[] - * | SPC-3, revision 21c, section 6.9 -- MODE_SENSE | - * | Structures and defines | - * []------------------------------------------------------------------[] - */ -/* ---- Section 7.4.6, Table 241: Queue Algorithm Modifer field ---- */ -#define SPC_QUEUE_RESTRICTED 0x00 -#define SPC_QUEUE_UNRESTRICTED 0x01 - -/* ---- Section 7.4.11, Table 250: Information Controller Page ---- */ -struct mode_info_ctrl { - struct mode_page mode_page; - /* - * Currently we don't sent any of this information and it's set - * to zero's. We only care about the size. - */ - char info_data[10]; -}; - -#define MODE_SENSE_PAGE3_CODE 0x03 -#define MODE_SENSE_PAGE4_CODE 0x04 -#define MODE_SENSE_CACHE 0x08 -#define MODE_SENSE_CONTROL 0x0a -#define MODE_SENSE_COMPRESSION 0x0f -#define MODE_SENSE_DEV_CONFIG 0x10 -#define MODE_SENSE_INFO_CTRL 0x1c -#define MODE_SENSE_SEND_ALL 0x3f - -/* -- Page Control Mask for Mode Sense -- */ -#define SPC_MODE_SENSE_PAGE_CODE_MASK 0x3f -#define SPC_MODE_SENSE_PC_MASK 0xc0 -#define SPC_MODE_SENSE_PC_SHIFT 6 - -#define SPC_PC_CURRENT_VALUES 0 -#define SPC_PC_MODIFIABLE_VALUES 1 -#define SPC_PC_DEFAULT_VALUES 2 -#define SPC_PC_SAVED_VALUES 3 - -#define SCSI_REPORTLUNS_ADDRESS_SIZE 8 -#define SCSI_REPORTLUNS_ADDRESS_MASK 0xC0 -#define SCSI_REPORTLUNS_ADDRESS_PERIPHERAL 0x00 -#define SCSI_REPORTLUNS_ADDRESS_FLAT_SPACE 0x40 -#define SCSI_REPORTLUNS_ADDRESS_LOGICAL_UNIT 0x80 -#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_UNIT 0xC0 -#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_2B 0x00 -#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_4B 0x10 -#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_6B 0x20 -#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_8B 0x30 -#define SCSI_REPORTLUNS_ADDRESS_EXTENDED_MASK 0x30 -#define SCSI_REPORTLUNS_SELECT_ALL 0x02 - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_SPC_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c deleted file mode 100644 index 7ee28c34ee..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c +++ /dev/null @@ -1,2126 +0,0 @@ -/* - * 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. - */ - -/* - * []------------------------------------------------------------------[] - * | Implementation of SPC-3 Persistent Reserve emulation | - * []------------------------------------------------------------------[] - */ -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/asynch.h> -#include <sys/param.h> -#include <sys/sysmacros.h> -#include <strings.h> -#include <unistd.h> -#include <pthread.h> -#include <assert.h> - -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/generic/inquiry.h> -#include <sys/scsi/generic/mode.h> -#include <sys/scsi/generic/commands.h> -#include <sys/scsi/generic/persist.h> - -#include "t10.h" -#include "t10_spc.h" -#include "t10_spc_pr.h" -#include "t10_sbc.h" -#include "target.h" - -/* - * External declarations - */ -extern target_queue_t *mgmtq; -void spc_free(emul_handle_t id); -void sbc_cmd(t10_cmd_t *, uint8_t *, size_t); -void sbc_cmd_reserved(t10_cmd_t *, uint8_t *, size_t); - -/* - * Forward declarations - */ -static spc_pr_key_t *spc_pr_key_find(scsi3_pgr_t *, uint64_t, char *, char *); -static spc_pr_key_t *spc_pr_key_alloc(scsi3_pgr_t *, uint64_t, char *, char *); -static spc_pr_rsrv_t *spc_pr_rsrv_find(scsi3_pgr_t *, uint64_t, char *, char *); -static spc_pr_rsrv_t *spc_pr_rsrv_alloc(scsi3_pgr_t *, uint64_t, char *, char *, - uint8_t, uint8_t); - -static void spc_pr_key_free(scsi3_pgr_t *, spc_pr_key_t *); -static void spc_pr_rsrv_free(scsi3_pgr_t *, spc_pr_rsrv_t *); -static void spc_pr_rsrv_release(t10_cmd_t *, scsi3_pgr_t *, spc_pr_rsrv_t *); - -static int spc_pr_out_register(t10_cmd_t *, void *, size_t); -static int spc_pr_out_reserve(t10_cmd_t *, void *, size_t); -static int spc_pr_out_release(t10_cmd_t *, void *, size_t); -static int spc_pr_out_clear(t10_cmd_t *, void *, size_t); -static int spc_pr_out_preempt(t10_cmd_t *, void *, size_t); -static int spc_pr_out_register_and_move(t10_cmd_t *, void *, size_t); - -static int spc_pr_in_readkeys(char *, scsi3_pgr_t *, void *, uint16_t); -static int spc_pr_in_readrsrv(char *, scsi3_pgr_t *, void *, uint16_t); -static int spc_pr_in_repcap(char *, scsi3_pgr_t *, void *, uint16_t); -static int spc_pr_in_fullstat(char *, scsi3_pgr_t *, void *, uint16_t); - -Boolean_t spc_pr_write(t10_cmd_t *); -static void spc_pr_erase(scsi3_pgr_t *); -static void spc_pr_initialize(scsi3_pgr_t *); - -/* - * []---- - * | spc_pgr_is_conflicting - * | PGR reservation conflict checking. - * | SPC-3, Revision 23, Table 31 - * []---- - */ -static int -spc_pgr_is_conflicting(uint8_t *cdb, uint_t type) -{ - Boolean_t conflict = False; - - switch (cdb[0]) { - case SCMD_FORMAT: - case SCMD_EXTENDED_COPY: - case SCMD_LOG_SELECT_G1: - case SCMD_MODE_SELECT: - case SCMD_MODE_SELECT_G1: - case SCMD_MODE_SENSE: - case SCMD_MODE_SENSE_G1: - case SCMD_READ_ATTRIBUTE: - case SCMD_READ_BUFFER: - case SCMD_GDIAG: /* SCMD_RECEIVE_DIAGNOSTIC_RESULTS */ - case SCMD_SDIAG: /* SCMD_SEND_DIAGNOSTIC_RESULTS */ - case SCMD_WRITE_ATTRIBUTE: - case SCMD_WRITE_BUFFER: - conflict = True; - break; - - case SCMD_DOORLOCK: /* SCMD_PREVENT_ALLOW_MEDIA_REMOVAL */ - /* - * As per SPC-3, Revision 23, Table 31 - * (prevent <> 0) - */ - conflict = (cdb[4] & 0x1) ? True: False; - break; - - case SCMD_MAINTENANCE_IN: /* SCMD_REPORT_ */ - /* - * As per SPC-3, Revision 23, Section 6.23 - */ - switch ((cdb[1] & 0x1f)) { - case SSVC_ACTION_GET_SUPPORTED_OPERATIONS: - case SSVC_SCTION_GET_SUPPORTED_MANAGEMENT: - - conflict = True; - break; - } - break; - - case SCMD_MAINTENANCE_OUT: - /* - * SPC-3, Revision 23, Section 6.29 - */ - switch ((cdb[1] & 0x1F)) { - case SSVC_ACTION_SET_DEVICE_IDENTIFIER: - case SSVC_ACTION_SET_PRIORITY: - case SSVC_ACTION_SET_TARGET_PORT_GROUPS: - case SSVC_ACTION_SET_TIMESTAMP: - conflict = True; - break; - } - break; - - case SCMD_READ: - case SCMD_READ_G1: - case SCMD_READ_G4: - /* - * Exclusive Access, and EA Registrants Only - */ - if (type == PGR_TYPE_EX_AC || type == PGR_TYPE_EX_AC_RO) - conflict = True; - break; - } - - return (conflict); -} - -/* - * []---- - * | spc_npr_check -- NON-PERSISTENT RESERVE check of I_T_L - * | Refer to SPC-2, Section 5.5.1, Tables 10 - * []---- - */ -Boolean_t -spc_npr_check(t10_cmd_t *cmd, uint8_t *cdb) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - Boolean_t conflict = False; - - /* - * If a logical unit has been reserved by any RESERVE command and - * is still reserved by any initiator, all PERSISTENT RESERVE IN - * and all PRESISTENT RESERVE OUT commands shall conflict regardless - * of initiator or service action and shall terminate with a - * RESERVATION CONLICT status. SPC-2 section 5.5.1. - */ - if ((cdb[0] == SCMD_PERSISTENT_RESERVE_IN) || - (cdb[0] == SCMD_PERSISTENT_RESERVE_OUT) || - (res->res_owner != cmd->c_lu)) { - conflict = True; - } - - queue_prt(mgmtq, Q_PR_IO, - "NPR%x LUN%d CDB:%s - spc_npr_check(Reservation:%s)\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL - ? "(no name)" - : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name, - (conflict) ? "Conflict" : "Allowed"); - - return (conflict); -} - -/* - * []---- - * | spc_pgr_check -- PERSISTENT_RESERVE {IN|OUT} check of I_T_L - * | Refer to SPC-3, Section 5.6.1, Tables 31 - * []---- - */ -Boolean_t -spc_pgr_check(t10_cmd_t *cmd, uint8_t *cdb) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv = NULL; - Boolean_t conflict = False; - - /* - * If no reservations exist, allow all remaining command types. - */ - assert(res->res_type == RT_PGR); - if ((cdb[0] == SCMD_PERSISTENT_RESERVE_IN) || - (cdb[0] == SCMD_TEST_UNIT_READY) || - (pgr->pgr_numrsrv == 0)) { - conflict = False; - goto done; - } - - /* - * If a logical unit has executed a PERSISTENT RESERVE OUT command - * with the REGISTER or REGISTER AND IGNORE EXISTING KEY service - * action and is still registered by any initiator, all RESERVE - * commands and all RELEASE commands regardless of initiator shall - * conflict and shall terminate with a RESERVATION CONFLICT status. - * SPC-2 section 5.5.1. - * - * CRH bit 0, no support for exception defined in - * SPC-3 section 5.6.3. - */ - if ((cdb[0] == SCMD_RESERVE) || - (cdb[0] == SCMD_RELEASE)) { - conflict = True; - goto done; - } - - /* - * At this point we know there is at least one reservation. - * If there is no reservation set on this service delivery - * port then conflict all remaining command types. - */ - if (!(rsrv = spc_pr_rsrv_find(pgr, 0, "", T10_PGR_TNAME(cmd)))) { - queue_prt(mgmtq, Q_PR_ERRS, "PGR%x Reserved on other port\n", - "\t%s:%s\n", cmd->c_lu->l_targ->s_targ_num, - T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); - conflict = True; - goto done; - } - - /* - * Check the command against the reservation type for this port. - */ - switch (rsrv->r_type) { - case PGR_TYPE_WR_EX: /* Write Exclusive */ - case PGR_TYPE_EX_AC: /* Exclusive Access */ - if (strcmp(T10_PGR_INAME(cmd), rsrv->r_i_name) == 0) - conflict = False; - else - conflict = spc_pgr_is_conflicting(cdb, - rsrv->r_type); - break; - case PGR_TYPE_WR_EX_RO: /* Write Exclusive, Registrants Only */ - case PGR_TYPE_EX_AC_RO: /* Exclusive Access, Registrants Only */ - if (spc_pr_key_find( - pgr, 0, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd))) - conflict = False; - else - conflict = spc_pgr_is_conflicting(cdb, - rsrv->r_type); - break; - case PGR_TYPE_WR_EX_AR: /* Write Exclusive, All Registrants */ - case PGR_TYPE_EX_AC_AR: /* Exclusive Access, All Registrants */ - if (spc_pr_key_find(pgr, 0, "", T10_PGR_TNAME(cmd))) - conflict = False; - else - conflict = spc_pgr_is_conflicting(cdb, - rsrv->r_type); - break; - default: - conflict = True; - break; - } - -done: - queue_prt(mgmtq, Q_PR_IO, "PGR%x LUN%d CDB:%s - spc_pgr_check(%s:%s)\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL - ? "(no name)" - : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name, - (rsrv == NULL) - ? "<none>" - : (rsrv->r_type == PGR_TYPE_WR_EX) - ? "Write Exclusive" - : (rsrv->r_type == PGR_TYPE_EX_AC) - ? "Exclusive Access" - : (rsrv->r_type == PGR_TYPE_WR_EX_RO) - ? "Write Exclusive, Registrants Only" - : (rsrv->r_type == PGR_TYPE_EX_AC_RO) - ? "Exclusive Access, Registrants Only" - : (rsrv->r_type == PGR_TYPE_WR_EX_AR) - ? "Write Exclusive, All Registrants" - : (rsrv->r_type == PGR_TYPE_EX_AC_AR) - ? "Exclusive Access, All Registrants" - : "Uknown reservation type", - (conflict) ? "Conflict" : "Allowed"); - - return (conflict); -} - -/* - * []---- - * | spc_cmd_reserve6 -- RESERVE(6) command - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_reserve6(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - t10_lu_impl_t *lu; - - if (cdb[1] & 0xe0 || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - (void) pthread_rwlock_wrlock(&res->res_rwlock); - /* - * The ways to get in here are, - * 1) to be the owner of the reservation (SPC-2 section 7.21.2) - * 2) reservation not applied, nobody is the owner. - */ - if (res->res_owner != cmd->c_lu) { - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - if (lu != cmd->c_lu) - lu->l_cmd = sbc_cmd_reserved; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - res->res_owner = cmd->c_lu; - } - res->res_type = RT_NPR; - (void) pthread_rwlock_unlock(&res->res_rwlock); - - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | spc_cmd_release6 -- RELEASE(6) command - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_release6(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - t10_lu_impl_t *lu; - - if (cdb[1] & 0xe0 || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - (void) pthread_rwlock_wrlock(&res->res_rwlock); - /* - * The ways to get in here are, - * 1) to be the owner of the reservation - * 2) reservation not applied, nobody is the owner. - */ - if (res->res_owner != NULL) { - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - res->res_owner = NULL; - res->res_type = RT_NONE; - } - (void) pthread_rwlock_unlock(&res->res_rwlock); - - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | spc_cmd_pr_in -- PERSISTENT_RESERVE IN - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_pr_in(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cdb_prin_t *p_prin = (scsi_cdb_prin_t *)cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - uint16_t alen; - size_t len = 0; - void *buf; - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11 PERSISTENCE RESERVE IN - * Need to generate a CHECK CONDITION with ILLEGAL REQUEST - * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is - * true. - * (1) The SERVICE ACTION field is 004h - 01fh, - * (2) The reserved area in byte 1 is set, - * (3) The reserved area in bytes 2 thru 6 are set, - * (4) If any of the reserved bits in the CONTROL byte are set. - */ - if ((p_prin->action >= 0x4) || p_prin->resbits || p_prin->resbytes[0] || - p_prin->resbytes[1] || p_prin->resbytes[2] || p_prin->resbytes[3] || - p_prin->resbytes[4] || p_prin->control) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11 PERSISTENCE RESERVE IN - * Acquire ALLOCATION LENGTH from bytes 7, 8 - * A zero(0) length allocation is not an error and we should just - * acknowledge the operation. - */ - if ((alen = SCSI_READ16(p_prin->alloc_len)) == 0) { - queue_prt(mgmtq, Q_PR_ERRS, - "PGR%x LUN%d CDB:%s - spc_cmd_pr_in, len = 0\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name == NULL - ? "(no name)" - : cmd->c_lu->l_cmd_table[cmd->c_cdb[0]].cmd_name); - - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - /* - * Allocate space with an alignment that will work for any casting. - */ - if ((buf = memalign(sizeof (void *), alen)) == NULL) { - /* - * Lack of memory is not fatal, just too busy - */ - trans_send_complete(cmd, STATUS_BUSY); - return; - } else { - bzero(buf, alen); - } - - /* - * Start processing, lock reservation - */ - (void) pthread_rwlock_rdlock(&res->res_rwlock); - - queue_prt(mgmtq, Q_PR_NONIO, "PGR%x LUN%d action:%s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - (p_prin->action == PR_IN_READ_KEYS) - ? "Read keys" - : (p_prin->action == PR_IN_READ_RESERVATION) - ? "Read reservation" - : (p_prin->action == PR_IN_REPORT_CAPABILITIES) - ? "Report capabilties" - : (p_prin->action == PR_IN_READ_FULL_STATUS) - ? "Read full status" - : "Uknown"); - - /* - * Per SPC-3, Revision 23, Table 102, validate ranget of service actions - */ - switch (p_prin->action) { - case PR_IN_READ_KEYS: - len = spc_pr_in_readkeys( - T10_PGR_TNAME(cmd), pgr, buf, alen); - break; - case PR_IN_READ_RESERVATION: - len = spc_pr_in_readrsrv( - T10_PGR_TNAME(cmd), pgr, buf, alen); - break; - case PR_IN_REPORT_CAPABILITIES: - len = spc_pr_in_repcap( - T10_PGR_TNAME(cmd), pgr, buf, alen); - break; - case PR_IN_READ_FULL_STATUS: - len = spc_pr_in_fullstat( - T10_PGR_TNAME(cmd), pgr, buf, alen); - break; - } - - /* - * Complete processing, unlock reservation - */ - (void) pthread_rwlock_unlock(&res->res_rwlock); - - /* - * Now send the selected Persistent Reservation response back - */ - if (trans_send_datain(cmd, buf, len, 0, spc_free, True, buf) == False) - trans_send_complete(cmd, STATUS_BUSY); -} - -/* - * []---- - * | spc_pr_in_readkey - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_in_readkeys(char *transportID, scsi3_pgr_t *pgr, void *bp, - uint16_t alloc_len) -{ - int i = 0, max_buf_keys, hsize; - scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp; - spc_pr_key_t *key; - - hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); - max_buf_keys = ((int)alloc_len - hsize) / sizeof (key->k_key); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGRIN readkeys - transportID=%s\n", transportID); - - if (pgr->pgr_numkeys) - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - if (strcmp(key->k_transportID, transportID)) - continue; - - if (i < max_buf_keys) { - SCSI_WRITE64(&buf->key_list.service_key[i], key->k_key); - queue_prt(mgmtq, Q_PR_NONIO, - "PGRIN readkeys - key:%016lx, i_name:%s\n", - key->k_key, key->k_i_name); - i++; - } - else - break; /* No room left, leave now */ - } - - SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); - SCSI_WRITE32(buf->add_len, pgr->pgr_numkeys * sizeof (key->k_key)); - - return (hsize + min(i, max_buf_keys) * sizeof (key->k_key)); -} - -/* - * []---- - * | spc_pr_in_readresv - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_in_readrsrv( - char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) -{ - int i = 0, max_buf_rsrv, hsize; - scsi_prin_readrsrv_t *buf = (scsi_prin_readrsrv_t *)bp; - scsi_prin_rsrvdesc_t *desc; - spc_pr_rsrv_t *rsrv; - - hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); - max_buf_rsrv = ((int)alloc_len - hsize) / sizeof (scsi_prin_rsrvdesc_t); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGRIN readrsrv - transportID=%s\n", transportID); - - if (pgr->pgr_numrsrv) - for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { - - if (strcmp(rsrv->r_transportID, transportID)) - continue; - - if (i < max_buf_rsrv) { - desc = &buf->key_list.res_key_list[i]; - SCSI_WRITE64(desc->reservation_key, rsrv->r_key); - desc->scope = rsrv->r_scope; - desc->type = rsrv->r_type; - - queue_prt(mgmtq, Q_PR_NONIO, - "PGRIN readrsrv - " - "key:%016lx i_name:%s scope:%d type:%d \n", - rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - - i++; - } - else - break; /* No room left, leave now */ - } - - SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); - SCSI_WRITE32(buf->add_len, - pgr->pgr_numrsrv * sizeof (scsi_prin_rsrvdesc_t)); - - return (hsize + min(i, max_buf_rsrv)* sizeof (scsi_prin_rsrvdesc_t)); -} - -/* - * []---- - * | spc_pr_in_repcap - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* - */ -static int -spc_pr_in_repcap( - char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) -{ - scsi_prin_rpt_cap_t *buf = (scsi_prin_rpt_cap_t *)bp; - - buf->crh = 1; /* Support Reserve/Release Exceptions */ - buf->sip_c = 1; /* Specify Initiator Ports Capable */ - buf->atp_c = 1; /* All Target Ports Capable */ - buf->ptpl_c = 1; /* Persist Through Power Loss C */ - buf->tmv = 1; /* Type Mask Valid */ - buf->ptpl_a = pgr_persist; /* Persist Though Power Loss Active */ - buf->pr_type.wr_ex = 1; /* Write Exclusve */ - buf->pr_type.ex_ac = 1; /* Exclusive Access */ - buf->pr_type.wr_ex_ro = 1; /* Write Exclusive Registrants Only */ - buf->pr_type.ex_ac_ro = 1; /* Exclusive Access Registrants Only */ - buf->pr_type.wr_ex_ar = 1; /* Write Exclusive All Registrants */ - buf->pr_type.ex_ac_ar = 1; /* Exclusive Access All Registrants */ - - SCSI_WRITE16(buf->length, sizeof (scsi_prin_rpt_cap_t)); - - return (sizeof (scsi_prin_rpt_cap_t)); -} - -/* - * []---- - * | spc_pr_in_fullstat - - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* - */ -static int -spc_pr_in_fullstat( - char *transportID, scsi3_pgr_t *pgr, void *bp, uint16_t alloc_len) -{ - int i = 0, max_buf_rsrv, hsize; - spc_pr_rsrv_t *rsrv; - scsi_prin_full_status_t *buf = (scsi_prin_full_status_t *)bp; - iscsi_transport_id_t *tptid; - - hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len); - max_buf_rsrv = ((int)alloc_len - hsize) / - sizeof (scsi_prin_full_status_t); - - if (pgr->pgr_numrsrv) - for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd) { - - if (i < max_buf_rsrv) { - SCSI_WRITE64(buf->full_desc[i].reservation_key, - rsrv->r_key); - buf->full_desc[i].all_tg_pt = 1; - buf->full_desc[i].r_holder = - strcmp(rsrv->r_transportID, transportID) ? 0 : 1; - buf->full_desc[i].scope = rsrv->r_scope; - buf->full_desc[i].type = rsrv->r_type; - SCSI_WRITE16(buf->full_desc[i].rel_tgt_port_id, 0); - SCSI_WRITE32(buf->full_desc[i].add_len, - sizeof (iscsi_transport_id_t)); - buf->full_desc[i].trans_id.protocol_id = - iSCSI_PROTOCOL_ID; - buf->full_desc[i].trans_id.format_code = - WW_UID_DEVICE_NAME; - tptid = (iscsi_transport_id_t *) - &(buf->full_desc[i].trans_id); - SCSI_WRITE16(tptid->add_len, 0); - (void) sprintf(tptid->iscsi_name, ""); - i++; - } - else - break; /* No room left, leave now */ - - } - - SCSI_WRITE32(buf->PRgeneration, pgr->pgr_generation); - SCSI_WRITE32(buf->add_len, i * sizeof (scsi_prin_rsrvdesc_t)); - - return (hsize + min(i, max_buf_rsrv) * sizeof (scsi_prin_rsrvdesc_t)); - -} - -/* - * []---- - * | spc_cmd_pr_out -- PERSISTENT_RESERVE OUT - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_pr_out(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cdb; - size_t len; - void *buf; - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12 PERSISTENCE RESERVE OUT - * Need to generate a CHECK CONDITION with ILLEGAL REQUEST - * and INVALID FIELD IN CDB (0x24/0x00) if any of the following is - * true. - * (1) The SERVICE ACTION field is 008h - 01fh, - * (2) The reserved area in byte 1 is set, - * (3) The TYPE and SCOPE fields are invalid, - * (4) The reserved area in bytes 3 and 4 are set, - * (5) If any of the reserved bits in the CONTROL byte are set. - */ - if ((p_prout->action >= 0x8) || p_prout->resbits || - (p_prout->type >= 0x9) || - (p_prout->scope >= 0x3) || p_prout->control) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.12 PERSISTENCE RESERVE OUT - * Acquire ALLOCATION LENGTH from bytes 5 thru 8 - */ - len = SCSI_READ32(p_prout->param_len); - - /* - * Parameter list length shall contain 24 (0x18), - * the SPEC_I_PIT is zero (it is because we don't support SIP_C)) - * the service action is not REGISTER AND MOVE - */ - if ((p_prout->action != PR_OUT_REGISTER_MOVE) && (len != 24)) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_PARAM_LIST_LEN, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Information obtained from: - * SPC-3, Revision 23 - * Section 6.11.3.3 Persistent Reservation Scope - * SCOPE field shall be set to LU_SCOPE - */ - if (p_prout->scope != PR_LU_SCOPE) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Allocate space with an alignment that will work for any casting. - */ - if ((buf = memalign(sizeof (void *), len)) == NULL) { - /* - * Lack of memory is not fatal, just too busy - */ - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - /* - * Now request the Persistent Reserve OUT parameter list - */ - if (trans_rqst_dataout(cmd, buf, len, 0, buf, spc_free) == False) - trans_send_complete(cmd, STATUS_BUSY); -} - -/* - * []---- - * | spc_cmd_pr_out_data -- DataIn phase of PERSISTENT_RESERVE OUT command - * []---- - */ -/*ARGSUSED*/ -void -spc_cmd_pr_out_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - t10_lu_impl_t *lu; - int status; - - /* - * If this is the first time using the persistence data, - * initialize the reservation and resource key queues - */ - (void) pthread_rwlock_wrlock(&res->res_rwlock); - if (pgr->pgr_rsrvlist.lnk_fwd == NULL) { - spc_pr_initialize(pgr); - } - - queue_prt(mgmtq, Q_PR_NONIO, "PGR%x LUN%d action:%s\n", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - (p_prout->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) - ? "Register & ignore existing key" - : (p_prout->action == PR_OUT_REGISTER) - ? "Register" - : (p_prout->action == PR_OUT_RESERVE) - ? "Reserve" - : (p_prout->action == PR_OUT_RELEASE) - ? "Release" - : (p_prout->action == PR_OUT_CLEAR) - ? "Clear" - : (p_prout->action == PR_OUT_PREEMPT_ABORT) - ? "Preempt & abort" - : (p_prout->action == PR_OUT_PREEMPT) - ? "Preempt" - : (p_prout->action == PR_OUT_REGISTER_MOVE) - ? "Register & move" - : "Uknown"); - - /* - * Now process the action. - */ - switch (p_prout->action) { - case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY: - case PR_OUT_REGISTER: - /* - * PR_OUT_REGISTER_IGNORE differs from PR_OUT_REGISTER - * in that the reservation_key is ignored. - */ - status = spc_pr_out_register(cmd, data, data_len); - break; - - case PR_OUT_RESERVE: - status = spc_pr_out_reserve(cmd, data, data_len); - break; - - case PR_OUT_RELEASE: - status = spc_pr_out_release(cmd, data, data_len); - break; - - case PR_OUT_CLEAR: - status = spc_pr_out_clear(cmd, data, data_len); - break; - - case PR_OUT_PREEMPT_ABORT: - case PR_OUT_PREEMPT: - /* - * PR_OUT_PREEMPT_ABORT differs from PR_OUT_PREEMPT - * in that all current acitivy for the preempted - * Initiators will be terminated. - */ - status = spc_pr_out_preempt(cmd, data, data_len); - break; - - case PR_OUT_REGISTER_MOVE: - /* - * PR_OUT_REGISTER_MOVE registers a key for another I_T - */ - status = spc_pr_out_register_and_move(cmd, data, data_len); - break; - } - - /* - * Check status of action performed. - */ - if (status == STATUS_CHECK) { - /* - * Check condition required. - */ - (void) pthread_rwlock_unlock(&res->res_rwlock); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, cmd->c_lu->l_asc, cmd->c_lu->l_ascq); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Handle Failed processing status - */ - if (status != STATUS_GOOD) { - (void) pthread_rwlock_unlock(&res->res_rwlock); - trans_send_complete(cmd, status); - return; - } - - /* - * Successful, bump the PRgeneration value - */ - if (p_prout->action != PR_OUT_RESERVE && - p_prout->action != PR_OUT_RELEASE) - pgr->pgr_generation++; - - /* - * If Activate Persist Through Power Loss (APTPL) is set, persist - * this PGR data on disk - */ - if (plist->aptpl || pgr->pgr_aptpl) - (void) spc_pr_write(cmd); - - /* - * When the last registration is removed, PGR is no longer - * active and we must reset the reservation type. - */ - if ((pgr->pgr_numkeys == 0) && (pgr->pgr_numrsrv == 0)) { - res->res_type = RT_NONE; - pgr->pgr_aptpl = 0; - } else { - res->res_type = RT_PGR; - } - - /* - * Set the command dispatcher according to the reservation type - */ - (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = (res->res_type == RT_NONE) - ? sbc_cmd : sbc_cmd_reserved; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - (void) pthread_mutex_unlock(&cmd->c_lu->l_common->l_common_mutex); - - /* - * Processing is complete, release mutex - */ - (void) pthread_rwlock_unlock(&res->res_rwlock); - - /* - * Send back a succesful response - */ - trans_send_complete(cmd, STATUS_GOOD); -} - -/* - * []---- - * | spc_pr_out_register - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_out_register(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - spc_pr_key_t *key; - uint64_t reservation_key; - uint64_t service_key; - t10_lu_impl_t *lu; - t10_targ_impl_t *ti; - - /* - * Validate Persistent Reserver Out parameter list - */ - if (plist->obsolete1[0] || plist->obsolete1[1] || - plist->obsolete1[2] || plist->obsolete1[3] || - plist->resbits1 || plist->resbits2 || plist->resbytes1 || - plist->obsolete2[0] || plist->obsolete2[1]) { - cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; - cmd->c_lu->l_asc = SPC_ASC_INVALID_CDB; - cmd->c_lu->l_ascq = 0; - return (STATUS_CHECK); - } - - /* - * Determine if Activate Persist Trhough Power Loss (APTPL) - * is valid for this device server. - */ - if (plist->aptpl && (pgr_persist == 0)) { - /* pgr - define SCSI-3 error codes */ - cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; - cmd->c_lu->l_asc = SPC_ASC_INVALID_FIELD_IN_PARAMETER_LIST; - cmd->c_lu->l_ascq = 0; - return (STATUS_CHECK); - } - - /* - * Get reservation values - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGR%x LUN%d register reservation:%016lx, key:%016lx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - reservation_key, service_key); - - /* - * We may need register all initiators, depending on ALL_TG_TP - */ - (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - /* - * Find specified key - */ - ti = lu->l_targ; - key = spc_pr_key_find(pgr, 0, ti->s_i_name, ti->s_targ_base); - if (key) { - /* - * What about ALL_TG_TP? - */ - if (plist->all_tg_pt || - (strcmp(key->k_i_name, T10_PGR_INAME(cmd)) == 0)) { - - if (p_prout->action == PR_OUT_REGISTER && - key->k_key != reservation_key) { - /* - * The Initiator did not specify the - * existing key. Reservation conflict. - */ - return (STATUS_RESERVATION_CONFLICT); - } - /* - * Change existing key ? - */ - if (service_key) { - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT: change " - "old:%016lx = new:%016lx\n", - key->k_key, service_key); - - /* - * Overwrite (change) key - */ - key->k_key = service_key; - - } else { - /* - * Remove existing key - * NOTE: If we own the reservation then - * we must release it. - */ - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT: delete " - "old:%016lx = new:%016lx\n", - key->k_key, service_key); - - rsrv = spc_pr_rsrv_find(pgr, 0, - ti->s_i_name, ti->s_targ_base); - if (rsrv) { - spc_pr_rsrv_release( - cmd, pgr, rsrv); - } - spc_pr_key_free(pgr, key); - } - } - } else { - /* - * What about ALL_TG_TP? - */ - if (plist->all_tg_pt || - (strcmp(ti->s_i_name, T10_PGR_INAME(cmd)) == 0)) { - /* - * Process request from un-registered Initiator. - */ - if ((p_prout->action == PR_OUT_REGISTER) && - (reservation_key || service_key == 0)) { - /* - * Unregistered initiator is attempting - * to modify a key. - */ - return (STATUS_RESERVATION_CONFLICT); - } - - key = spc_pr_key_alloc(pgr, service_key, - ti->s_i_name, ti->s_targ_base); - if (key == NULL) { - /* pgr - define SCSI-3 error codes */ - cmd->c_lu->l_status = - KEY_ABORTED_COMMAND; - cmd->c_lu->l_asc = - SPC_ASC_MEMORY_OUT_OF; - cmd->c_lu->l_ascq = - SPC_ASCQ_RESERVATION_FAIL; - return (STATUS_CHECK); - } - } - } - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - (void) pthread_mutex_unlock(&cmd->c_lu->l_common->l_common_mutex); - - /* - * Apply the last valid APTPL bit - * SPC-3, Revision 23 - * Section 5.6.4.1 Preserving persistent reservervations and - * registrations through power loss - */ - pgr->pgr_aptpl = plist->aptpl; - - return (STATUS_GOOD); -} - -/* - * []---- - * | spc_pr_out_reserve - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* ARGSUSED */ -static int -spc_pr_out_reserve(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - uint64_t service_key; - int status; - - /* - * Do not allow an unregistered initiator to - * make a reservation. - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGR%x LUN%d reserve reservation:%016lx, key:%016lx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - reservation_key, service_key); - - if (!spc_pr_key_find( - pgr, reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd))) { - - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT: reserve service:%016lx not found\n", - reservation_key); - - return (STATUS_RESERVATION_CONFLICT); - } - - /* - * See if there is a reservation on this port by - * another Initiator. There can be only one LU_SCOPE - * reservation per ITL. We do not support extents. - */ - if (rsrv = spc_pr_rsrv_find(pgr, 0, "", T10_PGR_TNAME(cmd))) { - if (strcmp(rsrv->r_i_name, T10_PGR_INAME(cmd)) != 0) { - - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT: reserve %s != %s:%s\n", rsrv->r_i_name, - T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); - - return (STATUS_RESERVATION_CONFLICT); - } - } - - /* - * At this point there is either no reservation or the - * reservation is held by this Initiator. - */ - if (rsrv != NULL) { - - /* - * An Initiator cannot re-reserve. It must first - * release. But if its' type and scope match then - * return STATUS_GOOD. - */ - if (rsrv->r_type == p_prout->type && - rsrv->r_scope == p_prout->scope) { - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT reserve - transportID=%s\n" - "\tkey:%016lx i_name:%s scope:%d type:%d \n", - rsrv->r_transportID, rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - status = STATUS_GOOD; - } else { - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT reserve failed - transportID=%s\n" - "\tkey:%016lx i_name:%s scope:%d type:%d \n", - rsrv->r_transportID, rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - status = STATUS_RESERVATION_CONFLICT; - } - } else { - /* - * No reservation exists. Establish a new one. - */ - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT reserve - transportID=%s\n" - "\tkey:%016lx i_name:%s scope:%d type:%d \n", - T10_PGR_TNAME(cmd), reservation_key, T10_PGR_INAME(cmd), - p_prout->scope, p_prout->type); - - rsrv = spc_pr_rsrv_alloc(pgr, reservation_key, - T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd), - p_prout->scope, p_prout->type); - if (rsrv == NULL) { - cmd->c_lu->l_status = KEY_ABORTED_COMMAND; - cmd->c_lu->l_asc = SPC_ASC_MEMORY_OUT_OF; - cmd->c_lu->l_ascq = SPC_ASCQ_RESERVATION_FAIL; - status = STATUS_CHECK; - } else { - status = STATUS_GOOD; - } - } - - return (status); -} - -/* - * []---- - * | spc_pr_out_release - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_out_release(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_rsrv_t *rsrv; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - uint64_t service_key; - int status; - - /* - * Do not allow an unregistered initiator to - * make a reservation. - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGR%x LUN%d release reservation:%016lx, key:%016lx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - reservation_key, service_key); - - if (!spc_pr_key_find( - pgr, reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd))) { - - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT: release service:%016lx not found\n", - reservation_key); - - return (STATUS_RESERVATION_CONFLICT); - } else { - - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT: release service:%016lx\n", service_key); - } - - /* - * Releasing a non-existent reservation is allowed. - */ - if (!(rsrv = spc_pr_rsrv_find( - pgr, 0, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)))) { - - status = STATUS_GOOD; - - } else if (p_prout->scope != rsrv->r_scope || - p_prout->type != rsrv->r_type || - reservation_key != rsrv->r_key) { - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT release failed - transportID=%s\n" - "\tkey:%016lx i_name:%s scope:%d type:%d \n", - T10_PGR_TNAME(cmd), reservation_key, T10_PGR_INAME(cmd), - p_prout->scope, p_prout->type); - - /* - * Scope and key must match to release. - */ - cmd->c_lu->l_status = KEY_ILLEGAL_REQUEST; - cmd->c_lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - cmd->c_lu->l_ascq = SPC_ASCQ_RES_RELEASED; - status = STATUS_CHECK; - } else { - /* - * Now release the reservation. - */ - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT release - transportID=%s\n" - "\tkey:%016lx i_name:s scope:%d type:%d \n", - rsrv->r_transportID, rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - - spc_pr_rsrv_release(cmd, pgr, rsrv); - status = STATUS_GOOD; - } - - return (status); -} - -/* - * []---- - * | spc_pr_out_preempt - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* ARGSUSED */ -static int -spc_pr_out_preempt(t10_cmd_t *cmd, void *data, size_t data_len) -{ - scsi_cdb_prout_t *p_prout = (scsi_cdb_prout_t *)cmd->c_cdb; - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - uint64_t service_key; - spc_pr_key_t *key, *key_next; - spc_pr_rsrv_t *rsrv, *rsrv_next; - t10_lu_impl_t *lu; - int status = STATUS_GOOD; - - /* - * Get reservation values - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGR%x LUN%d preempt reservation:%016lx, key:%016lx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - reservation_key, service_key); - - /* - * Service key (preempt key) must exist, and - * Initiator must be registered - */ - if (spc_pr_key_find(pgr, service_key, "", "") == NULL || - spc_pr_key_find(pgr, reservation_key, T10_PGR_INAME(cmd), "") == - NULL) { - - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT: preempt failed reservation:%016lx, key:%016lx\n", - reservation_key, service_key); - - return (STATUS_RESERVATION_CONFLICT); - } - - /* - * Preempt all keys matching service action key and free - * the associated structures. Do not set UNIT_ATTN for - * the Initiator which requested the action. - * - * Unlike the other Persistent Reservation commands, the preempt, - * preempt_and_abort and clear actions are service delivery port - * independent. So we remove matching keys across ports. - */ - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key_next) { - - Boolean_t unit_attn; - - /* - * Get next pointer in case the key gets deallocated - */ - key_next = (spc_pr_key_t *)key->k_link.lnk_fwd; - - /* Skip non-matching keys */ - if (key->k_key != service_key) { - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT preempt key:%016lx != key:%016lx " - "i_name:%s transportID:%s\n", service_key, - key->k_key, key->k_i_name, key->k_transportID); - continue; - } - - /* - * Determine if UNIT ATTN needed - */ - unit_attn = strcmp(key->k_i_name, T10_PGR_INAME(cmd)); - - /* - * Remove the registration key - */ - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT preempt delete key:%016lx " - "i_name:%s transportID:%s\n", - key->k_key, key->k_i_name, key->k_transportID); - spc_pr_key_free(pgr, key); - - /* - * UNIT ATTN needed ? - * Do not set UNIT ATTN for calling Initiator - */ - if (unit_attn == False) - continue; - - /* - * Is this the preempt and abort? - */ - if (p_prout->action == PR_OUT_PREEMPT_ABORT) { - queue_message_set( - cmd->c_lu->l_common->l_from_transports, - Q_HIGH, msg_reset_lu, (void *)cmd->c_lu); - } - - /* - * Find associated I_T Nexuses - */ - (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_status = KEY_UNIT_ATTENTION; - lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - lu->l_ascq = SPC_ASCQ_RES_PREEMPTED; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - (void) pthread_mutex_unlock( - &cmd->c_lu->l_common->l_common_mutex); - } - - /* - * Re-establish our service key if we preempted it. - */ - if (!(key = spc_pr_key_find( - pgr, reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)))) { - - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT: preempt - register:%016lx, i_name:%s:%s\n", - reservation_key, T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); - - key = spc_pr_key_alloc(pgr, reservation_key, - T10_PGR_INAME(cmd), T10_PGR_TNAME(cmd)); - if (key == NULL) { - cmd->c_lu->l_status = KEY_ABORTED_COMMAND; - cmd->c_lu->l_asc = SPC_ASC_MEMORY_OUT_OF; - cmd->c_lu->l_ascq = SPC_ASCQ_RESERVATION_FAIL; - return (STATUS_CHECK); - } - } - - /* - * Now look for a matching reservation to preempt. - */ - for (rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rsrv = (spc_pr_rsrv_t *)rsrv_next) { - - /* - * Get next pointer in case the reservation gets deallocated - */ - rsrv_next = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd; - - /* Skip non-matching keys */ - if (rsrv->r_key != service_key) { - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT preempt rsrv:%016lx != rsrv:%016lx" - "i_name:%s scope:%d type:%d \n", service_key, - rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - continue; - } - - /* - * Remove matching reservations on other ports - * and establish a new reservation on this port only. - * To change the fuctionality to preempt rather than - * delete the reservations on other ports just remove - * the following block of code. - */ - if (strcmp(rsrv->r_transportID, T10_PGR_TNAME(cmd))) { - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT preempt(-) rsrv:%016lx " - "i_name:%s scope:%d type:%d \n", - rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - - spc_pr_rsrv_free(pgr, rsrv); - continue; - } else { - /* - * We have a matching reservation so preempt it. - */ - rsrv->r_key = reservation_key; - rsrv->r_i_name = strdup(T10_PGR_INAME(cmd)); - rsrv->r_scope = p_prout->scope; - rsrv->r_type = p_prout->type; - - queue_prt(mgmtq, Q_PR_NONIO, - "PGROUT preempt(+) rsrv:%016lx " - "i_name:%s scope:%d type:%d \n", - rsrv->r_key, rsrv->r_i_name, - rsrv->r_scope, rsrv->r_type); - } - } - - return (status); -} - -/* - * []---- - * | spc_pr_out_clear - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -/* ARGSUSED */ -static int -spc_pr_out_clear(t10_cmd_t *cmd, void *data, size_t data_len) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - scsi_prout_plist_t *plist = (scsi_prout_plist_t *)data; - uint64_t reservation_key; - uint64_t service_key; - spc_pr_key_t *key; - t10_lu_impl_t *lu; - - /* - * Do not allow an unregistered initiator to attempting to - * clear the PGR. - */ - reservation_key = SCSI_READ64(plist->reservation_key); - service_key = SCSI_READ64(plist->service_key); - - queue_prt(mgmtq, Q_PR_NONIO, - "PGR%x LUN%d clear reservation:%016lx, key:%016lx\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - reservation_key, service_key); - - if (!spc_pr_key_find(pgr, reservation_key, T10_PGR_INAME(cmd), "")) { - - queue_prt(mgmtq, Q_PR_ERRS, - "PGROUT: clear service:%016lx not found\n", - reservation_key); - - return (STATUS_RESERVATION_CONFLICT); - } - - /* - * We need to set UNIT ATTENTION for all registered initiators. - */ - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - /* Do not set UNIT ATTN for calling Initiator */ - if (!(strcmp(key->k_i_name, T10_PGR_INAME(cmd)))) - continue; - /* - * At this point the only way to get in here is to be the owner - * of the reservation. - */ - (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_status = KEY_UNIT_ATTENTION; - lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - lu->l_ascq = SPC_ASCQ_RES_PREEMPTED; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - (void) pthread_mutex_unlock( - &cmd->c_lu->l_common->l_common_mutex); - } - - /* - * Now erase the reservation and registration info. - */ - spc_pr_erase(pgr); - - return (STATUS_GOOD); -} - -/* - * []---- - * | spc_pr_out_register_and_move - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static int -spc_pr_out_register_and_move(t10_cmd_t *cmd, void *data, size_t data_len) -{ - return (STATUS_RESERVATION_CONFLICT); -} - -/* - * []---- - * | spc_pr_key_alloc - - * | Allocate a new registration key and add it to the key list. - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static spc_pr_key_t * -spc_pr_key_alloc(scsi3_pgr_t *pgr, uint64_t service_key, char *i_name, - char *transportID) -{ - spc_pr_key_t *key = (spc_pr_key_t *) - memalign(sizeof (void *), sizeof (spc_pr_key_t)); - - if (key != NULL) { - key->k_key = service_key; - key->k_i_name = strdup(i_name); - key->k_transportID = strdup(transportID); - - insque(&key->k_link, pgr->pgr_keylist.lnk_bwd); - - pgr->pgr_numkeys++; - assert(pgr->pgr_numkeys > 0); - } - - return (key); -} - -/* - * []---- - * | spc_pr_initialize - - * | Initialize registration & reservervation queues - * []---- - */ -static void -spc_pr_initialize(scsi3_pgr_t *pgr) -{ - assert(pgr->pgr_numrsrv == 0); - assert(pgr->pgr_numkeys == 0); - pgr->pgr_rsrvlist.lnk_fwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd; - - assert(pgr->pgr_rsrvlist.lnk_bwd == NULL); - pgr->pgr_rsrvlist.lnk_bwd = (key_link_t *)&pgr->pgr_rsrvlist.lnk_fwd; - - assert(pgr->pgr_keylist.lnk_fwd == NULL); - pgr->pgr_keylist.lnk_fwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd; - - assert(pgr->pgr_keylist.lnk_bwd == NULL); - pgr->pgr_keylist.lnk_bwd = (key_link_t *)&pgr->pgr_keylist.lnk_fwd; -} - -/* - * []---- - * | spc_pr_key_free - - * | Free a registration key - * []---- - */ -static void -spc_pr_key_free(scsi3_pgr_t *pgr, spc_pr_key_t *key) -{ - remque(&key->k_link); - free(key->k_i_name); - free(key->k_transportID); - free(key); - - pgr->pgr_numkeys--; - assert(pgr->pgr_numkeys >= 0); -} - -/* - * []---- - * | spc_pr_key_find - - * | Find a registration key based on the key, owner id and port id. - * []---- - */ -static spc_pr_key_t * -spc_pr_key_find(scsi3_pgr_t *pgr, uint64_t key, char *i_name, char *transportID) -{ - spc_pr_key_t *kp; - spc_pr_key_t *rval = NULL; - - for (kp = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - kp != (spc_pr_key_t *)&pgr->pgr_keylist; - kp = (spc_pr_key_t *)kp->k_link.lnk_fwd) { - if ((key == 0 || kp->k_key == key) && - (strlen(i_name) == 0 || - (strcmp(kp->k_i_name, i_name) == 0)) && - (strlen(transportID) == 0 || - (strcmp(kp->k_transportID, transportID) == 0))) { - rval = kp; - break; - } - } - - return (rval); -} - - -/* - * []---- - * | spc_pr_rsrv_alloc - - * | Allocate a new reservation and add it to the rsrv list. - * []---- - */ -static spc_pr_rsrv_t * -spc_pr_rsrv_alloc(scsi3_pgr_t *pgr, uint64_t service_key, char *i_name, - char *transportID, uint8_t scope, uint8_t type) -{ - spc_pr_rsrv_t *rsrv = (spc_pr_rsrv_t *) - memalign(sizeof (void *), sizeof (spc_pr_rsrv_t)); - - if (rsrv != NULL) { - rsrv->r_key = service_key; - rsrv->r_i_name = strdup(i_name); - rsrv->r_transportID = strdup(transportID); - rsrv->r_scope = scope; - rsrv->r_type = type; - - insque(&rsrv->r_link, pgr->pgr_rsrvlist.lnk_bwd); - - pgr->pgr_numrsrv++; - assert(pgr->pgr_numrsrv > 0); - } - - return (rsrv); -} - - -/* - * []---- - * | spc_pr_rsrv_free - - * | Free a reservation. - * []---- - */ -static void -spc_pr_rsrv_free(scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv) -{ - remque(&rsrv->r_link); - free(rsrv->r_i_name); - free(rsrv->r_transportID); - free(rsrv); - - pgr->pgr_numrsrv--; - assert(pgr->pgr_numrsrv >= 0); -} - -/* - * []---- - * | spc_pr_rsrv_find - - * | Find a reservation based on the key, owner id and port id. - * []---- - */ -static spc_pr_rsrv_t * -spc_pr_rsrv_find(scsi3_pgr_t *pgr, uint64_t key, char *i_name, - char *transportID) -{ - spc_pr_rsrv_t *rp, *rval = NULL; - - for (rp = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rp != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist; - rp = (spc_pr_rsrv_t *)rp->r_link.lnk_fwd) { - if ((key == 0 || rp->r_key == key) && - (strlen(i_name) == 0 || - (strcmp(rp->r_i_name, i_name) == 0)) && - (strlen(transportID) == 0 || - (strcmp(rp->r_transportID, transportID) == 0))) { - rval = rp; - break; - } - } - - return (rval); -} - -/* - * []---- - * | spc_pr_erase - - * | Find specified key / reservation and erease it - * []---- - */ -/* - */ -static void -spc_pr_erase(scsi3_pgr_t *pgr) -{ - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - - while ((key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd) != - (spc_pr_key_t *)&pgr->pgr_keylist) { - spc_pr_key_free(pgr, key); - } - - assert(pgr->pgr_numkeys == 0); - - while ((rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd) != - (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist) { - spc_pr_rsrv_free(pgr, rsrv); - } - - assert(pgr->pgr_numrsrv == 0); - - pgr->pgr_generation = 0; - pgr->pgr_aptpl = 0; -} - -/* - * []---- - * | spc_pr_rsrv_release - - * | Release the reservation the perform any other required clearing actions. - * | Refer to SPC-3, Section 6.1, Tables ?? and ?? - * []---- - */ -static void -spc_pr_rsrv_release(t10_cmd_t *cmd, scsi3_pgr_t *pgr, spc_pr_rsrv_t *rsrv) -{ - t10_lu_impl_t *lu; - spc_pr_key_t *key; - - /* - * For Registrants-Only mode set UNIT ATTN. - */ - if (rsrv->r_type == PGR_TYPE_WR_EX_RO || - rsrv->r_type == PGR_TYPE_EX_AC_RO) { - - for (key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist; - key = (spc_pr_key_t *)key->k_link.lnk_fwd) { - - /* - * No UNIT ATTN for the requesting Initiator. - */ - if (!(strcmp(key->k_i_name, T10_PGR_INAME(cmd)))) - continue; - - /* - * Find associated I_T Nexuses - */ - (void) pthread_mutex_lock( - &cmd->c_lu->l_common->l_common_mutex); - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_status = KEY_UNIT_ATTENTION; - lu->l_asc = SPC_ASC_PARAMETERS_CHANGED; - lu->l_ascq = SPC_ASCQ_RES_RELEASED; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, - lu); - } while (lu != NULL); - (void) pthread_mutex_unlock( - &cmd->c_lu->l_common->l_common_mutex); - } - } - - /* - * Remove the reservation. - */ - spc_pr_rsrv_free(pgr, rsrv); -} - -/* - * []---- - * | spc_pr_read - - * | Read in pgr keys and reservations for this device from backend storage. - * | At least the local pgr write lock must be held. - * []---- - */ -void -spc_pr_read(t10_cmd_t *cmd) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - spc_pr_diskkey_t *klist; - spc_pr_diskrsrv_t *rlist; - spc_pr_persist_disk_t *buf = NULL; - t10_lu_impl_t *lu; - int i, pfd; - Boolean_t status = False; - char *c, path[MAXPATHLEN] = {0}; - - /* - * Open the PERSISTENCE file specification if one exists - * taking into account the alternate location if a ZVOL - */ - if (tgt_find_value_str(cmd->c_lu->l_common->l_root, XML_ELEMENT_BACK, - &c) == True) { - if (((pgr_basedir != NULL) && (strlen(pgr_basedir) != 0)) && - (strncmp(ZVOL_PATH, c, sizeof (ZVOL_PATH) - 1) == 0)) { - (void) snprintf(path, MAXPATHLEN, "%s/%s-%s%d", - pgr_basedir, &c[sizeof (ZVOL_PATH) - 1], - PERSISTENCEBASE, cmd->c_lu->l_common->l_num); - } else { - (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d", - target_basedir, cmd->c_lu->l_targ->s_targ_base, - PERSISTENCEBASE, cmd->c_lu->l_common->l_num); - } - free(c); - } - if ((pfd = open(path, O_RDONLY)) >= 0) { - struct stat pstat; - if ((fstat(pfd, &pstat)) == 0) - if (pstat.st_size > 0) - if (buf = malloc(pstat.st_size)) - if (read(pfd, buf, pstat.st_size) == - pstat.st_size) - status = True; - } - - /* - * Clean up on no persistence file found - */ - if (status == False) { - if (pfd >= 0) - (void) close(pfd); - if (buf) - free(buf); - return; - } - - /* - * If this is the first time using the persistence data, - * initialize the reservation and resource key queues - */ - if (pgr->pgr_rsrvlist.lnk_fwd == NULL) { - (void) spc_pr_initialize(pgr); - } - - /* - * Perform some vailidation on what we are looking at - */ - assert(buf->magic == PGRMAGIC); - assert(buf->revision == SPC_PGR_PERSIST_DATA_REVISION); - - /* - * Get the PGR keys - */ - klist = (spc_pr_diskkey_t *)&buf->keylist[0]; - for (i = 0; i < buf->numkeys; i++) { - assert(klist[i].rectype == PGRDISKKEY); - - /* - * Was the key previously read, if not restore it - */ - key = spc_pr_key_find(pgr, 0, T10_PGR_INAME(cmd), - T10_PGR_TNAME(cmd)); - if (key == NULL) - key = spc_pr_key_alloc(pgr, klist[i].key, - klist[i].i_name, klist[i].transportID); - assert(key); - } - - /* - * Get the PGR reservations - */ - rlist = (spc_pr_diskrsrv_t *)&buf->keylist[buf->numkeys]; - for (i = 0; i < buf->numrsrv; i++) { - assert(rlist[i].rectype == PGRDISKRSRV); - - /* - * Was the reservation previously read, if not restore it - */ - rsrv = spc_pr_rsrv_find(pgr, 0, T10_PGR_INAME(cmd), - T10_PGR_TNAME(cmd)); - if (rsrv == NULL) - rsrv = spc_pr_rsrv_alloc(pgr, rlist[i].key, - rlist[i].i_name, rlist[i].transportID, - rlist[i].scope, rlist[i].type); - assert(rsrv); - } - - /* - * If there was data then set the reservation type. - */ - if (pgr->pgr_numkeys > 0 || pgr->pgr_numrsrv > 0) { - res->res_type = RT_PGR; - pgr->pgr_generation = buf->generation; - - /* - * Set the command dispatcher according to the reservation type - */ - (void) pthread_mutex_lock(&cmd->c_lu->l_common->l_common_mutex); - lu = avl_first(&cmd->c_lu->l_common->l_all_open); - do { - lu->l_cmd = sbc_cmd_reserved; - lu = AVL_NEXT(&cmd->c_lu->l_common->l_all_open, lu); - } while (lu != NULL); - (void) pthread_mutex_unlock( - &cmd->c_lu->l_common->l_common_mutex); - } - - free(buf); -} - -/* - * []---- - * | spc_pr_write - - * | Write PGR keys and reservations for this device to backend storage. - * | At least the local pgr write lock must be held. - * []---- - */ -Boolean_t -spc_pr_write(t10_cmd_t *cmd) -{ - disk_params_t *p = (disk_params_t *)T10_PARAMS_AREA(cmd); - sbc_reserve_t *res = &p->d_sbc_reserve; - scsi3_pgr_t *pgr = &res->res_scsi_3_pgr; - spc_pr_key_t *key; - spc_pr_rsrv_t *rsrv; - spc_pr_diskkey_t *klist; - spc_pr_diskrsrv_t *rlist; - spc_pr_persist_disk_t *buf; - ssize_t length, bufsize; - int i, pfd = -1; - char *c, path[MAXPATHLEN] = {0}; - Boolean_t status = True; - - /* - * Verify space requirements and allocate buffer memory. - * Space needed is header + keylist + rsrvlist. - * Subtract 1 from numkeys since header already defines - * the first element of the keylist. - * Round up the bufsize to the next FBA boundary. - */ - bufsize = sizeof (spc_pr_persist_disk_t) + - (pgr->pgr_numkeys - 1) * sizeof (spc_pr_diskkey_t) + - pgr->pgr_numrsrv * sizeof (spc_pr_diskrsrv_t); - bufsize = roundup(bufsize, 512); - if ((buf = memalign(sizeof (void *), bufsize)) == NULL) - return (False); - else - bzero(buf, bufsize); - - /* - * Build header. - */ - buf->magic = PGRMAGIC; - buf->revision = SPC_PGR_PERSIST_DATA_REVISION; - buf->generation = pgr->pgr_generation; - buf->numkeys = pgr->pgr_numkeys; - buf->numrsrv = pgr->pgr_numrsrv; - - /* - * Copy the keys. - */ - klist = buf->keylist; - for (i = 0, key = (spc_pr_key_t *)pgr->pgr_keylist.lnk_fwd; - key != (spc_pr_key_t *)&pgr->pgr_keylist && i < pgr->pgr_numkeys; - key = (spc_pr_key_t *)key->k_link.lnk_fwd, i++) { - - klist[i].rectype = PGRDISKKEY; - klist[i].key = key->k_key; - (void) strncpy(klist[i].i_name, key->k_i_name, - sizeof (klist[i].i_name)); - (void) strncpy(klist[i].transportID, key->k_transportID, - sizeof (klist[i].transportID)); - } - - /* - * Copy the reservations. - */ - rlist = (spc_pr_diskrsrv_t *)&buf->keylist[pgr->pgr_numkeys]; - for (i = 0, rsrv = (spc_pr_rsrv_t *)pgr->pgr_rsrvlist.lnk_fwd; - rsrv != (spc_pr_rsrv_t *)&pgr->pgr_rsrvlist && - i < pgr->pgr_numrsrv; - rsrv = (spc_pr_rsrv_t *)rsrv->r_link.lnk_fwd, i++) { - - rlist[i].rectype = PGRDISKRSRV; - rlist[i].key = rsrv->r_key; - rlist[i].scope = rsrv->r_scope; - rlist[i].type = rsrv->r_type; - (void) strncpy(rlist[i].i_name, rsrv->r_i_name, - sizeof (rlist[i].i_name)); - (void) strncpy(rlist[i].transportID, rsrv->r_transportID, - sizeof (rlist[i].transportID)); - } - - /* - * Open the PERSISTENCE file specification if one exists - * taking into account the alternate location if a ZVOL - */ - if (tgt_find_value_str(cmd->c_lu->l_common->l_root, XML_ELEMENT_BACK, - &c) == True) { - if (((pgr_basedir != NULL) && (strlen(pgr_basedir) != 0)) && - (strncmp(ZVOL_PATH, c, sizeof (ZVOL_PATH) - 1) == 0)) { - (void) snprintf(path, MAXPATHLEN, "%s/%s-%s%d", - pgr_basedir, &c[sizeof (ZVOL_PATH) - 1], - PERSISTENCEBASE, cmd->c_lu->l_common->l_num); - } else { - (void) snprintf(path, MAXPATHLEN, "%s/%s/%s%d", - target_basedir, cmd->c_lu->l_targ->s_targ_base, - PERSISTENCEBASE, cmd->c_lu->l_common->l_num); - } - free(c); - } - if ((pfd = open(path, O_WRONLY|O_CREAT, 0600)) >= 0) { - length = write(pfd, buf, bufsize); - (void) close(pfd); - } else { - if ((pfd < 0) || (length != bufsize)) - status = False; - } - - /* - * Free allocated buffer - */ - free(buf); - return (status); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h deleted file mode 100644 index 1ad68ae93b..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 _T10_SPC_PR_H -#define _T10_SPC_PR_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SPC-3 Persistent Reservation specific structures and defines - */ - -/* - * Key Linked Lists - */ -typedef struct key_link { - union { - uint64_t align; - struct { - struct key_link *_lnk_fwd; /* Forward element */ - struct key_link *_lnk_bwd; /* Backward element */ - } key_ptr; - } key_link; -} key_link_t; -#define lnk_fwd key_link.key_ptr._lnk_fwd -#define lnk_bwd key_link.key_ptr._lnk_bwd -#define insque(a, b) \ - ((key_link_t *)(a))->lnk_fwd = (key_link_t *)(b); \ - ((key_link_t *)(a))->lnk_bwd = ((key_link_t *)(b))->lnk_bwd; \ - ((key_link_t *)(b))->lnk_bwd = (key_link_t *)(a); \ - ((key_link_t *)(a))->lnk_bwd->lnk_fwd = (key_link_t *)(a); - -#define remque(A) \ - ((key_link_t *)(A))->lnk_bwd->lnk_fwd = ((key_link_t *)(A))->lnk_fwd; \ - ((key_link_t *)(A))->lnk_fwd->lnk_bwd = ((key_link_t *)(A))->lnk_bwd; - -/* - * Reservation Types (res_type). - */ -typedef enum { - RT_NONE = 0, /* None */ - RT_PGR, /* SCSI-3 Persistent Reservation */ - RT_NPR /* SCSI-2 Non-Persistent Reservation */ -} spc_reserve_types; - -/* - * Persistent reservation data. - */ -typedef struct spc_pr_key { - key_link_t k_link; /* Key linked list */ - uint64_t k_key; /* registration key */ - char *k_i_name; /* initiator name */ - char *k_transportID; /* transport ID */ -} spc_pr_key_t; - -typedef struct spc_pr_rsrv { - key_link_t r_link; /* Key linked list */ - uint64_t r_key; /* reservation key */ - char *r_i_name; /* initiator name */ - char *r_transportID; /* transport ID */ - uint8_t r_scope; /* reservation scope */ - uint8_t r_type; /* reservation type */ -} spc_pr_rsrv_t; - -/* - * Persistent Reservation data - */ -typedef struct scsi3_pgr { - uint32_t pgr_generation; /* PGR PRgeneration value */ - uint16_t pgr_unused; - uint16_t pgr_bits : 15, - pgr_aptpl : 1; /* persistence data exists */ - int32_t pgr_numkeys; /* # entries in key list */ - int32_t pgr_numrsrv; /* # entries in rsrv list */ - key_link_t pgr_keylist; /* Registration key list */ - key_link_t pgr_rsrvlist; /* reservation list */ -} scsi3_pgr_t; - -typedef struct sbc_reserve { - spc_reserve_types res_type; /* standard or pr active */ - pthread_rwlock_t res_rwlock; /* Lock for coordination */ - scsi3_pgr_t res_scsi_3_pgr; /* SCSI-3 PGR */ - t10_lu_impl_t *res_owner; /* SCSI-2 Reservation */ -} sbc_reserve_t; - -/* - * On-disk PGR data. - * - * NOTE: The following three structures should be rounded up to 512 bytes each - * to prevent potential problems with on-disk data skew - */ -typedef struct spc_pr_diskkey { - uint64_t key; /* registration key (8) */ - uint32_t rectype; /* record type (4) */ - char i_name[224]; /* initiator name (224) */ - char filler1[20]; /* filler to 256 bytes */ - char transportID[228]; /* transport ID (228) */ - char filler2[28]; /* filler to 512 bytes */ -} spc_pr_diskkey_t; - -typedef struct spc_pr_diskrsrv { - uint64_t key; /* reservation key (8) */ - uint32_t rectype; /* record type (4) */ - uint8_t scope; /* reservation scope (1) */ - uint8_t type; /* reservation type (1) */ - char i_name[224]; /* initiator name (224) */ - char filler1[18]; /* filler to 256 bytes */ - char transportID[228]; /* Transport ID (228) */ - char filler2[28]; /* filler to 512 bytes */ -} spc_pr_diskrsrv_t; - -typedef struct spc_pr_persist_disk { - uint64_t magic; /* magic number (8) */ - uint32_t revision; /* header format revision (4) */ - uint32_t generation; /* pgr generation count (4) */ - int32_t numkeys; /* # items in key list (4) */ - int32_t numrsrv; /* # items in rsrv list (4) */ - char filler[488]; /* 8+4+4+4+4 */ - -/* - * After the header the data is laid out as follows: - * spc_pr_diskkey_t keylist[]; - * spc_pr_diskrsrv_t rsrvlist[]; - */ - spc_pr_diskkey_t keylist[1]; -} spc_pr_persist_disk_t; - - -#define SPC_PGR_PERSIST_DATA_REVISION 0x01 /* REVISON = 1 */ -#define PGRMAGIC 0x5047524D41474943LL /* "PGRMAGIC" */ -#define PGRDISKKEY 0x5047526B /* "PGRk" */ -#define PGRDISKRSRV 0x50475272 /* "PGRr" */ - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_SPC_PR_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_ssc.c b/usr/src/cmd/iscsi/iscsitgtd/t10_ssc.c deleted file mode 100644 index dfa83a34a0..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_ssc.c +++ /dev/null @@ -1,1646 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Implementation of SSC-2 emulation - */ - -#include <strings.h> -#include <unistd.h> -#include <sys/types.h> -#include <aio.h> -#include <sys/asynch.h> -#include <sys/scsi/generic/sense.h> -#include <sys/scsi/generic/status.h> -#include <sys/scsi/targets/stdef.h> -#include <netinet/in.h> - -#include "target.h" -#include "utility.h" -#include "t10.h" -#include "t10_spc.h" -#include "t10_ssc.h" - -/* - * []---- - * | Forward declarations - * []---- - */ -static scsi_cmd_table_t ssc_table[]; -static void ssc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len); -static void ssc_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, - char *data, size_t data_len); -static void ssc_free(emul_handle_t e); -static void ssc_write_cmplt(emul_handle_t e); -static void ssc_read_cmplt(emul_handle_t id); -static void ssc_setup_tape(ssc_params_t *s, t10_lu_common_t *lu); -static uint32_t find_last_obj_id(char *file_mark, off_t eod); -static char *sense_dev_config(ssc_params_t *s, char *data); -static char *sense_compression(ssc_params_t *s, char *data); - -static long ssc_page_size; - -/* - * []---- - * | ssc_init_common -- initialize common information that all ITLs will use - * []---- - */ -Boolean_t -ssc_common_init(t10_lu_common_t *lu) -{ - ssc_params_t *s; - ssc_obj_mark_t mark; - - ssc_page_size = sysconf(_SC_PAGESIZE); - - if (lu->l_mmap == MAP_FAILED) - return (False); - - if ((s = (ssc_params_t *)calloc(1, sizeof (*s))) == NULL) - return (False); - - s->s_size = lu->l_size; - s->s_fast_write_ack = lu->l_fast_write_ack; - - bcopy(lu->l_mmap, &mark, sizeof (mark)); - if (mark.som_sig != SSC_OBJ_SIG) { - ssc_setup_tape(s, lu); - } - s->s_cur_fm = 0; - s->s_cur_rec = sizeof (ssc_obj_mark_t); - s->s_prev_rec = s->s_cur_rec; - s->s_state = lu->l_state; - - lu->l_dtype_params = (void *)s; - return (True); -} - -/* - * []---- - * | ssc_fini_common -- free any resources - * []---- - */ -void -ssc_common_fini(t10_lu_common_t *lu) -{ - free(lu->l_dtype_params); -} - -void -ssc_task_mgmt(t10_lu_common_t *lu, TaskOp_t op) -{ - ssc_params_t *s = (ssc_params_t *)lu->l_dtype_params; - - switch (op) { - case CapacityChange: - s->s_size = lu->l_size; - break; - - case DeviceOnline: - s->s_state = lu->l_state; - } -} - -/* - * []---- - * | ssc_init_per -- initialize per ITL information - * []---- - */ -void -ssc_per_init(t10_lu_impl_t *itl) -{ - ssc_params_t *s = (ssc_params_t *)itl->l_common->l_dtype_params; - - if (s->s_state == lu_online) - itl->l_cmd = ssc_cmd; - else - itl->l_cmd = spc_cmd_offline; - itl->l_data = ssc_data; - itl->l_cmd_table = ssc_table; -} - -/* - * []---- - * | ssc_fini_per -- release or free any ITL resources - * []---- - */ -/*ARGSUSED*/ -void -ssc_per_fini(t10_lu_impl_t *itl) -{ -} - -/* - * []---- - * | ssc_cmd -- start a SCSI command - * | - * | This routine is called from within the SAM-3 Task router. - * []---- - */ -static void -ssc_cmd(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - scsi_cmd_table_t *e; - - e = &cmd->c_lu->l_cmd_table[cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SSC%x LUN%d Cmd %s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name == NULL ? "(no name)" : e->cmd_name); -#endif - (*e->cmd_start)(cmd, cdb, cdb_len); -} - -/* - * []---- - * | ssc_data -- Data phase for command. - * | - * | Normally this is only called for the WRITE command. Other commands - * | that have a data in phase will probably be short circuited when - * | we call trans_rqst_dataout() and the data is already available. - * | At least this is true for iSCSI. FC however will need a DataIn phase - * | for commands like MODE SELECT and PGROUT. - * []---- - */ -static void -ssc_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - scsi_cmd_table_t *e; - - e = &cmd->c_lu->l_cmd_table[cmd->c_cdb[0]]; -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, "SSC%x LUN%d Data %s\n", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - e->cmd_name); -#endif - (*e->cmd_data)(cmd, id, offset, data, data_len); -} - -/* - * []------------------------------------------------------------------[] - * | SCSI Streaming Commands - 3 | - * | T10/1611-D Revision 01c | - * | The following functions implement the emulation of SSC-3 type | - * | commands. | - * []------------------------------------------------------------------[] - */ - -/*ARGSUSED*/ -static void -ssc_read(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_io_t *io; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - ssc_obj_mark_t fm, - rm; - int fixed, - sili; - off_t offset = 0; - size_t xfer, - req_len; - void *mmap = cmd->c_lu->l_common->l_mmap; - t10_cmd_t *c; - - fixed = cdb[1] & 0x01; - sili = cdb[1] & 0x02; - - if (s == NULL) - return; - - /* - * Standard error checking. - */ - if ((sili && fixed) || (cdb[1] & 0xfc) || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - req_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; - req_len *= fixed ? 512 : 1; - - if (req_len == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SSC%x LUN%d read 0x%x bytes", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, req_len); -#endif - - bcopy((char *)mmap + s->s_cur_fm, &fm, sizeof (fm)); - bcopy((char *)mmap + s->s_cur_fm + s->s_cur_rec, &rm, sizeof (rm)); - - if (rm.som_sig != SSC_OBJ_SIG) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d bad RECORD-MARK", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num); - spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } else if (rm.som_type != SSC_OBJ_TYPE_RM) { - s->s_cur_fm += fm.o_fm.size; - s->s_cur_rec = sizeof (ssc_obj_mark_t); - s->s_prev_rec = s->s_cur_rec; - - spc_sense_create(cmd, KEY_NO_SENSE, 0); - spc_sense_ascq(cmd, SPC_ASC_FM_DETECTED, SPC_ASCQ_FM_DETECTED); - spc_sense_info(cmd, req_len); - spc_sense_flags(cmd, SPC_SENSE_FM); - trans_send_complete(cmd, STATUS_CHECK); - return; - } else if ((sili == 0) && - ((rm.o_rm.size - sizeof (ssc_obj_mark_t)) != req_len)) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d Wrong size read", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num); - - s->s_prev_rec = s->s_cur_rec; - s->s_cur_rec += rm.o_rm.size; - - spc_sense_create(cmd, KEY_NO_SENSE, 0); - spc_sense_flags(cmd, SPC_SENSE_ILI); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - do { - xfer = MIN((req_len - offset), T10_MAX_OUT(cmd)); - if ((offset + xfer) < req_len) - c = trans_cmd_dup(cmd); - else - c = cmd; - if ((io = (ssc_io_t *)calloc(1, sizeof (*io))) == NULL) { - trans_send_complete(c, STATUS_BUSY); - return; - } - - io->sio_cmd = c; - io->sio_offset = offset; - io->sio_total = req_len; - io->sio_data_len = xfer; - io->sio_data = (char *)mmap + s->s_cur_fm + - s->s_cur_rec + sizeof (ssc_obj_mark_t) + offset; - io->sio_aio.a_aio.aio_return = xfer; - - ssc_read_cmplt((emul_handle_t)io); - offset += xfer; - } while (offset < req_len); - - s->s_prev_rec = s->s_cur_rec; - s->s_cur_rec += req_len + sizeof (ssc_obj_mark_t); -} - -static void -ssc_read_cmplt(emul_handle_t id) -{ - ssc_io_t *io = (ssc_io_t *)id; - t10_cmd_t *cmd = io->sio_cmd; - - if (io->sio_aio.a_aio.aio_return != io->sio_data_len) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((io->sio_offset + io->sio_data_len) < io->sio_total) { - if (trans_send_datain(cmd, io->sio_data, io->sio_data_len, - io->sio_offset, ssc_free, False, io) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } - } else { - if (trans_send_datain(cmd, io->sio_data, io->sio_data_len, - io->sio_offset, ssc_free, True, io) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } - } -} - -/*ARGSUSED*/ -static void -ssc_write(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_obj_mark_t mark; - size_t request_len, - max_xfer; - int fixed, - prev_id; - ssc_io_t *io; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - - if (s == NULL) - return; - - if ((cdb[1] & 0xfe) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - fixed = cdb[1]; - request_len = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; - request_len *= fixed ? 512 : 1; - -#ifdef FULL_DEBUG - queue_prt(mgmtq, Q_STE_IO, - "SSC%x LUN%d write %d, fixed %d", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - request_len, fixed); -#endif - io = cmd->c_emul_id; - if (io == NULL) { - if ((io = calloc(1, sizeof (*io))) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - io->sio_total = request_len; - io->sio_cmd = cmd; - io->sio_offset = 0; - - /* - * Writing looses all information after the current - * file-mark. So, check to see if the current file-mark - * size doesn't reflect the end-of-media. If not, update - * it. - */ - bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm, - &mark, sizeof (mark)); - if (mark.o_fm.size != - (s->s_size - sizeof (ssc_obj_mark_t) - s->s_cur_fm)) { - mark.o_fm.size = s->s_size - sizeof (ssc_obj_mark_t) - - s->s_cur_fm; - bcopy(&mark, (char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm, sizeof (mark)); - } - - /* - * End-of-Partition detection - */ - if ((s->s_cur_rec + request_len) > (mark.o_fm.size)) { - spc_sense_create(cmd, KEY_VOLUME_OVERFLOW, 0); - spc_sense_ascq(cmd, SPC_ASC_EOP, SPC_ASCQ_EOP); - spc_sense_flags(cmd, SPC_SENSE_EOM); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((s->s_cur_fm == 0) && - (s->s_cur_rec == sizeof (ssc_obj_mark_t))) { - - /* - * The current position is a BOM. By setting - * the prev_id value to -1 the code below will - * create the first ID with a value of zero - * Which is what the specification requires. - */ - prev_id = -1; - - } else if (s->s_cur_rec == sizeof (ssc_obj_mark_t)) { - - /* - * If the current position is at the beginning of - * this file-mark use the object ID found in - * the file-mark header. It will have been updated - * from the last object ID in the previous file-mark. - * - * NOTE: We're counting on 'mark' still referring - * to the current file mark here. - */ - prev_id = mark.o_fm.last_obj_id; - } else { - bcopy((char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm + s->s_prev_rec, &mark, sizeof (mark)); - prev_id = mark.o_rm.obj_id; - } - - bzero(&mark, sizeof (mark)); - mark.som_sig = SSC_OBJ_SIG; - mark.som_type = SSC_OBJ_TYPE_RM; - mark.o_rm.size = request_len + - sizeof (ssc_obj_mark_t); - mark.o_rm.obj_id = prev_id + 1; - bcopy(&mark, (char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm + s->s_cur_rec, sizeof (mark)); - } - - max_xfer = min(io->sio_total - io->sio_offset, - cmd->c_lu->l_targ->s_maxout); - io->sio_aio.a_aio.aio_return = max_xfer; - io->sio_data_len = max_xfer; - io->sio_data = (char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm + s->s_cur_rec + sizeof (mark) + io->sio_offset; - - if (trans_rqst_dataout(cmd, io->sio_data, io->sio_data_len, - io->sio_offset, io, ssc_free) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -ssc_write_data(t10_cmd_t *cmd, emul_handle_t id, size_t offset, char *data, - size_t data_len) -{ - ssc_io_t *io = (ssc_io_t *)id; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - - if (s == NULL) - return; - - if (s->s_fast_write_ack == False) { - uint64_t sa; - size_t len; - - /* - * msync requires the address to be page aligned. - * That means we need to account for any alignment - * loss in the len field and access the full page. - */ - sa = (uint64_t)(intptr_t)data & ~(ssc_page_size - 1); - len = (((size_t)data & (ssc_page_size - 1)) + - data_len + ssc_page_size - 1) & - ~(ssc_page_size -1); - - /* - * We only need to worry about sync'ing the blocks - * in the mmap case because if the fast cache isn't - * enabled for AIO the file will be opened with F_SYNC - * which performs the correct action. - */ - if (msync((char *)(intptr_t)sa, len, MS_SYNC) == -1) { - perror("msync"); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - } - ssc_write_cmplt((emul_handle_t)io); -} - -static void -ssc_write_cmplt(emul_handle_t e) -{ - ssc_io_t *io = (ssc_io_t *)e; - t10_cmd_t *cmd = io->sio_cmd; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - - if (s == NULL) - return; - - if ((io->sio_offset + io->sio_data_len) < io->sio_total) { - io->sio_offset += io->sio_data_len; - ssc_write(cmd, cmd->c_cdb, cmd->c_cdb_len); - return; - } - - s->s_prev_rec = s->s_cur_rec; - s->s_cur_rec += io->sio_total + sizeof (ssc_obj_mark_t); - free(io); - trans_send_complete(cmd, STATUS_GOOD); -} - -/*ARGSUSED*/ -static void -ssc_rewind(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - - if (s == NULL) - return; - - if ((cdb[1] & ~SSC_REWIND_IMMED) || cdb[2] || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - s->s_cur_fm = 0; - s->s_cur_rec = sizeof (ssc_obj_mark_t); - trans_send_complete(cmd, STATUS_GOOD); -} - -/*ARGSUSED*/ -static void -ssc_read_limits(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - struct read_blklim *rb; - int min_size = 512; - - if (cdb[1] || cdb[2] || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if ((rb = (struct read_blklim *)calloc(1, sizeof (*rb))) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - /* - * maximum block size is set to zero to indicate no maximum block - * limit is specified. - */ - rb->granularity = 9; /* 512 block sizes */ - rb->min_hi = hibyte(min_size); - rb->min_lo = lobyte(min_size); - - if (trans_send_datain(cmd, (char *)rb, sizeof (*rb), 0, ssc_free, - True, (emul_handle_t)rb) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -ssc_space(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - int code, - count; - ssc_params_t *s = T10_PARAMS_AREA(cmd); - ssc_obj_mark_t mark; - t10_lu_common_t *lu = cmd->c_lu->l_common; - - if (s == NULL) - return; - - if ((cdb[1] & 0xf0) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - code = cdb[1] & 0x0f; - count = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; - - if ((count == 0) && (code != SSC_SPACE_CODE_END_OF_DATA)) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } - - switch (code) { - case SSC_SPACE_CODE_BLOCKS: - if (count < 0) { - bcopy((char *)lu->l_mmap + s->s_cur_fm + s->s_cur_rec, - &mark, sizeof (mark)); - if ((mark.som_sig == SSC_OBJ_SIG) && - (mark.som_type == SSC_OBJ_TYPE_RM)) { - count = mark.o_rm.obj_id + count; - - /* - * If the count is still negative it means - * the request is still attempting to go - * beyond the beginning of the file mark. - */ - if (count < 0) { - count *= -1; - spc_sense_create(cmd, KEY_NO_SENSE, 0); - spc_sense_ascq(cmd, - SPC_ASC_FM_DETECTED, - SPC_ASCQ_FM_DETECTED); - spc_sense_info(cmd, count); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - s->s_cur_rec = s->s_cur_fm + sizeof (mark); - } else { - /* - * Something is not right. We'll let the - * processing below determine exactly what - * is wrong. So don't update the record - * mark and sent the count to 1. - */ - count = 1; - } - } - - while (count) { - bcopy((char *)lu->l_mmap + s->s_cur_fm + s->s_cur_rec, - &mark, sizeof (mark)); - - /* - * Something internally bad has happened with - * the marks in the file. - */ - if (mark.som_sig != SSC_OBJ_SIG) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d, bad sig mark: " - "expected=0x%x, got=0x%x", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - SSC_OBJ_SIG, mark.som_sig); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Hit a filemark. Update the current record if - * we're not at the End-Of-Medium. - */ - if (mark.som_type == SSC_OBJ_TYPE_FM) { - if (mark.o_fm.eom == True) { - spc_sense_create(cmd, KEY_MEDIUM_ERROR, - 0); - spc_sense_ascq(cmd, SPC_ASC_EOP, - SPC_ASCQ_EOP); - spc_sense_info(cmd, count); - spc_sense_flags(cmd, SPC_SENSE_EOM); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - s->s_cur_fm += s->s_cur_rec; - s->s_cur_rec += sizeof (mark); - spc_sense_create(cmd, KEY_NO_SENSE, 0); - spc_sense_ascq(cmd, SPC_ASC_FM_DETECTED, - SPC_ASCQ_FM_DETECTED); - spc_sense_info(cmd, count); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - s->s_cur_rec += mark.o_rm.size; - count--; - } - trans_send_complete(cmd, STATUS_CHECK); - break; - - case SSC_SPACE_CODE_FILEMARKS: - if (count < 0) { - bcopy((char *)lu->l_mmap + s->s_cur_fm, &mark, - sizeof (mark)); - if ((mark.som_sig == SSC_OBJ_SIG) && - (mark.som_type == SSC_OBJ_TYPE_FM)) { - count = mark.o_fm.num + count; - - /* - * If the count is still negative it means - * the request is still attempting to go - * beyond the beginning of the file mark. - */ - if (count < 0) { - count *= -1; - spc_sense_create(cmd, KEY_NO_SENSE, 0); - spc_sense_ascq(cmd, - SPC_ASC_FM_DETECTED, - SPC_ASCQ_FM_DETECTED); - spc_sense_info(cmd, count); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - s->s_cur_fm = 0; - s->s_cur_rec = sizeof (ssc_obj_mark_t); - } else { - /* - * Something is not right. We'll let the - * processing below determine exactly what - * is wrong. So don't update the record - * mark and sent the count to 1. - */ - count = 1; - } - } - - while (count--) { - bcopy((char *)lu->l_mmap + s->s_cur_fm, &mark, - sizeof (mark)); - if (mark.som_sig != SSC_OBJ_SIG) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d, bad sig mark: " - "expected=0x%x, got=0x%x", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - SSC_OBJ_SIG, mark.som_sig); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (mark.som_type != SSC_OBJ_TYPE_FM) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d, bad mark type: " - "expected=0x%x, got=0x%x", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - SSC_OBJ_TYPE_FM, mark.som_type); - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (mark.o_fm.eom == True) { - spc_sense_create(cmd, KEY_MEDIUM_ERROR, 0); - spc_sense_ascq(cmd, SPC_ASC_EOP, SPC_ASCQ_EOP); - spc_sense_info(cmd, count); - spc_sense_flags(cmd, SPC_SENSE_EOM); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - s->s_cur_fm += mark.o_fm.size; - } - trans_send_complete(cmd, STATUS_GOOD); - break; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } -} - -/* - * []---- - * | ssc_msense -- MODE SENSE command - * | - * | This command is part of the SPC set, but is device specific enough - * | that it must be emulated in each device type. - * []---- - */ -/*ARGSUSED*/ -static void -ssc_msense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_params_t *s = T10_PARAMS_AREA(cmd); - struct mode_header *mode_hdr; - int request_len, - alloc_len; - char *data, - *np; - - /* - * SPC-3 Revision 21c section 6.8 - * Reserve bit checks - */ - if ((cdb[1] & ~8) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - /* - * Zero length causes a simple ack to occur. - */ - if (cdb[4] == 0) { - trans_send_complete(cmd, STATUS_GOOD); - return; - } else { - request_len = cdb[4]; - alloc_len = max(request_len, - sizeof (*mode_hdr) + MODE_BLK_DESC_LENGTH + - sizeof (ssc_data_compression_t) + sizeof (*mode_hdr) + - MODE_BLK_DESC_LENGTH + sizeof (ssc_device_config_t)); - } - - queue_prt(mgmtq, Q_STE_NONIO, "SSC%x LUN%d: MODE_SENSE(0x%x)", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, cdb[2]); - - if ((data = memalign(sizeof (void *), alloc_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - - mode_hdr = (struct mode_header *)data; - - switch (cdb[2]) { - case MODE_SENSE_COMPRESSION: - mode_hdr->length = sizeof (ssc_data_compression_t); - mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH; - (void) sense_compression(s, data + sizeof (*mode_hdr) + - mode_hdr->bdesc_length); - break; - - case MODE_SENSE_DEV_CONFIG: - mode_hdr->length = sizeof (ssc_device_config_t); - mode_hdr->bdesc_length = MODE_BLK_DESC_LENGTH; - (void) sense_dev_config(s, data + sizeof (*mode_hdr) + - mode_hdr->bdesc_length); - break; - - case MODE_SENSE_SEND_ALL: - np = sense_compression(s, data); - (void) sense_dev_config(s, np); - break; - - case 0x00: - bzero(data, alloc_len); - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d: MODE SENSE(0x%x) not handled", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, - cdb[2]); - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if (trans_send_datain(cmd, (char *)data, request_len, 0, ssc_free, - True, data) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -ssc_read_pos(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - int service_action, - request_len, - alloc_len; - pos_short_form_t *sf; - void *data; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - ssc_obj_mark_t mark; - - if (s == NULL) - return; - - /* - * Standard reserve bit check - */ - if ((cdb[1] & 0xc0) || cdb[2] || cdb[3] || cdb[4] || cdb[5] || - cdb[6] || SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - service_action = cdb[1] & 0x1f; - request_len = (cdb[7] << 8) | cdb[8]; - switch (service_action) { - case SSC_READ_POS_SHORT_FORM: - alloc_len = max(request_len, sizeof (*sf)); - if ((data = memalign(sizeof (void *), alloc_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - sf = (pos_short_form_t *)data; - bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm, - &mark, sizeof (mark)); - if ((mark.o_fm.bom == True) && - (s->s_cur_rec == sizeof (ssc_obj_mark_t))) - sf->bop = 1; - bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm + - s->s_cur_rec, &mark, sizeof (mark)); - sf->first_obj[0] = hibyte(hiword(mark.o_rm.obj_id)); - sf->first_obj[1] = lobyte(hiword(mark.o_rm.obj_id)); - sf->first_obj[2] = hibyte(loword(mark.o_rm.obj_id)); - sf->first_obj[3] = lobyte(loword(mark.o_rm.obj_id)); - - /* - * We mark the last object to be the same as the first - * object which indicates that nothing is currently - * buffered. - */ - sf->last_obj[0] = sf->first_obj[0]; - sf->last_obj[1] = sf->first_obj[1]; - sf->last_obj[2] = sf->first_obj[2]; - sf->last_obj[3] = sf->first_obj[3]; - - break; - - case SSC_READ_POS_LONG_FORM: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - if (trans_send_datain(cmd, (char *)data, request_len, 0, ssc_free, - True, data) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -ssc_rpt_density(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_density_t *d; - ssc_density_media_t *dm; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - size_t cap = s->s_size / (1024 * 1024); - int medium_type, - request_len, - alloc_len; - void *data; - - if (s == NULL) - return; - - if ((cdb[1] & 0xfc) || cdb[2] || cdb[3] || cdb[4] || cdb[5] || - cdb[6] || SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - medium_type = cdb[1] & 0x2; - request_len = (cdb[7] << 8) | cdb[8]; - alloc_len = max(request_len, max(sizeof (*d), sizeof (*dm))); - if ((data = memalign(sizeof (void *), alloc_len)) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - if (medium_type == 0) { - d = (ssc_density_t *)data; - d->d_hdr.len = htons(sizeof (*d) - - sizeof (ssc_density_header_t)); - d->d_prim_code = 1; - d->d_wrtok = 1; - d->d_deflt = 1; - d->d_tracks[1] = 1; - d->d_capacity[0] = hibyte(hiword(cap)); - d->d_capacity[1] = lobyte(hiword(cap)); - d->d_capacity[2] = hibyte(loword(cap)); - d->d_capacity[3] = lobyte(loword(cap)); - bcopy(cmd->c_lu->l_common->l_vid, d->d_organization, - min(sizeof (d->d_organization), - strlen(cmd->c_lu->l_common->l_vid))); - bcopy(cmd->c_lu->l_common->l_pid, d->d_description, - min(sizeof (d->d_description), - strlen(cmd->c_lu->l_common->l_pid))); - } else { - dm = (ssc_density_media_t *)data; - dm->d_hdr.len = htons(sizeof (*d) - - sizeof (ssc_density_header_t)); - bcopy(cmd->c_lu->l_common->l_vid, d->d_organization, - min(sizeof (d->d_organization), - strlen(cmd->c_lu->l_common->l_vid))); - bcopy(cmd->c_lu->l_common->l_pid, dm->d_description, - min(sizeof (dm->d_description), - strlen(cmd->c_lu->l_common->l_pid))); - } - - if (trans_send_datain(cmd, (char *)data, request_len, 0, ssc_free, - True, (emul_handle_t)data) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } -} - -/*ARGSUSED*/ -static void -ssc_write_fm(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - int marks_requested; - off_t next_size; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - ssc_obj_mark_t mark_fm; - - if (s == NULL) - return; - - if ((cdb[1] & 0xfc) || SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0x00); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - marks_requested = (cdb[2] << 16) | (cdb[3] << 8) | cdb[4]; - while (marks_requested--) { - /* - * Get the last file-mark and update it's size. - */ - bcopy((char *)cmd->c_lu->l_common->l_mmap + s->s_cur_fm, - &mark_fm, sizeof (mark_fm)); - if (mark_fm.som_sig != SSC_OBJ_SIG) { - spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - next_size = mark_fm.o_fm.size - s->s_cur_rec; - mark_fm.o_fm.size = s->s_cur_rec; - bcopy(&mark_fm, (char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm, sizeof (mark_fm)); - - /* - * Write new mark and update internal location of mark. - */ - mark_fm.o_fm.last_obj_id = - find_last_obj_id((char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm, s->s_cur_rec); - mark_fm.o_fm.bom = False; - mark_fm.o_fm.size = next_size; - s->s_cur_fm += s->s_cur_rec; - s->s_cur_rec = sizeof (ssc_obj_mark_t); - s->s_prev_rec = s->s_cur_rec; - bcopy(&mark_fm, (char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm, sizeof (mark_fm)); - mark_fm.o_fm.size = 0; - bcopy(&mark_fm, (char *)cmd->c_lu->l_common->l_mmap + - s->s_cur_fm + s->s_cur_rec, sizeof (mark_fm)); - } - trans_send_complete(cmd, STATUS_GOOD); -} - -/*ARGSUSED*/ -static void -ssc_locate(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ -} - -/*ARGSUSED*/ -static void -ssc_erase(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_obj_mark_t mark; - ssc_params_t *s = (ssc_params_t *)T10_PARAMS_AREA(cmd); - - if (s == NULL) - return; - - bzero(&mark, sizeof (mark)); - mark.som_sig = SSC_OBJ_SIG; - mark.som_type = SSC_OBJ_TYPE_FM; - mark.o_fm.bom = True; - mark.o_fm.eom = False; - mark.o_fm.size = s->s_size - sizeof (mark); - - bcopy(&mark, (char *)cmd->c_lu->l_common->l_mmap, sizeof (mark)); -} - -/*ARGSUSED*/ -static void -ssc_load(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - ssc_params_t *s = T10_PARAMS_AREA(cmd); - t10_lu_common_t *lu = cmd->c_lu->l_common; - ssc_obj_mark_t mark; - - /* - * SSC-3, revision 02, section 7.2 LOAD/UNLOAD command - * Check for various reserve bits. - */ - if ((cdb[1] & ~SSC_LOAD_CMD_IMMED) || cdb[2] || cdb[3] || - (cdb[4] & ~(SSC_LOAD_CMD_LOAD | SSC_LOAD_CMD_RETEN | - SSC_LOAD_CMD_EOT | SSC_LOAD_CMD_HOLD)) || - SAM_CONTROL_BYTE_RESERVED(cdb[5])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - queue_prt(mgmtq, Q_STE_NONIO, "SSC%x LUN%d load bits 0x%x", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, cdb[4]); - - /* - * There are four possible actions based on the LOAD and HOLD - * bits. - */ - switch (cdb[4] & (SSC_LOAD_CMD_LOAD|SSC_LOAD_CMD_HOLD)) { - case SSC_LOAD_CMD_LOAD|SSC_LOAD_CMD_HOLD: - /* - * Load the media into the system if not already done - * so, but do not position tape. The EOT and RETEN should - * be zero. Since this emulation currently is always available - * we're good to go. - */ - break; - - case SSC_LOAD_CMD_LOAD: - /* - * Without the HOLD bit the tape should be positioned at - * the beginning of partition 0. - */ - s->s_cur_fm = 0; - s->s_cur_rec = sizeof (ssc_obj_mark_t); - break; - - case SSC_LOAD_CMD_HOLD: - /* - * Without the LOAD bit we leave the tape online, but look - * at the RETEN and EOT bits. The RETEN doesn't mean anything - * for this virtual tape, but we can reposition to EOT. - */ - if (cdb[4] & SSC_LOAD_CMD_EOT) { - /*CONSTANTCONDITION*/ - while (1) { - bcopy((char *)lu->l_mmap + s->s_cur_fm, &mark, - sizeof (mark)); - if (mark.som_sig != SSC_OBJ_SIG) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d, bad sig mark: " - "expected=0x%x, got=0x%x", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - SSC_OBJ_SIG, mark.som_sig); - spc_sense_create(cmd, - KEY_MEDIUM_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (mark.som_type != SSC_OBJ_TYPE_FM) { - queue_prt(mgmtq, Q_STE_ERRS, - "SSC%x LUN%d, bad mark type: " - "expected=0x%x, got=0x%x", - cmd->c_lu->l_targ->s_targ_num, - cmd->c_lu->l_common->l_num, - SSC_OBJ_TYPE_FM, mark.som_type); - spc_sense_create(cmd, - KEY_MEDIUM_ERROR, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - if (mark.o_fm.eom == True) - break; - s->s_cur_fm += mark.o_fm.size; - } - } - break; - - case 0: - /* - * Unload the current tape. - */ - - break; - } - trans_send_complete(cmd, STATUS_GOOD); -} - -/*ARGSUSED*/ -static void -ssc_logsense(t10_cmd_t *cmd, uint8_t *cdb, size_t cdb_len) -{ - spc_log_supported_pages_t p; - void *v; - - /* - * Reserve bit checks - */ - if ((cdb[1] & ~(SSC_LOG_SP|SSC_LOG_PPC)) || cdb[3] || cdb[4] || - SAM_CONTROL_BYTE_RESERVED(cdb[9])) { - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0); - trans_send_complete(cmd, STATUS_CHECK); - return; - } - - queue_prt(mgmtq, Q_STE_ERRS, "SSC%x LUN%d page code 0x%x", - cmd->c_lu->l_targ->s_targ_num, cmd->c_lu->l_common->l_num, cdb[2]); - - switch (cdb[2] & SPC_LOG_PAGE_MASK) { - case 0: - if ((v = malloc(sizeof (p))) == NULL) { - trans_send_complete(cmd, STATUS_BUSY); - return; - } - bzero(&p, sizeof (p)); - p.length[0] = 1; - bcopy(&p, v, sizeof (p)); - if (trans_send_datain(cmd, (char *)v, sizeof (p), 0, free, - True, (emul_handle_t)v) == False) { - trans_send_complete(cmd, STATUS_BUSY); - } - break; - - default: - spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0); - spc_sense_ascq(cmd, SPC_ASC_INVALID_CDB, 0); - trans_send_complete(cmd, STATUS_CHECK); - break; - } -} - -/* - * []------------------------------------------------------------------[] - * | Support functions for the SSC command set | - * []------------------------------------------------------------------[] - */ -static uint32_t -find_last_obj_id(char *file_mark, off_t eod) -{ - ssc_obj_mark_t rm; - off_t offset = sizeof (ssc_obj_mark_t); - uint32_t obj_id = 0xffffffff; - - bcopy(file_mark + offset, &rm, sizeof (rm)); - while (rm.som_type == SSC_OBJ_TYPE_RM) { - obj_id = rm.o_rm.obj_id; - offset += rm.o_rm.size; - if (offset >= eod) - break; - bcopy(file_mark + offset, &rm, sizeof (rm)); - } - return (obj_id); -} - -static void -ssc_setup_tape(ssc_params_t *s, t10_lu_common_t *lu) -{ - ssc_obj_mark_t mark; - - /* - * Add Begin-of-Partition marker - */ - bzero(&mark, sizeof (mark)); - mark.som_sig = SSC_OBJ_SIG; - mark.som_type = SSC_OBJ_TYPE_FM; - mark.o_fm.bom = True; - mark.o_fm.eom = False; - mark.o_fm.size = s->s_size - sizeof (mark); - bcopy(&mark, lu->l_mmap, sizeof (mark)); - - /* - * Add first file-record with a zero size. - */ - bzero(&mark, sizeof (mark)); - mark.som_sig = SSC_OBJ_SIG; - mark.som_type = SSC_OBJ_TYPE_RM; - mark.o_rm.size = 0; - mark.o_rm.obj_id = 0xffffffff; - bcopy(&mark, (char *)lu->l_mmap + sizeof (ssc_obj_mark_t), - sizeof (mark)); - - /* - * Add End-of-Partiton marker - */ - bzero(&mark, sizeof (mark)); - mark.som_sig = SSC_OBJ_SIG; - mark.som_type = SSC_OBJ_TYPE_FM; - mark.o_fm.bom = False; - mark.o_fm.eom = True; - mark.o_fm.size = 0; - bcopy(&mark, (char *)lu->l_mmap + s->s_size - sizeof (mark), - sizeof (mark)); -} - -static char * -sense_compression(ssc_params_t *s, char *data) -{ - ssc_data_compression_t d; - - bzero(&d, sizeof (d)); - d.mode_page.code = MODE_SENSE_COMPRESSION; - d.mode_page.length = sizeof (d) - sizeof (struct mode_page); - bcopy(&d, data, sizeof (d)); - - return (data + sizeof (d)); -} - -static char * -sense_dev_config(ssc_params_t *s, char *data) -{ - ssc_device_config_t d; - - bzero(&d, sizeof (d)); - d.mode_page.code = MODE_SENSE_DEV_CONFIG; - d.mode_page.length = sizeof (d) - sizeof (struct mode_page); - d.lois = 1; - d.socf = 1; - d.rewind_on_reset = 1; - bcopy(&d, data, sizeof (d)); - - return (data + sizeof (d)); -} - -static void -ssc_free(emul_handle_t e) -{ - free(e); -} - -/* - * []---- - * | Command table for SSC emulation. This is at the end of the file because - * | it's big and ugly. ;-) To make for fast translation to the appropriate - * | emulation routine we just have a big command table with all 256 possible - * | entries. Most will report STATUS_CHECK, unsupport operation. By doing - * | this we can avoid error checking for command range. - * []---- - */ -static scsi_cmd_table_t ssc_table[] = { - /* 0x00 -- 0x0f */ - { spc_tur, NULL, NULL, "TEST_UNIT_READY" }, - { ssc_rewind, NULL, NULL, "REWIND"}, - { spc_unsupported, NULL, NULL, NULL }, - { spc_request_sense, NULL, NULL, "REQUEST_SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_read_limits, NULL, NULL, "READ BLOCK LIMITS"}, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_read, NULL, ssc_read_cmplt, "READ(6)" }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_write, ssc_write_data, ssc_write_cmplt, "WRITE(6)" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x10 -- 0x1f */ - { ssc_write_fm, NULL, NULL, "WRITE_FILEMARKS(6)"}, - { ssc_space, NULL, NULL, "SPACE(6)"}, - { spc_inquiry, NULL, NULL, "INQUIRY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_mselect, spc_mselect_data, NULL, "MODE_SELECT(6)" }, - { spc_request_sense, NULL, NULL, "RESERVE" }, - { spc_request_sense, NULL, NULL, "RELEASE" }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_erase, NULL, NULL, "ERASE(6)"}, - { ssc_msense, NULL, NULL, "MODE_SENSE(6)" }, - { ssc_load, NULL, NULL, "LOAD_UNLOAD" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_send_diag, NULL, NULL, "SEND_DIAG" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x20 -- 0x2f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "READ_CAPACITY" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_read, NULL, ssc_read_cmplt, "READ_G1" }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_write, ssc_write_data, ssc_write_cmplt, "WRITE_G1" }, - { ssc_locate, NULL, NULL, "LOCATE(10)"}, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x30 -- 0x3f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_read_pos, NULL, NULL, "READ POSITION"}, - { spc_unsupported, NULL, NULL, "SYNC_CACHE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x40 -- 0x4f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_rpt_density, NULL, NULL, "REPORT DENSITY SUPPORT"}, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_logsense, NULL, NULL, "LOG SENSE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x50 -- 0x5f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x60 -- 0x6f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x70 -- 0x7f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x80 -- 0x8f */ - { ssc_write_fm, NULL, NULL, "WRITE_FILEMARKS(16)"}, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_read, NULL, ssc_read_cmplt, "READ_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_write, ssc_write_data, ssc_write_cmplt, "WRITE_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0x90 -- 0x9f */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { ssc_locate, NULL, NULL, "LOCATE(16)"}, - { ssc_erase, NULL, NULL, "ERASE" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, "SVC_ACTION_G4" }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xa0 - 0xaf */ - { spc_report_luns, NULL, NULL, "REPORT_LUNS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_report_tpgs, NULL, NULL, "REPORT_TPGS" }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xb0 -- 0xbf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xc0 -- 0xcf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xd0 -- 0xdf */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xe0 -- 0xef */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - - /* 0xf0 -- 0xff */ - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, - { spc_unsupported, NULL, NULL, NULL }, -}; diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_ssc.h b/usr/src/cmd/iscsi/iscsitgtd/t10_ssc.h deleted file mode 100644 index 6096138899..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/t10_ssc.h +++ /dev/null @@ -1,317 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _T10_SSC_H -#define _T10_SSC_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Implementation specific headers for SCSI Streaming Commands (Tapes) - */ - -#ifdef __cplusplus -extern "C" { -#endif - - -#define SSC_SPACE_CODE_BLOCKS 0x00 /* Mandatory support */ -#define SSC_SPACE_CODE_FILEMARKS 0x01 /* Mandatory support */ -#define SSC_SPACE_CODE_SEQ_FILEMARKS 0x02 /* Optional support */ -#define SSC_SPACE_CODE_END_OF_DATA 0x03 /* Optional support */ - -#define SSC_READ_POS_SHORT_FORM 0x00 -#define SSC_READ_POS_LONG_FORM 0x06 - -#define SSC_OBJ_SIG 0x22005454 -#define SSC_OBJ_TYPE_FM 1 -#define SSC_OBJ_TYPE_RM 2 - -#define SSC_REWIND_IMMED 0x01 - -/* - * SSC-3, revision 01c, section 7.2 - * LOAD/UNLOAD bits - */ -#define SSC_LOAD_CMD_LOAD 0x01 -#define SSC_LOAD_CMD_RETEN 0x02 -#define SSC_LOAD_CMD_EOT 0x04 -#define SSC_LOAD_CMD_HOLD 0x08 -/* ---- bit 0 of byte 1 ---- */ -#define SSC_LOAD_CMD_IMMED 0x01 - -/* - * On disk file and record mark object structure. - */ -typedef struct ssc_obj_mark { - uint32_t som_sig; - uint32_t som_type; - union { - struct { - Boolean_t bom, - eom; - off_t size; - uint32_t num, - last_obj_id; - } _fm_; - struct { - off_t size; - /* - * SSC-3 Revision 1c, Section 3.1.40 - * Object Identifier relative to beginning of - * partition. - */ - uint32_t obj_id; - } _rm_; - char _filler_[512 - (sizeof (uint32_t) * 2)]; - } _u_; -} ssc_obj_mark_t; - -#define o_fm _u_._fm_ -#define o_rm _u_._rm_ - -/* - * In core structure which indicates current file-mark and record-mark - */ -typedef struct ssc_params { - Boolean_t s_fast_write_ack; - off_t s_size; - off_t s_cur_rec, /* starts at sizeof (ssc_obj_mark) */ - s_prev_rec, - s_cur_fm; /* starts at 0 */ - t10_lu_state_t s_state; -} ssc_params_t; - -/* - * During asynchronous I/O there are a few things needed to complete - * the operation. - */ -typedef struct ssc_io { - /* - * Look at SBC for the reason that this member must be first - */ - t10_aio_t sio_aio; - - t10_cmd_t *sio_cmd; - - char *sio_data; - size_t sio_data_len; - off_t sio_offset; /* offset from s_cur_rec */ - size_t sio_total; -} ssc_io_t; - -/* - * READ POSITION data format, short form - */ -typedef struct pos_short_form { -#if defined(_BIT_FIELDS_LTOH) - uchar_t rsvd2 : 1, - perr : 1, - lolu : 1, - rsvd1 : 1, - bycu : 1, - locu : 1, - eop : 1, - bop : 1; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t bop : 1, - eop : 1, - locu : 1, - bycu : 1, - rsvd1 : 1, - lolu : 1, - perr : 1, - rsvd2 : 1; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t partition, - rsvd3[2], - first_obj[4], - last_obj[4], - rsvd4, - objs_in_buf[3], - bytes_in_buf[4]; -} pos_short_form_t; - -/* - * REPORT DENSITY SUPPORT header - */ -typedef struct ssc_density_header { - uint16_t len, - rsvd; -} ssc_density_header_t; - -typedef struct ssc_density { - ssc_density_header_t d_hdr; - uchar_t d_prim_code, - d_secondary_code; -#if defined(_BIT_FIELDS_LTOH) - uchar_t d_dlv : 1, - d_rsvd : 4, - d_deflt : 1, - d_dup : 1, - d_wrtok : 1; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t d_wrtok : 1, - d_dup : 1, - d_deflt : 1, - d_rsvd : 4, - d_dlv : 1; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t d_len[2], - d_bpm[3], - d_width[2], - d_tracks[2], - d_capacity[4], - d_organization[8], - d_name[8], - d_description[20]; -} ssc_density_t; - -typedef struct ssc_density_media { - ssc_density_header_t d_hdr; - uchar_t d_type, - d_resvd1, - d_len[2], - d_num_codes, - d_codes[9], - d_width[2], - d_medium_len[2], - d_rsvd2[2], - d_organization[8], - d_medium_name[8], - d_description[20]; -} ssc_density_media_t; - -/* - * MODE_SENSE/MODE_SELECT, Page Code 0xf - * Data Compression - */ -typedef struct ssc_data_compression { - struct mode_page mode_page; -#if defined(_BIT_FIELDS_LTOH) - uchar_t c_rsvd1 : 6, - c_dcc : 1, - c_dce : 1; - uchar_t c_rsdv2 : 5, - c_red : 2, - c_dde : 1; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t c_dce : 1, - c_dcc : 1, - c_rsvd1 : 6; - uchar_t c_dde : 1, - c_red : 2, - c_rsvd2 : 5; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t c_compression_algorithm[4], - c_decompression_algorithm[4], - c_rsvd3[4]; -} ssc_data_compression_t; - -/* - * MODE_SENSE/MODE_SELECT, Page Code 0x10 - * Device Configuration - */ -typedef struct ssc_device_config { - struct mode_page mode_page; -#if defined(_BIT_FIELDS_LTOH) - uchar_t active_format : 5, - caf : 1, - obsolete1 : 1, - rsvd : 1; - uchar_t active_partion, - wo_buf_ratio, - ro_buf_ratio, - wr_delay_time[2]; - uchar_t rew : 1, - robo : 1, - socf : 2, - avc : 1, - obsolete2 : 1, - lois : 1, - obr : 1; - uchar_t obsolete3; - uchar_t bam : 1, - baml : 1, - swp : 1, - sew : 1, - eeg : 1, - eod_defined : 3; - uchar_t obj_size_ew[3], - data_comp_algorithm; - uchar_t prmwp : 1, - perswp : 1, - asocwp : 1, - rewind_on_reset : 2, - oir : 1, - wtre : 2; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t rsvd : 1, - obsolete1 : 1, - caf : 1, - active_format : 5; - uchar_t active_partion, - wo_buf_ratio, - ro_buf_ratio, - wr_delay_time[2]; - uchar_t obr : 1, - lois : 1, - obsolete2 : 1, - avc : 1, - socf : 2, - robo : 1, - rew : 1; - uchar_t obsolete3; - uchar_t eod_defined : 3, - eeg : 1, - sew : 1, - swp : 1, - baml : 1, - bam : 1; - uchar_t obj_size_ew[3], - data_comp_algorithm; - uchar_t wtre : 2, - oir : 1, - rewind_on_reset : 2, - asocwp : 1, - perswp : 1, - prmwp : 1; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif -} ssc_device_config_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _T10_SSC_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/target.h b/usr/src/cmd/iscsi/iscsitgtd/target.h deleted file mode 100644 index e07ec6601c..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/target.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 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 _TARGET_H -#define _TARGET_H - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define DEFAULT_CONFIG "/etc/iscsi/" -#define DEFAULT_CONFIG_LOCATION DEFAULT_CONFIG "target_config.xml" -#define DEFAULT_TARGET_BASEDIR DEFAULT_CONFIG -#define DEFAULT_TARGET_LOG "/tmp/target_log" - -/* - * []------------------------------------------------------------------[] - * | Common strings which are used throughout the target. | - * []------------------------------------------------------------------[] - */ -/* - * Target type strings are used to distinguish between the emulated types. - * These strings are stored in the params file so they must not be changed - * without thinking about upgrade issues. - */ -#define TGT_TYPE_DISK "disk" -#define TGT_TYPE_TAPE "tape" -#define TGT_TYPE_OSD "osd" -#define TGT_TYPE_RAW "raw" -#define TGT_TYPE_INVALID "invalid" - -/* - * During the creation phase of a LU it starts out offline during block - * initialization, once initialization is complete it will transition to - * online. If during the initialization an error occurs it will be so marked. - */ -#define TGT_STATUS_OFFLINE "offline" -#define TGT_STATUS_ONLINE "online" -#define TGT_STATUS_ERRORED "errored" - -/* - * Base file names for the logical units (LU). The format used is params.%d and - * lun.%d These are used both to build the LU name and when searching the - * target directory for valid luns. Don't change these names unless the upgrade - * path has been thought about. - */ -#define PARAMBASE "params." -#define LUNBASE "lun." -#define OSDBASE "osd_root." -#define PERSISTENCEBASE "pgr." -#define ISCSI_TARGET_ALIAS "TargetAlias" -#define ZVOL_PATH "/dev/zvol/rdsk/" - -/* - * Base file name for persistent reservation data (PR). The format used is pr. - * This name is used both to build the PR name and when searching the target - * directory for persistent reservation data. Don't change these names unless - * the upgrade path has been thought about. - */ -#define PRBASE "persistent_reservations" - -/* - * The IQN names that are created use libuuid + the local target name - * as the idr_str portion of: iqn.1986-03.com.sun:<version>:<id_str> - * In case this changes we also include a version number. Currently - * version 1 is used by the Solaris iSCSI Initiator which has the MAC address, - * timestamp, and hostname. - */ -#define TARGET_NAME_VERS 2 -#define TARGET_NOFILE 10000 - -/* - * Minimum and maximum values for Target Portal Group Tag as specified - * by RFC3720 - */ -#define TPGT_MIN 1 -#define TPGT_MAX 65535 - -/* - * Minimum and maximum values for MaxRecvDataSegmentLength - */ -#define MAXRCVDATA_MIN 512 -#define MAXRCVDATA_MAX ((1 << 24) - 1) - -/* - * Major/minor versioning for the configuration files. - * If we find a configuration file that has a higher - * major number than we support we exit. Major number - * changes are for radical structure differences. Shouldn't - * happen, but we've got a means of detecting such a situation - * a bailing out before doing any damage. Minor number changes - * mean additions to the current format have been added. For - * right now, we use -1, which means ignore the minor number. In - * the future it would be possible for the software to determine - * that a file had certain additions, but maybe not all changes. - */ -#define XML_VERS_MAIN_MAJ 1 -#define XML_VERS_MAIN_MIN -1 -#define XML_VERS_TARG_MAJ 1 -#define XML_VERS_TARG_MIN -1 -#define XML_VERS_LUN_MAJ 1 -#define XML_VERS_LUN_MIN -1 -#define XML_VERS_RESULT_MAJ 1 -#define XML_VERS_RESULT_MIN -1 - -/* - * Default values of the LUN parameters - */ -#define DEFAULT_LUN_SIZE ((1024 * 1024 * 1024) / 512) -#define DEFAULT_RPM 7200 -#define DEFAULT_HEADS 16 -#define DEFAULT_CYLINDERS 100 -#define DEFAULT_SPT 128 -#define DEFAULT_BYTES_PER 512 -#define DEFAULT_INTERLEAVE 1 -#define DEFAULT_PID "SOLARIS" -#define DEFAULT_VID "SUN" -#define DEFAULT_REVISION "1" - -/* - * SPC-3 revision 21c, section 7.6.4.4.4 - * EUI-64 based 16-byte IDENTIFIER field format - */ -typedef struct eui_16 { - uchar_t e_vers, - e_resrv1, - e_mac[6], - e_company_id[3], - e_resv2, - e_timestamp[4]; -} eui_16_t; - -/* - * SPC-4 revision 11, section 7.6.3.6.5 - * NAA IEEE Registered Extended designator format - */ -typedef struct naa_16 { -#if defined(_BIT_FIELDS_LTOH) - uchar_t n_company_id_hi : 4, - n_naa : 4; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t n_naa : 4, - n_company_id_hi : 4; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t n_company_id_b1, - n_company_id_b2; -#if defined(_BIT_FIELDS_LTOH) - uchar_t n_resv1 : 4, - n_company_id_lo : 4; -#elif defined(_BIT_FIELDS_HTOL) - uchar_t n_company_id_lo : 4, - n_resv1 : 4; -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif - uchar_t n_timestamp[4]; - uchar_t n_resv2; - uchar_t n_mac[6]; - uchar_t n_resv3; -} naa_16_t; - -#define SUN_EUI_16_VERS 1 -#define SUN_NAA_16_TYPE 6 - -#define SUN_INQUIRY_ID_TYPE(GUID) \ - (((naa_16_t *)(GUID))->n_naa == SUN_NAA_16_TYPE ? \ - SPC_INQUIRY_ID_TYPE_NAA : SPC_INQUIRY_ID_TYPE_EUI) - -#define SUN_EN 0x144f -#define MIN_VAL 4 - -#ifndef min -#define min(a, b) ((a) > (b) ? (b) : (a)) -#endif -#ifndef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#endif - -typedef struct { - char *name; - char *(*func)(char *, char *); - char *delete_name; -} admin_table_t; - -#include <sys/socket.h> -#include <umem.h> -#include <iscsitgt_impl.h> -#include "queue.h" - -void create_func(tgt_node_t *, target_queue_t *, target_queue_t *, ucred_t *); -void modify_func(tgt_node_t *, target_queue_t *, target_queue_t *, ucred_t *); -void remove_func(tgt_node_t *, target_queue_t *, target_queue_t *, ucred_t *); -void list_func(tgt_node_t *, target_queue_t *, target_queue_t *, ucred_t *); -void logout_targ(char *targ); -char *update_basedir(char *, char *); -char *valid_radius_srv(char *name, char *prop); -char *valid_isns_srv(char *name, char *prop); -Boolean_t if_find_mac(target_queue_t *mgmt); -void if_target_address(char **text, int *text_length, struct sockaddr *sp); - -extern admin_table_t admin_prop_list[]; -extern char *target_basedir; -extern char *target_log; -extern char *config_file; -extern char *pgr_basedir; -extern tgt_node_t *targets_config; -extern tgt_node_t *main_config; -extern uchar_t mac_addr[]; -extern size_t mac_len; -extern int main_vers_maj, - main_vers_min, - targets_vers_maj, - targets_vers_min, - iscsi_port; -extern Boolean_t enforce_strict_guid, - thin_provisioning, - disable_tpgs, - dbg_timestamps, - pgr_persist; -extern pthread_rwlock_t targ_config_mutex; -extern umem_cache_t *iscsi_cmd_cache, - *t10_cmd_cache, - *queue_cache; - -#ifdef __cplusplus -} -#endif - -#endif /* _TARGET_H */ diff --git a/usr/src/cmd/iscsi/iscsitgtd/util.c b/usr/src/cmd/iscsi/iscsitgtd/util.c deleted file mode 100644 index 31863e6328..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/util.c +++ /dev/null @@ -1,1844 +0,0 @@ -/* - * 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 <strings.h> -#include <stdlib.h> -#include <unistd.h> -#include <dirent.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <inttypes.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <errno.h> -#include <utility.h> -#include <fcntl.h> -#include <syslog.h> - -#include <iscsitgt_impl.h> -#include "target.h" -#include "utility.h" -#include "errcode.h" -#include "isns_client.h" -#include <sys/scsi/generic/commands.h> -#include "mgmt_scf.h" -#include "t10_spc.h" - -#define CRC32_STR "CRC32C" -#define NONE_STR "None" - -static thick_provo_t *thick_head, - *thick_tail; -pthread_mutex_t thick_mutex; - -static Boolean_t connection_parameters_get(iscsi_conn_t *c, char *targ_name); -static Boolean_t util_create_guid_naa(char **guid); - -void -util_init() -{ - (void) pthread_mutex_init(&thick_mutex, NULL); -} - -/* - * []---- - * | check_access -- see if the requesting initiator is in the ACL - * | - * | Optionally will also check to see if this initiator requires - * | authentication. - * []---- - */ -Boolean_t -check_access(tgt_node_t *targ, char *initiator_name, Boolean_t req_chap) -{ - tgt_node_t *acl; - tgt_node_t *inode = NULL; - tgt_node_t *tgt_initiator = NULL; - char *dummy; - Boolean_t valid = False; - Boolean_t found_chap = False; - Boolean_t access = False; - - /* - * If ISNS is enable check for access privilege from isns server - */ - if (isns_enabled() == True) { - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &dummy) - == False) { - return (False); - } - access = isns_qry_initiator(dummy, initiator_name); - free(dummy); - if (req_chap == False) { - return (access); - } - - /* Need to check if CHAP is needed for initiator */ - while ((inode = tgt_node_next_child(main_config, - XML_ELEMENT_INIT, inode)) != NULL) { - if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) - == True) { - if (strcmp(dummy, initiator_name) == 0) { - free(dummy); - if (tgt_find_value_str(inode, - XML_ELEMENT_CHAPSECRET, &dummy) - == True) { - free(dummy); - found_chap = True; - break; - } - } - } - } - if (access == True) { - if ((req_chap == True) && (found_chap == True)) - access = False; - } - return (access); - } - - /* - * If there's no ACL for this target everyone has access. - */ - if ((acl = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == NULL) - return (True); - - /* - * Find the local initiator name and also save the knowledge - * if the initiator had a CHAP secret. - */ - inode = NULL; - while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, - inode)) != NULL) { - if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) == - True) { - if (strcmp(dummy, initiator_name) == 0) { - free(dummy); - if (tgt_find_value_str(inode, - XML_ELEMENT_CHAPSECRET, &dummy) == True) { - free(dummy); - found_chap = True; - } - break; - } else { - free(dummy); - } - } - } - - if ((acl != NULL) && (inode == NULL)) - return (False); - - while ((tgt_initiator = tgt_node_next(acl, XML_ELEMENT_INIT, - tgt_initiator)) != NULL) { - - if (strcmp(inode->x_value, tgt_initiator->x_value) == 0) { - valid = True; - break; - } - } - - if (valid == True) { - - /* - * If req_chap is True it means the login code hasn't gone - * through the authentication phase and it's trying to - * determine if the initiator should have done so. If - * we find a CHAP-secret then this routine will fail. - * No CHAP-secret for an initiator just means that a - * simple ACL list is used. This can be spoofed easily - * enough and is mainly used to limit the number of - * targets an initiator would see. - */ - if ((req_chap == True) && (found_chap == True)) - valid = False; - } - - return (valid); -} - -/* - * []---- - * | convert_local_tpgt -- Convert a local tpgt name to real addresses - * | - * | To simplify the configuration files targets only have a target portal - * | group tag string(s) associated. In the main configuration file there's - * | a tpgt element which has one or more ip-address elements. So the tag - * | is located and the actual data is inserted into the outgoing stream. - * []---- - */ -static Boolean_t -convert_local_tpgt(char **text, int *text_length, char *local_tpgt) -{ - tgt_node_t *tpgt = NULL; - tgt_node_t *x; - char buf[80]; - char ipaddr[4]; - - while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, - tpgt)) != NULL) { - if (strcmp(tpgt->x_value, local_tpgt) == 0) { - - /* - * The only children of the tpgt element are - * ip-address elements. The value of each element is - * the string we need to use. So, we don't need to - * check the node's name to see if this is correct or - * not. - */ - if ((tpgt = tgt_node_next(tpgt, XML_ELEMENT_IPADDRLIST, - NULL)) == NULL) { - return (False); - } - - x = NULL; - while ((x = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, x)) - != NULL) { - if (inet_pton(AF_INET, x->x_value, &ipaddr) - == 1) { - /* - * Valid IPv4 address - */ - (void) snprintf(buf, sizeof (buf), - - "%s,%s", x->x_value, local_tpgt); - } else { - /* - * Invalid IPv4 address - * try with brackets (RFC2732) - */ - (void) snprintf(buf, sizeof (buf), - "[%s],%s", x->x_value, local_tpgt); - } - (void) add_text(text, text_length, - "TargetAddress", buf); - } - break; - } - } - - return (True); -} - -/* - * []---- - * | add_target_address -- find and add any target address information - * []---- - */ -static void -add_target_address(iscsi_conn_t *c, char **text, int *text_length, - tgt_node_t *targ) -{ - tgt_node_t *tpgt_list; - tgt_node_t *tpgt = NULL; - struct sockaddr_in *sp4; - struct sockaddr_in6 *sp6; - /* - * 7 is enough room for the largest TPGT of "65536", the ',' and a NULL - */ - char buf[INET6_ADDRSTRLEN + 7]; - char net_buf[INET6_ADDRSTRLEN]; - - if ((tpgt_list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, - NULL)) == NULL) { - if_target_address(text, text_length, - (struct sockaddr *)&c->c_target_sockaddr); - return; - } - - while ((tpgt = tgt_node_next_child(tpgt_list, XML_ELEMENT_TPGT, - tpgt)) != NULL) { - if (convert_local_tpgt(text, text_length, tpgt->x_value) == - False) { - if (c->c_target_sockaddr.ss_family == AF_INET) { - sp4 = (struct sockaddr_in *) - &c->c_target_sockaddr; - (void) snprintf(buf, sizeof (buf), "%s,%s", - inet_ntop(sp4->sin_family, - (void *)&sp4->sin_addr, - net_buf, sizeof (net_buf)), - tpgt->x_value); - } else { - sp6 = (struct sockaddr_in6 *) - &c->c_target_sockaddr; - (void) snprintf(buf, sizeof (buf), "[%s],%s", - inet_ntop(sp6->sin6_family, - (void *)&sp6->sin6_addr, - net_buf, sizeof (net_buf)), - tpgt->x_value); - } - (void) add_text(text, text_length, "TargetAddress", - buf); - } - } -} - -/* - * []---- - * | add_targets -- add TargetName and TargetAddress to text argument - * | - * | Add targets which this initiator is allowed to see based on - * | the access_list associated with a target. If a target doesn't - * | have an access list then let everyone see it. - * []---- - */ -static Boolean_t -add_targets(iscsi_conn_t *c, char **text, int *text_length) -{ - tgt_node_t *targ = NULL; - Boolean_t rval = True; - char *targ_name = NULL; - - while ((rval == True) && ((targ = tgt_node_next_child(targets_config, - XML_ELEMENT_TARG, targ)) != NULL)) { - - if (check_access(targ, c->c_sess->s_i_name, False) == True) { - - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, - &targ_name) == False) { - rval = False; - break; - } - queue_prt(c->c_mgmtq, Q_CONN_LOGIN, - "CON%x %24s = %s\n", c->c_num, "TargetName", - targ_name); - - (void) add_text(text, text_length, "TargetName", - targ_name); - free(targ_name); - add_target_address(c, text, text_length, targ); - } - } - return (rval); -} - -/* - * []---- - * | add_text -- Add new name/value pair to possibly existing string - * []---- - */ -Boolean_t -add_text(char **text, int *current_length, char *name, char *val) -{ - int dlen = *current_length; - int plen; - char *p; - - /* - * Length is 'name' + separator + 'value' + NULL - */ - plen = strlen(name) + 1 + strlen(val) + 1; - - if (dlen) { - if ((p = (char *)realloc(*text, dlen + plen)) == NULL) - return (False); - } else { - if ((p = (char *)malloc(plen)) == NULL) - return (False); - } - - *text = p; - p = *text + dlen; - - (void) snprintf(p, plen, "%s%c%s", name, ISCSI_TEXT_SEPARATOR, val); - *current_length = dlen + plen; - - return (True); -} - -static void -send_named_msg(iscsi_conn_t *c, msg_type_t t, char *name) -{ - target_queue_t *q = queue_alloc(); - msg_t *m; - name_request_t n; - - n.nr_q = q; - n.nr_name = name; - - queue_message_set(c->c_sessq, 0, t, &n); - m = queue_message_get(q); - queue_message_free(m); - queue_free(q, NULL); -} - -static Boolean_t -parse_digest_vals(Boolean_t *bp, char *name, char *val, char **text, int *len) -{ - Boolean_t rval; - - /* - * It's the initiators data so we'll allow them - * to determine if CRC checks should be enabled - * or not. So, look at the first token, which - * declares their preference, and use that. - */ - if (strncmp(val, CRC32_STR, strlen(CRC32_STR)) == 0) { - *bp = True; - rval = add_text(text, len, name, CRC32_STR); - } else if (strncmp(val, NONE_STR, strlen(NONE_STR)) == 0) { - *bp = False; - rval = add_text(text, len, name, NONE_STR); - } else { - *bp = False; - rval = add_text(text, len, name, "Reject"); - } - - return (rval); -} - -/* - * []---- - * | parse_text -- receive text information from initiator and parse - * | - * | Read in the current data based on the amount which the login PDU says - * | should be available. Add it to the end of previous data if it exists. - * | Previous data would be from a PDU which had the 'C' bit set and was - * | stored in the connection. - * | - * | Once values for parameter name has been selected store outgoing string - * | in text message for response. - * | - * | If errcode is non-NULL the appropriate login error code will be - * | stored. - * []---- - */ -Boolean_t -parse_text(iscsi_conn_t *c, int dlen, char **text, int *text_length, - int *errcode) -{ - char *p = NULL; - char *n; - char *cur_pair; - char param_rsp[32]; - int plen; /* pair length */ - Boolean_t rval = True; - char *target_name = NULL; - char *initiator_name = NULL; - char param_buf[16]; - - if ((p = (char *)malloc(dlen)) == NULL) - return (False); - - /* - * Read in data to buffer. - */ - if (read(c->c_fd, p, dlen) != dlen) { - free(p); - return (False); - } - - queue_prt(c->c_mgmtq, Q_CONN_NONIO, "CON%x Available text size %d\n", - c->c_num, dlen); - - /* - * Read in and toss any pad data - */ - if (dlen % ISCSI_PAD_WORD_LEN) { - char junk[ISCSI_PAD_WORD_LEN]; - int pad_len = ISCSI_PAD_WORD_LEN - (dlen % ISCSI_PAD_WORD_LEN); - - if (read(c->c_fd, junk, pad_len) != pad_len) { - free(p); - return (False); - } - } - - if (c->c_text_area != NULL) { - if ((n = (char *)realloc(c->c_text_area, - c->c_text_len + dlen)) == NULL) { - free(p); - return (False); - } - bcopy(p, n + c->c_text_len, dlen); - - /* - * No longer need the space allocated to 'p' since it - * will point to the aggregated area of all data. - */ - free(p); - - /* - * Point 'p' to this new area for parsing and save the - * combined length in dlen. - */ - p = n; - dlen += c->c_text_len; - - /* - * Clear the indication that space has been allocated - */ - c->c_text_area = NULL; - c->c_text_len = 0; - } - - /* - * At this point 'p' points to the name/value parameters. Need - * to cycle through each pair. - */ - n = p; - while (dlen > 0) { - cur_pair = n; - - plen = strlen(n); - if ((n = strchr(cur_pair, ISCSI_TEXT_SEPARATOR)) == NULL) { - if (errcode != NULL) - *errcode = - (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) | - ISCSI_LOGIN_STATUS_INIT_ERR; - rval = False; - break; - } else - *n++ = '\0'; - - queue_prt(c->c_mgmtq, Q_CONN_LOGIN, "CON%x %-24s = %s\n", - c->c_num, cur_pair, n); - - /* - * At this point, 'cur_pair' points at the name and 'n' - * points at the value. - */ - - /* - * []--------------------------------------------------[] - * | The order of parameters processed matches the | - * | the RFC in section 12. | - * []--------------------------------------------------[] - */ - /* - * 12.1 -- HeaderDigest - * Negotiated - */ - if (strcmp("HeaderDigest", cur_pair) == 0) { - - rval = parse_digest_vals(&c->c_header_digest, - cur_pair, n, text, text_length); - - /* - * 12.1 -- DataDigest - * Negotiated - */ - } else if (strcmp("DataDigest", cur_pair) == 0) { - - rval = parse_digest_vals(&c->c_data_digest, cur_pair, - n, text, text_length); - - /* - * 12.2 -- MaxConnections - * Negotiated - */ - } else if (strcmp("MaxConnections", cur_pair) == 0) { - - /* ---- To be fixed ---- */ - c->c_max_connections = 1; - (void) snprintf(param_rsp, sizeof (param_rsp), - "%d", c->c_max_connections); - rval = add_text(text, text_length, - cur_pair, param_rsp); - - /* - * 12.3 -- SendTargets - * Declarative - */ - } else if (strcmp("SendTargets", cur_pair) == 0) { - - if ((c->c_sess->s_type != SessionDiscovery) && - (strcmp("All", n) == 0)) { - rval = add_text(text, text_length, cur_pair, - "Irrelevant"); - } else { - rval = add_targets(c, text, text_length); - } - - /* - * 12.4 -- TargetName - * Declarative - */ - } else if (strcmp("TargetName", cur_pair) == 0) { - - send_named_msg(c, msg_target_name, n); - target_name = n; - - /* - * 12.5 -- IntiatorName - * Declarative - */ - } else if (strcmp("InitiatorName", cur_pair) == 0) { - - send_named_msg(c, msg_initiator_name, n); - initiator_name = n; - - /* ---- Section 12.6 is handled within TargetName ---- */ - - /* - * 12.7 -- InitiatorAlias - * Declarative - */ - } else if (strcmp("InitiatorAlias", cur_pair) == 0) { - - send_named_msg(c, msg_initiator_alias, n); - - /* - * Sections 12.8 (TargetAddress) and 12.9 - * (TargetPortalGroupTag) are handled during the SendTargets - * processing. - */ - - /* - * 12.10 -- IntialR2T - * Negotiated - */ - } else if (strcmp("InitialR2T", cur_pair) == 0) { - - c->c_initialR2T = True; - rval = add_text(text, text_length, cur_pair, "Yes"); - - /* - * 12.11 -- ImmediateData - * Negotiated - */ - } else if (strcmp("ImmediateData", cur_pair) == 0) { - - /* - * Since we can handle immediate data without - * a problem just echo back what the initiator - * sends. If the initiator decides to violate - * the spec by sending immediate data even though - * they've disabled it, it's their problem and - * we'll deal with the data. - */ - c->c_immediate_data = strcmp(n, "No") ? True : False; - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.12 -- MaxRecvDataSegmentLength - * Declarative - */ - } else if (strcmp("MaxRecvDataSegmentLength", cur_pair) == 0) { - - c->c_max_recv_data = strtol(n, NULL, 0); - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.13 -- MaxBurstLength - * Negotiated - */ - } else if (strcmp("MaxBurstLength", cur_pair) == 0) { - - c->c_max_burst_len = strtol(n, NULL, 0); - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.14 -- FirstBurstLength - * Negotiated - */ - } else if (strcmp("FirstBurstLength", cur_pair) == 0) { - - /* - * We can handle anything the initiator wishes - * to shove in our direction. So, store the value - * in case we ever wish to validate input data, - * but there's no real need to do so. - */ - c->c_first_burst_len = strtol(n, NULL, 0); - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.15 DefaultTime2Wait - * Negotiated - */ - } else if (strcmp("DefaultTime2Wait", cur_pair) == 0) { - - c->c_default_time_2_wait = strtol(n, NULL, 0); - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.16 -- DefaultTime2Retain - * Negotiated - */ - } else if (strcmp("DefaultTime2Retain", cur_pair) == 0) { - - c->c_default_time_2_retain = strtol(n, NULL, 0); - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.17 -- MaxOutstandingR2T - * Negotiated - */ - } else if (strcmp("MaxOutstandingR2T", cur_pair) == 0) { - - /* - * Save the value, but at most we'll toss out - * one R2T packet. - */ - c->c_max_outstanding_r2t = strtol(n, NULL, 0); - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.18 -- DataPDUInOder - * Negotiated - */ - } else if (strcmp("DataPDUInOrder", cur_pair) == 0) { - - /* - * We can handle DataPDU's out of order and - * currently we'll only send them in order. We're - * to far removed from the hardware to see data - * coming off of the platters out of order so - * it's unlikely we'd ever implement this feature. - * Store the parameter and echo back the initiators - * request. - */ - c->c_data_pdu_in_order = strcmp(n, "Yes") == 0 ? - True : False; - rval = add_text(text, text_length, cur_pair, n); - - /* - * 12.19 -- DataSequenceInOrder - * Negotiated - */ - } else if (strcmp("DataSequenceInOrder", cur_pair) == 0) { - - /* - * Currently we're set up to look at and require - * PDU sequence numbers be in order. The check - * now is only done as a prelude to supporting - * MC/S and guaranteeing the order of incoming - * packets on different connections. - */ - c->c_data_sequence_in_order = True; - rval = add_text(text, text_length, cur_pair, "Yes"); - - /* - * 12.20 -- ErrorRecoveryLevel - * Negotiated - */ - } else if (strcmp("ErrorRecoveryLevel", cur_pair) == 0) { - - c->c_erl = 0; - (void) snprintf(param_rsp, sizeof (param_rsp), - "%d", c->c_erl); - rval = add_text(text, text_length, - cur_pair, param_rsp); - - /* - * 12.21 -- SessionType - * Declarative - */ - } else if (strcmp("SessionType", cur_pair) == 0) { - - c->c_sess->s_type = strcmp(n, "Discovery") == 0 ? - SessionDiscovery : SessionNormal; - - - /* - * Appendix A 3.1 -- IFMarker - * Negotiated - */ - } else if (strcmp("IFMarker", cur_pair) == 0) { - - c->c_ifmarker = False; - rval = add_text(text, text_length, cur_pair, "No"); - - /* - * Appendix A 3.1 -- OFMarker - * Negotiated - */ - } else if (strcmp("OFMarker", cur_pair) == 0) { - - c->c_ofmarker = False; - rval = add_text(text, text_length, cur_pair, "No"); - - } else if ((strcmp("AuthMethod", cur_pair) == 0) || - (strcmp("CHAP_A", cur_pair) == 0) || - (strcmp("CHAP_I", cur_pair) == 0) || - (strcmp("CHAP_C", cur_pair) == 0) || - (strcmp("CHAP_N", cur_pair) == 0) || - (strcmp("CHAP_R", cur_pair) == 0)) { - - rval = add_text(&(c->auth_text), &c->auth_text_length, - cur_pair, n); - - } else { - - /* - * It's perfectly legitimate for an initiator to - * send us a parameter we don't currently understand. - * For example, an initiator that supports iSER will - * send an RDMA options parameter. If we respond with - * a valid return value it knows to switch to iSER - * for future processing. - */ - rval = add_text(text, text_length, - cur_pair, "NotUnderstood"); - - /* - * Go ahead a log this information in case we see - * something unexpected. - */ - queue_prt(c->c_mgmtq, Q_CONN_ERRS, - "CON%x Unknown parameter %s=%s\n", - c->c_num, cur_pair, n); - } - - /* - * If parsed both Initiator and Target names have been parsed, - * then it is now time to load the connection parameters. - * - * This may fail because the target doesn't exist or the - * initiator doesn't have permission to access this target. - */ - if ((target_name != NULL) && (initiator_name != NULL)) { - if ((rval = connection_parameters_get(c, target_name)) - == False) { - if ((errcode != NULL) && (*errcode == 0)) - *errcode = - (ISCSI_STATUS_CLASS_INITIATOR_ERR - << 8) | - ISCSI_LOGIN_STATUS_TGT_FORBIDDEN; - } else if ((rval = add_text(text, text_length, - "TargetAlias", c->c_targ_alias)) == True) { - - /* - * Add TPGT now - */ - (void) snprintf(param_buf, sizeof (param_buf), - "%d", c->c_tpgt); - rval = add_text(text, text_length, - "TargetPortalGroupTag", param_buf); - target_name = initiator_name = NULL; - } - } - - if (rval == False) { - /* - * Make sure the caller wants error status and that it - * hasn't already been set. - */ - if ((errcode != NULL) && (*errcode == 0)) - *errcode = - (ISCSI_STATUS_CLASS_TARGET_ERR << 8) | - ISCSI_LOGIN_STATUS_TARGET_ERROR; - break; - } - - /* - * next pair of parameters. 1 is added to include the NULL - * byte and the end of each string. - */ - n = cur_pair + plen + 1; - dlen -= (plen + 1); - } - - if (p != NULL) - free(p); - - return (rval); -} - -/* - * Pre-seed connection parameters to default values - * See RFC 3720 Section 12 - */ -void -connection_parameters_default(iscsi_conn_t *c) -{ - c->c_max_connections = 1; /* MaxConnections */ - c->c_tpgt = 1; /* TargetPortalGroupTag */ - c->c_initialR2T = True; /* InitialR2T */ - c->c_immediate_data = True; /* ImmediateData */ - c->c_max_recv_data = 8192; /* MaxRecvDataSegmentLength */ - c->c_max_burst_len = 262144; /* MaxBurstLength */ - c->c_first_burst_len = 65536; /* FirstBurstLength */ - c->c_default_time_2_wait = 2; /* DefaultTime2Wait */ - c->c_default_time_2_retain = 20; /* DefaultTime2Retain */ - c->c_max_outstanding_r2t = 1; /* MaxOutStandingR2T */ - c->c_data_pdu_in_order = True; /* DataPDUInOrder */ - c->c_data_sequence_in_order = True; /* DataSequenceOrder */ - c->c_erl = 0; /* ErrorRecoveryLevel */ -} - -/* - * []---- - * | find_main_tpgt -- Looks up the IP address and finds a match TPGT - * | - * | If no TPGT for this address exists the routine returns 0 which - * | is an illegal TPGT value. - * []---- - */ -static int -find_main_tpgt(struct sockaddr_storage *pst) -{ - char ip_addr[16]; - tgt_node_t *tpgt = NULL; - tgt_node_t *ip_node = NULL; - struct in_addr addr; - struct in6_addr addr6; - - /* - * Hardly can you believe that such struct-to-struct - * assignment IS valid. - */ - addr = ((struct sockaddr_in *)pst)->sin_addr; - addr6 = ((struct sockaddr_in6 *)pst)->sin6_addr; - - while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, - tpgt)) != NULL) { - - ip_node = NULL; - while ((ip_node = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, - ip_node)) != NULL) { - - if (pst->ss_family == AF_INET) { - - if (inet_pton(AF_INET, ip_node->x_value, - ip_addr) != 1) { - continue; - } - if (bcmp(ip_addr, &addr, - sizeof (struct in_addr)) == 0) { - return (atoi(tpgt->x_value)); - } - } else if (pst->ss_family == AF_INET6) { - - if (inet_pton(AF_INET6, ip_node->x_value, - ip_addr) != 1) { - continue; - } - if (bcmp(ip_addr, &addr6, - sizeof (struct in6_addr)) == 0) { - return (atoi(tpgt->x_value)); - } - } - } - } - - return (0); -} - -/* - * convert_to_tpgt -- return a TPGT based on the target address - * - * If a target doesn't have a TPGT list then just return the default - * value of 1. Otherwise determine which TPGT the target address is - * part of and find that TPGT value in the list of TPGTs this target - * is willing to expose. If the TPGT value is not found in the list - * return zero which will break the connection. - */ -static int -convert_to_tpgt(iscsi_conn_t *c, tgt_node_t *targ) -{ - tgt_node_t *list; - tgt_node_t *tpgt = NULL; - int addr_tpgt, pos_tpgt; - - /* - * If this target doesn't have a list of target portal group tags - * just return the default which is 1. - */ - list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL); - if (list == NULL) - return (1); - - /* - * If we don't find our IP in the general configuration list - * we'll use the default value which is 1 according to RFC3720. - */ - addr_tpgt = find_main_tpgt(&(c->c_target_sockaddr)); - - while ((tpgt = tgt_node_next(list, XML_ELEMENT_TPGT, tpgt)) != NULL) { - (void) tgt_find_value_int(tpgt, XML_ELEMENT_TPGT, &pos_tpgt); - if (pos_tpgt == addr_tpgt) { - return (addr_tpgt); - } - } - - return (0); -} - -/* - * []---- - * | find_target_node -- given a target IQN name, return the XML node - * []---- - */ -tgt_node_t * -find_target_node(char *targ_name) -{ - tgt_node_t *tnode = NULL; - char *iname; - - while ((tnode = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - tnode)) != NULL) { - if (tgt_find_value_str(tnode, XML_ELEMENT_INAME, &iname) == - True) { - if (strcmp(iname, targ_name) == 0) { - free(iname); - return (tnode); - } else - free(iname); - } - } - - return (NULL); -} - -static Boolean_t -connection_parameters_get(iscsi_conn_t *c, char *targ_name) -{ - tgt_node_t *targ, *alias; - Boolean_t rval = False; - - (void) pthread_rwlock_rdlock(&targ_config_mutex); - if ((targ = find_target_node(targ_name)) != NULL) { - - if (check_access(targ, c->c_sess->s_i_name, False) == False) { - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (False); - } - - /* - * Have a valid node for our target. Start looking - * for connection oriented parameters. - */ - if ((c->c_tpgt = convert_to_tpgt(c, targ)) == 0) { - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (False); - } - if ((alias = tgt_node_next(targ, XML_ELEMENT_ALIAS, NULL)) == - NULL) { - (void) tgt_find_value_str(targ, XML_ELEMENT_TARG, - &c->c_targ_alias); - } else { - (void) tgt_find_value_str(alias, XML_ELEMENT_ALIAS, - &c->c_targ_alias); - } - - (void) tgt_find_value_int(targ, XML_ELEMENT_MAXCMDS, - &c->c_maxcmdsn); - rval = True; - } - - (void) pthread_rwlock_unlock(&targ_config_mutex); - return (rval); -} - -Boolean_t -validate_version(tgt_node_t *node, int *maj_p, int *min_p) -{ - char *vers_str = NULL; - char *minor_part; - int maj, min; - - if ((tgt_find_attr_str(node, XML_ELEMENT_VERS, &vers_str) == False) || - (vers_str == NULL)) - return (False); - - maj = strtol(vers_str, &minor_part, 0); - if ((maj > *maj_p) || (minor_part == NULL) || (*minor_part != '.')) { - free(vers_str); - return (False); - } - - min = strtol(&minor_part[1], NULL, 0); - *maj_p = maj; - *min_p = min; - free(vers_str); - - return (True); -} - -/* - * []---- - * | sna_lt -- Serial Number Arithmetic, 32 bits, less than, RFC1982 - * []---- - */ -int -sna_lt(uint32_t n1, uint32_t n2) -{ - return ((n1 != n2) && - (((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) || - ((n1 > n2) && ((n1 - n2) > SNA32_CHECK)))); -} - -/* - * []---- - * sna_lte -- Serial Number Arithmetic, 32 bits, less than, RFC1982 - * []---- - */ -int -sna_lte(uint32_t n1, uint32_t n2) -{ - return ((n1 == n2) || - (((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) || - ((n1 > n2) && ((n1 - n2) > SNA32_CHECK)))); -} - -/* - * util_create_guid -- generate GUID based on the guid type - * id_type: SPC_INQUIRY_ID_TYPE_EUI - - * EUI-64 based 16-byte designator format; - * SPC_INQUIRY_ID_TYPE_NAA - - * NAA IEEE Registered Extended designator format. - * - * SPC-4 revision 11 section 7.6.3.5.4 and 7.6.3.6.5. - * - * Note that now this function is always called with parameter - * id_type SPC_INQUIRY_ID_TYPE_NAA, therefore the code for creating - * EUI-64 based 16-byte format GUID is no longer used. But in order - * to keep backward compatiability and for future extension, all the - * code that has been used for creating old GUIDs should be kept, to - * make the format clear for all possible GUIDs targets might have. - */ -Boolean_t -util_create_guid(char **guid, uchar_t id_type) -{ - eui_16_t eui; - /* - * We only have room for 32bits of data in the GUID. The hiword/loword - * macros will not work on 64bit variables. The work, but produce - * invalid results on Big Endian based machines. - */ - uint32_t tval = (uint_t)time((time_t *)0); - size_t guid_size; - int i, fd; - - /* - * Create the NAA (6) GUID. - */ - if (id_type == SPC_INQUIRY_ID_TYPE_NAA) { - return (util_create_guid_naa(guid)); - } - - if ((mac_len == 0) && (if_find_mac(NULL) == False)) { - - /* - * By default strict GUID generation is enforced. This can - * be disabled by using the correct XML tag in the configuration - * file. - */ - if (enforce_strict_guid == True) - return (False); - - /* - * There's no MAC address available and we've even tried - * a second time to get one. So fallback to using a random - * number for the MAC address. - */ - if ((fd = open("/dev/random", O_RDONLY)) < 0) - return (False); - if (read(fd, &eui, sizeof (eui)) != sizeof (eui)) - return (False); - (void) close(fd); - - eui.e_vers = SUN_EUI_16_VERS; - eui.e_company_id[0] = (SUN_EN >> 16) & 0xff; - eui.e_company_id[1] = (SUN_EN >> 8) & 0xff; - eui.e_company_id[2] = SUN_EN & 0xff; - - } else { - bzero(&eui, sizeof (eui)); - - eui.e_vers = SUN_EUI_16_VERS; - eui.e_company_id[0] = (SUN_EN >> 16) & 0xff; - eui.e_company_id[1] = (SUN_EN >> 8) & 0xff; - eui.e_company_id[2] = SUN_EN & 0xff; - eui.e_timestamp[0] = hibyte(hiword(tval)); - eui.e_timestamp[1] = lobyte(hiword(tval)); - eui.e_timestamp[2] = hibyte(loword(tval)); - eui.e_timestamp[3] = lobyte(loword(tval)); - for (i = 0; i < min(mac_len, sizeof (eui.e_mac)); i++) { - eui.e_mac[i] = mac_addr[i]; - } - - /* - * To prevent duplicate GUIDs we need to sleep for one - * second here since part of the GUID is a time stamp with - * a one second resolution. - */ - (void) sleep(1); - } - - if (tgt_xml_encode((uint8_t *)&eui, sizeof (eui), guid, - &guid_size) == False) { - return (False); - } else - return (True); -} - -Boolean_t -util_create_guid_naa(char **guid) -{ - naa_16_t naa; - /* - * We only have room for 32bits of data in the GUID. The hiword/loword - * macros will not work on 64bit variables. The work, but produce - * invalid results on Big Endian based machines. - */ - uint32_t tval = (uint_t)time((time_t *)0); - size_t guid_size; - int i, fd; - - if ((mac_len == 0) && (if_find_mac(NULL) == False)) { - - /* - * By default strict GUID generation is enforced. This can - * be disabled by using the correct XML tag in the configuration - * file. - */ - if (enforce_strict_guid == True) - return (False); - - /* - * There's no MAC address available and we've even tried - * a second time to get one. So fallback to using a random - * number for the MAC address. - */ - if ((fd = open("/dev/random", O_RDONLY)) < 0) - return (False); - if (read(fd, &naa, sizeof (naa)) != sizeof (naa)) - return (False); - (void) close(fd); - - } else { - bzero(&naa, sizeof (naa)); - - /* - * Set vendor specific identifier and extension. - */ - naa.n_timestamp[0] = hibyte(hiword(tval)); - naa.n_timestamp[1] = lobyte(hiword(tval)); - naa.n_timestamp[2] = hibyte(loword(tval)); - naa.n_timestamp[3] = lobyte(loword(tval)); - for (i = 0; i < min(mac_len, sizeof (naa.n_mac)); i++) { - naa.n_mac[i] = mac_addr[i]; - } - - /* - * To prevent duplicate GUIDs we need to sleep for one - * second here since part of the GUID is a time stamp with - * a one second resolution. - */ - (void) sleep(1); - } - - /* - * Set NAA (6) and IEEE Company_ID. - */ - naa.n_naa = SUN_NAA_16_TYPE; - naa.n_company_id_hi = (SUN_EN >> 20) & 0x0f; - naa.n_company_id_b1 = (SUN_EN >> 12) & 0xff; - naa.n_company_id_b2 = (SUN_EN >> 4) & 0xff; - naa.n_company_id_lo = SUN_EN & 0x0f; - if (tgt_xml_encode((uint8_t *)&naa, sizeof (naa), guid, - &guid_size) == False) { - return (False); - } else - return (True); -} - -/* - * []---- - * | create_geom -- based on size, determine best fit for CHS - * | - * | Given size in bytes, which will be adjusted to blocks, find - * | the best fit for making (C * H * S == blocks) - * | - * | Note that the following algorithm was derived from the - * | common disk label implementation, cmlb_convert_geometry(). - * | - * []---- - */ -void -create_geom(diskaddr_t size, int *cylinders, int *heads, int *spt) -{ - diskaddr_t blocks = size >> 9; /* 512 bytes/block */ - - /* - * For all devices we calculate cylinders using the heads and sectors - * we assign based on capacity of the device. The algorithm is - * designed to be compatible with the way other operating systems - * lay out fdisk tables for X86 and to insure that the cylinders never - * exceed 65535 to prevent problems with X86 ioctls that report - * geometry. - * For some smaller disk sizes we report geometry that matches those - * used by X86 BIOS usage. For larger disks, we use SPT that are - * multiples of 63, since other OSes that are not limited to 16-bits - * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT. - * - * The following table (in order) illustrates some end result - * calculations: - * - * Maximum number of blocks nhead nsect - * - * 2097152 (1GB) 64 32 - * 16777216 (8GB) 128 32 - * 1052819775 (502.02GB) 255 63 - * 2105639550 (0.98TB) 255 126 - * 3158459325 (1.47TB) 255 189 - * 4211279100 (1.96TB) 255 252 - * 5264098875 (2.45TB) 255 315 - * ... - */ - - if (blocks <= 0x200000) { - *heads = 64; - *spt = 32; - } else if (blocks <= 0x01000000) { - *heads = 128; - *spt = 32; - } else { - *heads = 255; - - /* make sectors-per-track be smallest multiple of 63 */ - *spt = ((blocks + - (UINT16_MAX * 255 * 63) - 1) / - (UINT16_MAX * 255 * 63)) * 63; - - if (*spt == 0) - *spt = (UINT16_MAX / 63) * 63; - } - - /* cyls/dsk = (sectors/dsk) / (sectors/trk * tracks/cyl) */ - *cylinders = blocks / (*spt * *heads); -} - -/* - * []---- - * | strtol_multiplier -- common method to deal with human type numbers - * []---- - */ -Boolean_t -strtoll_multiplier(char *str, uint64_t *sp) -{ - char *m; - uint64_t size; - - size = strtoll(str, &m, 0); - if (m && *m) { - switch (*m) { - case 't': - case 'T': - size *= 1024; - /*FALLTHRU*/ - case 'g': - case 'G': - size *= 1024; - /*FALLTHRU*/ - case 'm': - case 'M': - size *= 1024; - /*FALLTHRU*/ - case 'k': - case 'K': - size *= 1024; - break; - - default: - return (False); - } - } - - *sp = size; - return (True); -} - -/* - * []---- - * | util_title -- print out start/end title in consistent manner - * []---- - */ -void -util_title(target_queue_t *q, int type, int num, char *title) -{ - char *type_str; - int len, pad; - - len = strlen(title); - pad = len & 1; - - switch (type) { - case Q_CONN_LOGIN: - case Q_CONN_NONIO: - type_str = "CON"; - break; - - case Q_SESS_LOGIN: - case Q_SESS_NONIO: - type_str = "SES"; - break; - - case Q_STE_NONIO: - type_str = "SAM"; - break; - - default: - type_str = "UGH"; - break; - } - - queue_prt(q, type, "%s%x ---- %*s%s%*s ----\n", type_str, num, - ((60 - len) / 2), "", title, ((60 - len) / 2) + pad, ""); -} - -/* - * []---- - * | task_to_str -- convert task management event to string (DEBUG USE) - * []---- - */ -char * -task_to_str(int func) -{ - switch (func) { - case ISCSI_TM_FUNC_ABORT_TASK: return ("Abort"); - case ISCSI_TM_FUNC_ABORT_TASK_SET: return ("Abort Set"); - case ISCSI_TM_FUNC_CLEAR_ACA: return ("Clear ACA"); - case ISCSI_TM_FUNC_CLEAR_TASK_SET: return ("Clear Task"); - case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: return ("LUN Reset"); - case ISCSI_TM_FUNC_TARGET_WARM_RESET: return ("Target Warm Reset"); - case ISCSI_TM_FUNC_TARGET_COLD_RESET: return ("Target Cold Reset"); - case ISCSI_TM_FUNC_TASK_REASSIGN: return ("Task Reassign"); - default: return ("Unknown"); - } -} - -/* - * []---- - * | xml_rtn_msg -- create a common format for XML replies to management UI - * []---- - */ -void -xml_rtn_msg(char **buf, err_code_t code) -{ - char lbuf[16]; - - tgt_buf_add_tag_and_attr(buf, XML_ELEMENT_ERROR, "version='1.0'"); - (void) snprintf(lbuf, sizeof (lbuf), "%d", code); - tgt_buf_add(buf, XML_ELEMENT_CODE, lbuf); - tgt_buf_add(buf, XML_ELEMENT_MESSAGE, errcode_to_str(code)); - tgt_buf_add_tag(buf, XML_ELEMENT_ERROR, Tag_End); -} - -/* - * []---- - * | thick_provo_start -- start an initialization thread for targ/lun - * []---- - */ -void * -thick_provo_start(void *v) -{ - thick_provo_t *tp = (thick_provo_t *)v; - msg_t *m; - Boolean_t rval; - char *err = NULL; - - /* - * Add this threads information to the main queue. This is - * used in case the administrator decides to remove the LU - * before the initialization is complete. - */ - (void) pthread_mutex_lock(&thick_mutex); - if (thick_head == NULL) { - thick_head = tp; - } else { - thick_tail->next = tp; - tp->prev = thick_tail; - } - thick_tail = tp; - (void) pthread_mutex_unlock(&thick_mutex); - - /* - * This let's the parent thread know this thread is running. - */ - queue_message_set(tp->q, 0, msg_mgmt_rply, 0); - - /* ---- Start the initialization of the LU ---- */ - rval = t10_thick_provision(tp->targ_name, tp->lun, tp->q); - - /* ---- Remove from the linked list ---- */ - (void) pthread_mutex_lock(&thick_mutex); - if (tp->prev == NULL) { - assert(tp == thick_head); - thick_head = tp->next; - if (tp->next == NULL) { - assert(tp == thick_tail); - thick_tail = NULL; - } else - tp->next->prev = NULL; - } else { - tp->prev->next = tp->next; - if (tp->next != NULL) - tp->next->prev = tp->prev; - else - thick_tail = tp->prev; - } - (void) pthread_mutex_unlock(&thick_mutex); - - /* - * There's a race condition where t10_thick_provision() could - * finish and before the thick_mutex lock is grabbed again - * that another thread running the thick_provo_stop() could - * find a match and send a shutdown message. If that happened - * that thread would wait forever in queue_message_get(). So, - * After this target/lun pair has been removed check the message - * queue one last time to see if there's a message available. - * If so, send an ack. - */ - m = queue_message_try_get(tp->q); - if (m != NULL) { - assert(m->msg_type == msg_shutdown); - queue_message_set((target_queue_t *)m->msg_data, 0, - msg_shutdown_rsp, 0); - } - - if (rval == True) - iscsi_inventory_change(tp->targ_name); - else { - queue_prt(mgmtq, Q_GEN_ERRS, "Failed to initialize %s/%d\n", - tp->targ_name, tp->lun); - syslog(LOG_ERR, "Failed to initialize %s, LU%d", tp->targ_name, - tp->lun); - remove_target_common(tp->targ_name, tp->lun, &err); - if (err != NULL) { - - /* - * There's not much we can do here. The most likely - * cause of not being able to remove the target is - * that it's LU 0 and there is currently another - * LU allocated. - */ - queue_prt(mgmtq, Q_GEN_ERRS, - "Failed to remove target\n"); - syslog(LOG_ERR, "Failed to remove target/lun after " - "initialization failure"); - } - } - - free(tp->targ_name); - queue_free(tp->q, NULL); - free(tp); - - queue_message_set(mgmtq, 0, msg_pthread_join, - (void *)(uintptr_t)pthread_self()); - return (NULL); -} - -/* - * []---- - * | thick_provo_stop -- stop initialization thread for given targ/lun - * []---- - */ -void -thick_provo_stop(char *targ, int lun) -{ - thick_provo_t *tp; - target_queue_t *q = queue_alloc(); - - (void) pthread_mutex_lock(&thick_mutex); - tp = thick_head; - while (tp) { - if ((strcmp(tp->targ_name, targ) == 0) && (tp->lun == lun)) { - queue_message_set(tp->q, 0, msg_shutdown, (void *)q); - /* - * Drop the global mutex because it's entirely - * possible for a thick_provo_start thread to be - * in the early stages in which it will can call - * thick_provo_chk() from the T10 SAM code. - */ - (void) pthread_mutex_unlock(&thick_mutex); - - queue_message_free(queue_message_get(q)); - - /* - * Pick the lock back up since it'll make the - * finish stage easier to deal with. - */ - (void) pthread_mutex_lock(&thick_mutex); - break; - } - tp = tp->next; - } - (void) pthread_mutex_unlock(&thick_mutex); - queue_free(q, NULL); -} - -/* - * []---- - * | thick_provo_chk_thr -- see if there's an initialization thread running - * []---- - */ -Boolean_t -thick_provo_chk_thr(char *targ, int lun) -{ - thick_provo_t *tp; - Boolean_t rval = False; - - (void) pthread_mutex_lock(&thick_mutex); - tp = thick_head; - while (tp) { - if ((strcmp(tp->targ_name, targ) == 0) && (tp->lun == lun)) { - rval = True; - break; - } - tp = tp->next; - } - (void) pthread_mutex_unlock(&thick_mutex); - - return (rval); -} - -/* - * []---- - * | remove_target_common -- remove targ/lun from system. - * | - * | This is a common function that's used both by the normal remove - * | target code and when a write failure occurs during initialization. - * | It will handle being given either the local target name or the full - * | IQN name of the target. - * []---- - */ -void -remove_target_common(char *name, int lun_num, char **msg) -{ - tgt_node_t *targ = NULL; - tgt_node_t *list, *lun, *c; - char path[MAXPATHLEN]; - char *tname = NULL; - char *iname = NULL; - int chk; - - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - /* ---- Look for a match on the friendly name ---- */ - if (strcmp(targ->x_value, name) == 0) { - tname = name; - break; - } - - /* ---- Check to see if they gave the IQN name instead ---- */ - if ((tgt_find_value_str(targ, XML_ELEMENT_INAME, &iname) == - True) && (strcmp(iname, name) == 0)) - break; - else { - free(iname); - iname = NULL; - } - } - - /* ---- Check to see if it's already been removed ---- */ - if (targ == NULL) { - return; - } - - /* - * We need both the friendly and IQN names so figure out which wasn't - * given and find it's value. - */ - if (tname == NULL) - tname = targ->x_value; - if (iname == NULL) { - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &iname) == - False) { - xml_rtn_msg(msg, ERR_INTERNAL_ERROR); - return; - } - } - - if ((list = tgt_node_next(targ, XML_ELEMENT_LUNLIST, NULL)) == NULL) - goto error; - - if (lun_num == 0) { - - /* - * LUN must be the last one removed, so check to - * see if others are still present. - */ - lun = NULL; - while ((lun = tgt_node_next(list, XML_ELEMENT_LUN, lun)) != - NULL) { - if (tgt_find_value_int(lun, XML_ELEMENT_LUN, &chk) == - False) - goto error; - - if (chk != lun_num) { - xml_rtn_msg(msg, ERR_LUN_ZERO_NOT_LAST); - goto error; - } - } - } else { - - /* - * Make sure the LU exists that's being removed - */ - lun = NULL; - while ((lun = tgt_node_next(list, XML_ELEMENT_LUN, lun)) != - NULL) { - if (tgt_find_value_int(lun, XML_ELEMENT_LUN, &chk) == - False) - goto error; - - if (chk == lun_num) { - lun = tgt_node_alloc(XML_ELEMENT_LUN, Int, - &lun_num); - (void) tgt_node_remove(list, lun, MatchBoth); - tgt_node_free(lun); - break; - } - } - if (lun == NULL) { - xml_rtn_msg(msg, ERR_LUN_NOT_FOUND); - goto error; - } - } - - /* ---- Say goodbye to that data ---- */ - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, - iname, LUNBASE, lun_num); - (void) unlink(path); - (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, - iname, PARAMBASE, lun_num); - (void) unlink(path); - - (void) mgmt_param_remove(tname, lun_num); - - /* - * If the was LUN 0 then do to the previous check - * we know that no other files exist in the target - * directory so the target information can be removed - * along with the directory. - */ - if (lun_num == 0) { - (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, - iname); - (void) rmdir(path); - - /* - * Don't forget to remove the symlink to - * the target directory. - */ - (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, - tname); - (void) unlink(path); - - /* - * 'tname' is just a reference to the memory within - * the targets_config structure. So once the tgt_node_remove() - * is called 'tname' is no longer valid. - */ - c = tgt_node_alloc(XML_ELEMENT_TARG, String, tname); - (void) tgt_node_remove(targets_config, c, MatchBoth); - tgt_node_free(c); - } - - /* - * Not much we can do here if we fail to updated the config. - */ - if (mgmt_config_save2scf() == False) - syslog(LOG_ERR, "Failed to update target configuration!"); - -error: - if (iname != NULL) - free(iname); -} - -/* - * []---- - * | validate_xml - * | - * | This function checks if there is predefined entities &<>'" in xml request - * []---- - */ -Boolean_t -validate_xml(char *req) -{ - in_mark_t in_mark = in_none; - - if (req == NULL) - return (False); - for (; *req != '\0'; req++) { - if (in_mark == in_none) { - if (*req == '<') { - in_mark = in_lt; - continue; - } else if (*req == '&') { - in_mark = in_amp; - continue; - } else if (strchr("\"\'>", *req) != NULL) { - return (False); - } - } else if (in_mark == in_lt) { - if (*req == '>') { - in_mark = in_none; - continue; - } else if (*req == '<') { - return (False); - } - } else { - if (*req == ';') { - in_mark = in_none; - continue; - } else if (*req == '&' || *req == '<') { - return (False); - } - } - } - - if (in_mark == in_none) - return (True); - else - return (False); -} - -/* - * []---- - * | get_local_name - * | - * | This function fetches local name from a iscsi-name - * | Caller is responsible to free the string. - * []---- - */ -char * -get_local_name(char *iname) -{ - tgt_node_t *targ = NULL; - char *str; - char *ret = NULL; - - while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, - targ)) != NULL) { - if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &str) == True) { - if (strcmp(str, iname) == 0) - ret = strdup(targ->x_value); - free(str); - if (ret != NULL) - break; - } - } - return (ret); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/util_err.c b/usr/src/cmd/iscsi/iscsitgtd/util_err.c deleted file mode 100644 index 8860436ea9..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/util_err.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <libintl.h> -#include "errcode.h" - -char * -errcode_to_str(err_code_t err_code) -{ - switch (err_code) { - case ERR_SUCCESS: - return ((char *)gettext("Operation completed successfully")); - case ERR_NULL_XML_MESSAGE: - return ((char *)gettext("Null XML message")); - case ERR_SYNTAX_EMPTY: - return ((char *)gettext("Syntax error: " - "Empty XML message or syntax error")); - case ERR_SYNTAX_MISSING_ALL: - return ((char *)gettext("Syntax error: Missing --all")); - case ERR_SYNTAX_MISSING_BACKING_STORE: - return ((char *)gettext("Syntax error: Missing backing-store")); - case ERR_SYNTAX_MISSING_INAME: - return ((char *)gettext("Syntax error: Missing iscsi name")); - case ERR_SYNTAX_MISSING_IPADDR: - return ((char *)gettext("Syntax error: Missing IP address")); - case ERR_SYNTAX_MISSING_NAME: - return ((char *)gettext("Syntax error: Missing name")); - case ERR_SYNTAX_MISSING_OBJECT: - return ((char *)gettext("Syntax error: Missing object")); - case ERR_SYNTAX_MISSING_OPERAND: - return ((char *)gettext("Syntax error: Missing operand")); - case ERR_SYNTAX_MISSING_SIZE: - return ((char *)gettext("Syntax error: Missing size")); - case ERR_SYNTAX_MISSING_TYPE: - return ((char *)gettext("Syntax error: Missing type")); - case ERR_SYNTAX_EMPTY_ACL: - return ((char *)gettext("Syntax error: empty ACL")); - case ERR_SYNTAX_EMPTY_ALIAS: - return ((char *)gettext("Syntax error: empty alias")); - case ERR_SYNTAX_EMPTY_CHAPNAME: - return ((char *)gettext("Empty chap-name")); - case ERR_SYNTAX_EMPTY_CHAPSECRET: - return ((char *)gettext("Empty 'chap-secret' element")); - case ERR_SYNTAX_EMPTY_IPADDR: - return ((char *)gettext("Syntax error: empty IP address")); - case ERR_SYNTAX_EMPTY_MAXRECV: - return ((char *)gettext("Syntax error: empty maxrecv")); - case ERR_SYNTAX_EMPTY_TPGT: - return ((char *)gettext("Syntax error: empty TPGT")); - case ERR_SYNTAX_INVALID_NAME: - return ((char *)gettext("Syntax error: name may contain only " - "a..z, A..Z, 0-9, dot(.), dash(-), colon(:) characters")); - case ERR_INVALID_COMMAND: - return ((char *)gettext("Invalid command")); - case ERR_INVALID_OBJECT: - return ((char *)gettext("Invalid object")); - case ERR_INVALID_BASEDIR: - return ((char *)gettext("Invalid base directory")); - case ERR_INVALID_IP: - return ((char *)gettext("Invalid IP address")); - case ERR_INVALID_TPGT: - return ((char *)gettext("Invalid TPGT")); - case ERR_INVALID_MAXRECV: - return ((char *)gettext("Invalid MaxRecvDataSegmentLength")); - case ERR_INVALID_RADSRV: - return ((char *)gettext("Invalid RADIUS server name")); - case ERR_INVALID_SIZE: - return ((char *)gettext("Invalid size parameter")); - case ERR_INIT_EXISTS: - return ((char *)gettext("Initiator already exists")); - case ERR_LUN_EXISTS: - return ((char *)gettext("LUN already exists")); - case ERR_LUN_INVALID_RANGE: - return ((char *)gettext("LUN must be between 0 and 16383")); - case ERR_TPGT_EXISTS: - return ((char *)gettext("TPGT already exists")); - case ERR_ACL_NOT_FOUND: - return ((char *)gettext("ACL list not found")); - case ERR_INIT_NOT_FOUND: - return ((char *)gettext("Initiator not found")); - case ERR_TARG_NOT_FOUND: - return ((char *)gettext("Target not found")); - case ERR_LUN_NOT_FOUND: - return ((char *)gettext("LUN not found")); - case ERR_TPGT_NOT_FOUND: - return ((char *)gettext("TPGT not found")); - case ERR_ACCESS_RAW_DEVICE_FAILED: - return ((char *)gettext("Failed to " - "access a direct access device")); - case ERR_CREATE_METADATA_FAILED: - return ((char *)gettext("Failed to " - "create meta data for tape device")); - case ERR_CREATE_SYMLINK_FAILED: - return ((char *)gettext("Failed to " - "create a symbolic link to the backing store")); - case ERR_CREATE_NAME_TOO_LONG: - return ((char *)gettext("Name must be less than 166 " - "characters")); - case ERR_NAME_TOO_LONG: - return ((char *)gettext("Name too long, must be less than 223 " - "characters")); - case ERR_DISK_BACKING_SIZE_OR_FILE: - return ((char *)gettext("Size must be 0 if backing store " - "exists")); - case ERR_DISK_BACKING_MUST_BE_REGULAR_FILE: - return ((char *)gettext("For type " - "'disk' backing must be a regular file")); - case ERR_DISK_BACKING_NOT_VALID_RAW: - return ((char *)gettext("Backing store is not a valid raw " - "device")); - case ERR_STAT_BACKING_FAILED: - return ((char *)gettext("Failed to " - "stat(2) backing for 'disk'")); - case ERR_RAW_PART_NOT_CAP: - return ((char *)gettext("Partition size does not match capacity" - " of device. Use p0 or ctd name")); - case ERR_CREATE_TARGET_DIR_FAILED: - return ((char *)gettext("Failed to " - "create target directory")); - case ERR_ENCODE_GUID_FAILED: - return ((char *)gettext("Failed to encode GUID value")); - case ERR_INIT_XML_READER_FAILED: - return ((char *)gettext("Failed to initialize XML reader")); - case ERR_INVALID_XML_REQUEST: - return ((char *)gettext("Invalid characters in XML request")); - case ERR_OPEN_PARAM_FILE_FAILED: - return ((char *)gettext("Failed to open parameter file")); - case ERR_UPDATE_MAINCFG_FAILED: - return ((char *)gettext("Failed to " - "update main configuration file")); - case ERR_UPDATE_TARGCFG_FAILED: - return ((char *)gettext("Failed to " - "update target configuration file")); - case ERR_VALID_TARG_EXIST: - return ((char *)gettext("Valid targets " - "exist under current base directory")); - case ERR_TARGCFG_MISSING_INAME: - return ((char *)gettext("Missing " - "iscsi name in target configuration")); - case ERR_NO_MATCH: - return ((char *)gettext("No match")); - case ERR_NO_MEM: - return ((char *)gettext("Internal error: Out of memory")); - case ERR_LUN_ZERO_NOT_LAST: - return ((char *)gettext("LUN 0 must be the last one deleted")); - case ERR_LUN_ZERO_NOT_FIRST: - return ((char *)gettext("LUN 0 must exist before creating " - "other LUNs")); - case ERR_SIZE_MOD_BLOCK: - return ((char *)gettext("Size must be multiple of 512")); - case ERR_CANT_SHRINK_LU: - return ((char *)gettext("Shrinking of LU is not supported")); - case ERR_RESIZE_WRONG_TYPE: - return ((char *)gettext("Backing store must be regular file")); - case ERR_RESIZE_WRONG_DTYPE: - return ((char *)gettext("Cannot resize 'raw' targets")); - case ERR_LUN_NOT_GROWN: - return ((char *)gettext("Failed to grow LU")); - case ERR_FILE_TOO_BIG: - return ((char *)gettext("Requested size is too large for " - "system")); - case ERR_FAILED_TO_CREATE_LU: - return ((char *)gettext("Failed to create backing store")); - case ERR_INTERNAL_ERROR: - return ((char *)gettext("Internal error")); - case ERR_TAPE_NOT_SUPPORTED_IN_32BIT: - return ((char *)gettext("Tape emulation not supported in " - "32-bit mode")); - case ERR_BAD_CREDS: - return ((char *)gettext("No credentials available from door")); - case ERR_NO_PERMISSION: - return ((char *)gettext("Permission denied")); - case ERR_INVALID_ISNS_SRV: - return ((char *)gettext("Invalid ISNS Server name")); - case ERR_ISNS_ERROR: - return ((char *)gettext("ISNS error")); - case ERR_TPGT_NO_IPADDR: - return ((char *)gettext("TPGT has no ip-addr")); - case ERR_TPGT_IN_USE: - return ((char *)gettext("Specified TPGT is in-use")); - case ERR_ZFS_ISCSISHARE_OFF: - return ((char *)gettext("ZFS shareiscsi property is off")); - default: - return ((char *)gettext("Internal error: unknown message")); - } -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/util_ifname.c b/usr/src/cmd/iscsi/iscsitgtd/util_ifname.c deleted file mode 100644 index 2ee9e089c7..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/util_ifname.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * 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. - */ - -#include <sys/types.h> -#include <libdlpi.h> -#include <ctype.h> -#include <sys/sysmacros.h> -#include <net/if_types.h> -#include <net/if.h> -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <net/if_dl.h> -#include <sys/sockio.h> -#include <sys/socket.h> -#include <unistd.h> -#include <strings.h> -#include <stropts.h> -#include <fcntl.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <iscsitgt_impl.h> -#include "target.h" -#include "queue.h" -#include "utility.h" - -#define LOCAL_LOOPBACK "lo0" - -/* - * This entire file is all about getting these two variables. To create a - * unique iSCSI IQN string we need information that is unique. What Sun has - * decided is to use a MAC address along with a timestamp. No other machine - * at this given time will have the same MAC address and as time moves along - * well, time will change. - */ -uchar_t mac_addr[DLPI_PHYSADDR_MAX]; -size_t mac_len; - -static struct lifreq *if_setup(int *n); -static void dump_addr_to_ascii(struct sockaddr *addr, char *buf, - size_t len); -static Boolean_t grab_address(char *ifname, uchar_t *addrp, size_t *addrlenp); - -/* - * []---- - * | if_find_mac -- Finds a valid MAC address to use for GUID & IQN creation - * | - * | To create both the GUID and the IQN string we need to make them unique - * | and do so without requiring the user to have to register each target - * | creation with Sun. Each machine that's using iSCSI will have a network - * | interface from which we can obtain the MAC address. That guarantees - * | uniqueness within the network, but doesn't guarantee uniqueness with - * | the machine. So when creating the GUID/IQN we also use a timestamp. - * []---- - */ -Boolean_t -if_find_mac(target_queue_t *mgmt) -{ - struct lifreq *lifrp, *first; - int n; - char *str; - - mac_len = DLPI_PHYSADDR_MAX; - - first = if_setup(&n); - for (lifrp = first; n > 0; n--, lifrp++) { - if (grab_address(lifrp->lifr_name, mac_addr, - &mac_len) == True) { - str = _link_ntoa(mac_addr, NULL, mac_len, IFT_OTHER); - if ((str != NULL) && (mgmt != NULL)) { - queue_prt(mgmt, Q_GEN_DETAILS, - "MAIN %s: %s \n", lifrp->lifr_name, str); - free(str); - } - /* ---- grab the first valid MAC address ---- */ - break; - } - } - if (first) - free(first); - return (mac_len == 0 ? False : True); -} - -/* - * []---- - * | if_target_address -- setup IP address for SendTargets - * | - * | This routine is called when the iSCSI target is returning SendTargets - * | data during a discovery phase. The target name is returned along - * | with all of the IP address that can access that target. There's one - * | catch, the first address in the list will be the address used by - * | the initiator if it doesn't support multiple connections per session. - * | Therefore, whatever connection the initiator used is the first one - * | that should be in our list. The ramificiations of not doing this are - * | possible performance issues. Take for example a setup where both the - * | initiator and target have 10GbE and 1GbE interfaces. The initiator wants - * | to use the 10GbE interface because of it's speed. If the target returns - * | a list of addresses with the 1GbE listed first, that's the one which - * | the initiator would use. Not good. - * []---- - */ -void -if_target_address(char **text, int *text_length, struct sockaddr *sp) -{ - struct lifreq *lp, *first; - int n, i, s; - struct sockaddr_in *sin4_cur, *sin4_pos; - struct sockaddr_in6 *sin6_cur, *sin6_pos; - char ta[80], ip_buf[INET6_ADDRSTRLEN]; - int fromlen; - - if (sp->sa_family == AF_INET) { - fromlen = sizeof (struct sockaddr_in); - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return; - - /*LINTED*/ - sin4_cur = (struct sockaddr_in *)sp; - - /* - * Ugh. Would you believe that even though this array - * is defined as zero, we get back non-zero data from - * getsockname(). - */ - bzero(&sin4_cur->sin_zero[0], sizeof (sin4_cur->sin_zero)); - - } else if (sp->sa_family == AF_INET6) { - fromlen = sizeof (struct sockaddr_in6); - - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) - return; - - /*LINTED*/ - sin6_cur = (struct sockaddr_in6 *)sp; - } else - return; - - first = if_setup(&n); - for (lp = first, i = 0; i < n; i++, lp++) { - - if (sp->sa_family != lp->lifr_addr.ss_family) - continue; - - /* - * Change the possible incoming addresses port number, - * which would be zero, to that of the current incoming - * port number. Otherwise the comparison will not match. - */ - if (sp->sa_family == AF_INET) { - sin4_pos = (struct sockaddr_in *)&lp->lifr_addr; - sin4_pos->sin_port = sin4_cur->sin_port; - } else if (sp->sa_family == AF_INET6) { - sin6_pos = (struct sockaddr_in6 *)&lp->lifr_addr; - sin6_pos->sin6_port = sin6_cur->sin6_port; - } else - goto clean_up; - } - - for (lp = first, i = 0; i < n; i++, lp++) { - - if (bcmp(sp, &lp->lifr_addr, fromlen) == 0) { - dump_addr_to_ascii((struct sockaddr *)&lp->lifr_addr, - ip_buf, sizeof (ip_buf)); - - if (sp->sa_family == AF_INET) { - (void) snprintf(ta, sizeof (ta), "%s,1", - ip_buf); - } else if (sp->sa_family == AF_INET6) { - (void) snprintf(ta, sizeof (ta), "[%s],1", - ip_buf); - } else - goto clean_up; - - (void) add_text(text, text_length, "TargetAddress", ta); - - /* - * There is possiblity that both IPv4 & IPv6 enabled on - * certain interface, then we will see that interface - * twice identically in the list. - * Of course we need only one of them, not both. - */ - break; - } - } - - for (lp = first, i = 0; i < n; i++, lp++) { - /* - * We allow for the loopback address to match the discovery - * address above since it's entirely possible to create - * a target on the same machine that you're running the - * initiator. Now, when we provide the list of other - * possible interfaces to use we don't want to include - * the loopback because that's obviously not a valid I/F - * for a remote node. - */ - if (strcmp(lp->lifr_name, LOCAL_LOOPBACK) == 0) - continue; - - if (bcmp(sp, &lp->lifr_addr, fromlen) != 0) { - struct sockaddr *sp2; - sp2 = (struct sockaddr *)&lp->lifr_addr; - dump_addr_to_ascii(sp2, ip_buf, sizeof (ip_buf)); - - if (sp2->sa_family == AF_INET) { - (void) snprintf(ta, sizeof (ta), "%s,1", - ip_buf); - } else if (sp2->sa_family == AF_INET6) { - (void) snprintf(ta, sizeof (ta), "[%s],1", - ip_buf); - } else - goto clean_up; - (void) add_text(text, text_length, "TargetAddress", ta); - } - } - -clean_up: - (void) close(s); - if (first) - free(first); -} - -/* - * []---- - * | dump_addr_to_ascii -- Use appropriate translation routine - * []---- - */ -static void -dump_addr_to_ascii(struct sockaddr *addr, char *buf, size_t len) -{ - struct sockaddr_in *sin4; - struct sockaddr_in6 *sin6; - - if (addr->sa_family == AF_INET) { - /*LINTED*/ - sin4 = (struct sockaddr_in *)addr; - (void) inet_ntop(AF_INET, &sin4->sin_addr, buf, len); - } else if (addr->sa_family == AF_INET6) { - /*LINTED*/ - sin6 = (struct sockaddr_in6 *)addr; - (void) inet_ntop(AF_INET6, &sin6->sin6_addr, buf, len); - } -} - -/* - * []---- - * | if_setup -- Load up the interface names - * | - * | If this routine returns NULL, argument 'n' is also guaranteed to - * | be set to 0. - * []---- - */ -static struct lifreq * -if_setup(int *n) -{ - struct lifnum lifn; - struct lifconf lifc; - int numifs; - unsigned bufsize; - char *buf; - int s; - - *n = 0; - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { - /* - * If we failed to open an IPv6 socket - * try IPv4 socket instead - */ - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return (NULL); - } - - lifn.lifn_family = AF_UNSPEC; - lifn.lifn_flags = LIFC_ALLZONES | LIFC_EXTERNAL_SOURCE; - if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) - return (NULL); - - numifs = lifn.lifn_count; - - bufsize = numifs * sizeof (struct lifreq); - if ((buf = malloc(bufsize)) == NULL) { - /* - * This call is made so early on that if we're out of memory - * here, just say goodbye. - */ - return (NULL); - } - - lifc.lifc_family = AF_UNSPEC; - lifc.lifc_flags = LIFC_ALLZONES | LIFC_EXTERNAL_SOURCE; - lifc.lifc_len = bufsize; - lifc.lifc_buf = buf; - - if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { - free(buf); - return (NULL); - } - - (void) close(s); - *n = lifc.lifc_len / sizeof (struct lifreq); - return (lifc.lifc_req); -} - -static Boolean_t -grab_address(char *ifname, uchar_t *addrp, size_t *addrlenp) -{ - int retval; - dlpi_handle_t dh; - - if (dlpi_open(ifname, &dh, 0) != DLPI_SUCCESS) - return (False); - - retval = dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, addrp, addrlenp); - - dlpi_close(dh); - - return (retval == DLPI_SUCCESS); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/util_port.c b/usr/src/cmd/iscsi/iscsitgtd/util_port.c deleted file mode 100644 index 357e07156d..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/util_port.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * 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. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <string.h> -#include <strings.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <assert.h> -#include <syslog.h> -#include <unistd.h> - -#include "queue.h" -#include "port.h" -#include "iscsi_conn.h" -#include "utility.h" - -pthread_mutex_t port_mutex; -int port_conn_num; -iscsi_conn_t *conn_head = NULL; -iscsi_conn_t *conn_tail = NULL; - -void -port_init(void) -{ - (void) pthread_mutex_init(&port_mutex, NULL); - port_conn_num = 0; -} - -void -canonicalize_sockaddr(struct sockaddr_storage *st) -{ - struct in6_addr *addr6 = &((struct sockaddr_in6 *)st)->sin6_addr; - - /* - * If target address is IPv4 mapped IPv6 address convert it to IPv4 - * address. - */ - if (st->ss_family == AF_INET6 && - (IN6_IS_ADDR_V4MAPPED(addr6) || IN6_IS_ADDR_V4COMPAT(addr6))) { - struct in_addr *addr = &((struct sockaddr_in *)st)->sin_addr; - IN6_V4MAPPED_TO_INADDR(addr6, addr); - st->ss_family = AF_INET; - } -} - - -void * -port_watcher(void *v) -{ - int s; - int fd; - int on = 1; - char debug[80]; - struct sockaddr_in sin_ip; - struct sockaddr_in6 sin6_ip; - struct sockaddr_storage st; - socklen_t socklen; - iscsi_conn_t *conn; - port_args_t *p = (port_args_t *)v; - target_queue_t *q = p->port_mgmtq; - int l; - const int just_say_no = 1; - pthread_t junk; - - /* - * Try creating an IPv6 socket first - * If failed, try creating an IPv4 socket - */ - if ((s = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { - - queue_str(q, Q_GEN_ERRS, msg_log, "Opening IPv4 socket"); - if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) { - queue_str(q, Q_GEN_ERRS, msg_log, - "Can't open socket"); - return (NULL); - } else { - bzero(&sin_ip, sizeof (sin_ip)); - sin_ip.sin_family = AF_INET; - sin_ip.sin_port = htons(p->port_num); - sin_ip.sin_addr.s_addr = INADDR_ANY; - - (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof (on)); - - if ((bind(s, (struct sockaddr *)&sin_ip, - sizeof (sin_ip))) < 0) { - (void) snprintf(debug, sizeof (debug), - "bind on port %d failed, errno %d", - p->port_num, errno); - queue_str(q, Q_GEN_ERRS, msg_status, debug); - return (NULL); - } - } - - } else { - - queue_str(q, Q_GEN_DETAILS, msg_log, "Got IPv6 socket"); - bzero(&sin6_ip, sizeof (sin6_ip)); - sin6_ip.sin6_family = AF_INET6; - sin6_ip.sin6_port = htons(p->port_num); - sin6_ip.sin6_addr = in6addr_any; - - (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, - sizeof (on)); - - if ((bind(s, (struct sockaddr *)&sin6_ip, sizeof (sin6_ip))) - < 0) { - (void) snprintf(debug, sizeof (debug), - "bind on port %d failed, errno %d", - p->port_num, errno); - queue_str(q, Q_GEN_ERRS, msg_status, debug); - return (NULL); - } - } - - if (listen(s, 128) < 0) { - queue_str(q, Q_GEN_ERRS, msg_status, "listen failed"); - return (NULL); - } - - /*CONSTANTCONDITION*/ - while (1) { - - socklen = sizeof (st); - if ((fd = accept(s, (struct sockaddr *)&st, - &socklen)) < 0) { - if (errno != EINTR) - queue_prt(q, Q_GEN_ERRS, - "accept failed, %s", strerror(errno)); - (void) sleep(1); - continue; - } - - l = 128 * 1024; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&l, - sizeof (l)) < 0) - queue_str(q, Q_GEN_ERRS, msg_status, - "setsockopt failed"); - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&l, - sizeof (l)) < 0) - queue_str(q, Q_GEN_ERRS, msg_status, - "setsockopt failed"); - l = 1; - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&l, - sizeof (l)) < 0) - queue_str(q, Q_GEN_ERRS, msg_status, - "setsockopt keepalive failed"); - - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - (char *)&just_say_no, sizeof (just_say_no)) != 0) - queue_str(q, Q_GEN_ERRS, msg_status, - "setsockopt NODELAY failed"); - - if ((conn = calloc(1, sizeof (iscsi_conn_t))) == NULL) { - /* - * If we fail to get memory this is all rather - * pointless, since it's unlikely that queue_str - * could malloc memory to send a message. - */ - queue_str(q, Q_GEN_ERRS, msg_status, - "connection malloc failed"); - return (NULL); - } - - /* - * Save initiator address for future use. - */ - canonicalize_sockaddr(&st); - conn->c_initiator_sockaddr = st; - - /* - * Save target address for future use. - */ - socklen = sizeof (st); - if (getsockname(fd, (struct sockaddr *)&st, &socklen) == 0) - canonicalize_sockaddr(&st); - else - st.ss_family = AF_UNSPEC; - conn->c_target_sockaddr = st; - - conn->c_fd = fd; - conn->c_mgmtq = q; - conn->c_up_at = time(NULL); - conn->c_state = S1_FREE; - (void) pthread_mutex_init(&conn->c_mutex, NULL); - (void) pthread_mutex_init(&conn->c_state_mutex, NULL); - (void) pthread_mutex_lock(&port_mutex); - conn->c_num = port_conn_num++; - if (conn_head == NULL) { - conn_head = conn; - assert(conn_tail == NULL); - conn_tail = conn; - } else { - conn_tail->c_next = conn; - conn->c_prev = conn_tail; - conn_tail = conn; - } - (void) pthread_mutex_unlock(&port_mutex); - - (void) pthread_create(&junk, NULL, conn_process, conn); - } - return (NULL); -} - -void -port_conn_remove(iscsi_conn_t *c) -{ - iscsi_conn_t *n; - - (void) pthread_mutex_lock(&port_mutex); - if (conn_head == c) { - conn_head = c->c_next; - if (conn_head == NULL) - conn_tail = NULL; - else - conn_head->c_prev = NULL; - } else { - n = c->c_prev; - n->c_next = c->c_next; - if (c->c_next != NULL) - c->c_next->c_prev = n; - else { - assert(conn_tail == c); - conn_tail = n; - } - } - - /* - * The connection queue is freed here so that it's protected by - * locks. The main thread of the deamon when processing incoming - * management requests will send them on the connection queues. - * The main thread will grab the port_mutex so that we know the - * queue is still valid. - */ - queue_free(c->c_dataq, conn_queue_data_remove); - (void) pthread_mutex_unlock(&port_mutex); -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/util_queue.c b/usr/src/cmd/iscsi/iscsitgtd/util_queue.c deleted file mode 100644 index a5258936ee..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/util_queue.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <unistd.h> -#include <assert.h> -#include <syslog.h> -#include <synch.h> -#include <time.h> -#include <umem.h> - -#include "queue.h" -#include "iscsi_conn.h" -#include "utility.h" -#include "target.h" -#include "t10.h" - -/* - * Constants - */ -static const timespec_t usec = {0, 1000}; - -FILE *qlog = NULL; -int qlog_lvl = 0; - -pthread_mutex_t q_mutex; -int queue_num; - -void -queue_init() -{ - (void) pthread_mutex_init(&q_mutex, NULL); - queue_log(True); -} - -target_queue_t * -queue_alloc() -{ - target_queue_t *q = - (target_queue_t *)calloc(1, sizeof (target_queue_t)); - - if (q == NULL) - return (NULL); - - (void) pthread_mutex_lock(&q_mutex); - q->q_num = queue_num++; - (void) pthread_mutex_unlock(&q_mutex); - - (void) sema_init(&q->q_sema, 0, USYNC_THREAD, NULL); - (void) pthread_mutex_init(&q->q_mutex, NULL); - - return (q); -} - -void -queue_log(Boolean_t on) -{ - (void) pthread_mutex_lock(&q_mutex); - if ((on == True) && (qlog == NULL) && (qlog_lvl != 0)) { - qlog = fopen(target_log, "ab"); - } else if ((on == False) && (qlog != NULL)) { - (void) fclose(qlog); - qlog = NULL; - } - (void) pthread_mutex_unlock(&q_mutex); -} - -/* - * []---- - * | queue_message_set -- add a given message to the queue. - * []---- - */ -void -queue_message_set(target_queue_t *q, uint32_t lvl, msg_type_t type, - void *data) -{ - msg_t *msg; - - if ((msg = umem_cache_alloc(queue_cache, 0)) == NULL) - return; - - bzero(msg, sizeof (*msg)); - msg->msg_pri_level = lvl; - msg->msg_type = type; - msg->msg_data = data; - - (void) pthread_mutex_lock(&q->q_mutex); - - if (q->q_head == NULL) { - q->q_head = msg; - assert(q->q_tail == NULL); - q->q_tail = msg; - } else if (lvl & Q_HIGH) { - msg->msg_next = q->q_head; - q->q_head->msg_prev = msg; - q->q_head = msg; - } else { - q->q_tail->msg_next = msg; - msg->msg_prev = q->q_tail; - q->q_tail = msg; - } - - (void) pthread_mutex_unlock(&q->q_mutex); - - (void) sema_post(&q->q_sema); -} - -/* - * []---- - * | queue_message_get -- retrieve the first message in the queue - * []---- - */ -msg_t * -queue_message_get(target_queue_t *q) -{ - msg_t *m; - - while (sema_wait(&q->q_sema) == -1) - (void) nanosleep(&usec, 0); - (void) pthread_mutex_lock(&q->q_mutex); - m = q->q_head; - if (m == NULL) { - assert(q->q_tail == NULL); - (void) pthread_mutex_unlock(&q->q_mutex); - return (NULL); - } - q->q_head = m->msg_next; - if (q->q_head == NULL) - q->q_tail = NULL; - (void) pthread_mutex_unlock(&q->q_mutex); - - return (m); -} - -/* - * []---- - * | queue_message_try_get -- see if there's a message available - * []---- - */ -msg_t * -queue_message_try_get(target_queue_t *q) -{ - msg_t *m; - - if (sema_trywait(&q->q_sema) != 0) - return (NULL); - (void) pthread_mutex_lock(&q->q_mutex); - m = q->q_head; - q->q_head = m->msg_next; - if (q->q_head == NULL) - q->q_tail = NULL; - (void) pthread_mutex_unlock(&q->q_mutex); - - return (m); -} - -/* - * []---- - * | queue_walker_free -- Run through a queue and free certain messages. - * | - * | Users of the queues should not walk the queue structure themselves - * | unless they also need to grab the lock. To prevent that level of - * | knowledge of the queue structures this method is provided to enable - * | other subsystems to walk the queue looking for messages which need - * | to be deleted. - * []---- - */ -void -queue_walker_free(target_queue_t *q, Boolean_t (*func)(msg_t *m, void *v), - void *v1) -{ - msg_t *m; /* current working message */ - msg_t *n; /* next message */ - - (void) pthread_mutex_lock(&q->q_mutex); - m = q->q_head; - while (m) { - if ((*func)(m, v1) == True) { - if (m == q->q_head) { - q->q_head = m->msg_next; - if (m->msg_next == NULL) - q->q_tail = NULL; - else - m->msg_next->msg_prev = NULL; - } else { - m->msg_prev->msg_next = m->msg_next; - if (m->msg_next == NULL) - q->q_tail = m->msg_prev; - else - m->msg_next->msg_prev = m->msg_prev; - } - n = m->msg_next; - queue_message_free(m); - m = n; - } else { - m = m->msg_next; - } - } - (void) pthread_mutex_unlock(&q->q_mutex); -} - -/* - * []---- - * | queue_reset -- Flush a queue of all command messages messages. - * []---- - */ -void -queue_reset(target_queue_t *q) -{ - msg_t *m; - msg_t *n; - - (void) pthread_mutex_lock(&q->q_mutex); - m = q->q_head; - while (m != NULL) { - - switch (m->msg_type) { - case msg_cmd_data_out: - case msg_cmd_send: - if (m == q->q_head) { - q->q_head = m->msg_next; - if (m->msg_next == NULL) - q->q_tail = NULL; - else - m->msg_next->msg_prev = NULL; - } else { - assert(m->msg_prev != NULL); - m->msg_prev->msg_next = m->msg_next; - if (m->msg_next == NULL) - q->q_tail = m->msg_prev; - else - m->msg_next->msg_prev = m->msg_prev; - } - n = m->msg_next; - queue_message_free(m); - m = n; - (void) sema_wait(&q->q_sema); - break; - - case msg_reset_lu: - case msg_shutdown: - case msg_lu_add: - case msg_lu_remove: - case msg_lu_online: - case msg_thick_provo: - /* - * Don't flush the control messages - */ - m = m->msg_next; - break; - - default: - queue_prt(mgmtq, Q_STE_ERRS, - "---- Unexpected msg type %d ----", m->msg_type); - m = m->msg_next; - break; - } - } - - (void) pthread_mutex_unlock(&q->q_mutex); -} - -void -queue_message_free(msg_t *m) -{ - umem_cache_free(queue_cache, m); -} - -/* - * []---- - * | queue_free -- free resources used by queue structure - * []---- - */ -void -queue_free(target_queue_t *q, void (*free_func)(msg_t *)) -{ - msg_t *m; - msg_t *n; - - (void) pthread_mutex_lock(&q->q_mutex); - m = q->q_head; - while (m != NULL) { - if (free_func != NULL) - (*free_func)(m); - n = m->msg_next; - queue_message_free(m); - m = n; - } - (void) pthread_mutex_unlock(&q->q_mutex); - - (void) pthread_mutex_destroy(&q->q_mutex); - (void) sema_destroy(&q->q_sema); - free(q); -} - -void -queue_prt(target_queue_t *q, int type, char *fmt, ...) -{ - va_list ap; - char buf[80]; - - va_start(ap, fmt); - /* LINTED variable format specifier */ - (void) vsnprintf(buf, sizeof (buf), fmt, ap); - queue_str(q, type, msg_log, buf); - va_end(ap); -} - -/* - * []---- - * | queue_str -- helper function which sends a string to the queue - * []---- - */ -void -queue_str(target_queue_t *q, uint32_t lvl, msg_type_t type, char *fmt) -{ - int len; - char *m; - hrtime_t h = gethrtime(); - hrtime_t delta; - static hrtime_t last_h = 0; - time_t tval = time((time_t *)0); - char debug[80]; - - (void) pthread_mutex_lock(&q_mutex); - if ((qlog) && (qlog_lvl & lvl)) { - (void) ctime_r(&tval, debug, sizeof (debug)); - (void) fprintf(qlog, "%s %s", debug, fmt); - (void) fflush(qlog); - } - (void) pthread_mutex_unlock(&q_mutex); - - if ((dbg_timestamps == True) && (lvl != 0) && ((lvl & Q_HIGH) == 0)) { - len = strlen(fmt) + 12; - m = malloc(len); - delta = h - last_h; - last_h = h; - (void) snprintf(m, len, "%9.3f %s", - (double)delta / (double)1000000.0, fmt); - queue_message_set(q, lvl, type, (void *)m); - } else { - len = strlen(fmt) + 1; - m = malloc(len); - (void) strncpy(m, fmt, len); - queue_message_set(q, lvl, type, (void *)m); - } -} - -/* - * []------------------------------------------------------------------[] - * | Specialized free routines for queue data. | - * | It is possible for a shutdown to start because the STE thread | - * | receives an error while reading from the socket. If at the same | - * | time the connection poll thread is processing a PDU it could place | - * | a msg_ste_datain package on the STE queue. When the STE hits the | - * | shutdown message first it will exit and we need to clean up | - * | anything on that queue which means freeing memory in the | - * | appropriate manner. This is just one example and there are several | - * | others. Another method to deal with this would be to have a closed | - * | flag such that any futher calls to queue_message_set would return | - * | an error. This would require any calls to queue_message_set() deal | - * | with this condition. The approach used here seems cleaner. | - * | The drawback to this approach is that if any new messages are | - * | added then the developer had better add it to these routines as | - * | appropriate. | - * []------------------------------------------------------------------[] - */ - -/* - * []---- - * | sess_queue_data_remove -- free any message data left on the sess queue - * | - * | XXX This should be recoded so that we're doing the cleanup within - * | the session code. Peal off any messages and deal with them there. - * []---- - */ -void -sess_queue_data_remove(msg_t *m) -{ - mgmt_request_t *mq; - char **buf; - - syslog(LOG_ERR, "sess_queue_data: type %d", m->msg_type); - switch (m->msg_type) { - default: - syslog(LOG_ERR, "Unknown session type data being free'd, %d", - m->msg_type); - free(m->msg_data); - break; - - case msg_shutdown: - case msg_shutdown_rsp: - case msg_ste_media_error: - syslog(LOG_ERR, "Impossible message left in session queue" - " of type %d", m->msg_type); - break; - - case msg_cmd_data_out: - break; - - case msg_initiator_name: - case msg_initiator_alias: - case msg_target_name: - free(((name_request_t *)m->msg_data)->nr_name); - break; - - case msg_mgmt_rqst: - mq = (mgmt_request_t *)m->msg_data; - (void) pthread_mutex_lock(&mq->m_resp_mutex); - tgt_buf_add(mq->m_u.m_resp, "queue_freed", NULL); - (void) pthread_mutex_unlock(&mq->m_resp_mutex); - queue_message_set(mq->m_q, 0, msg_mgmt_rply, 0); - break; - - case msg_mgmt_rply: - mq = (mgmt_request_t *)m->msg_data; - buf = mq->m_u.m_resp; - tgt_buf_add_tag(buf, XML_ELEMENT_STATS, Tag_End); - tgt_buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End); - - (void) pthread_mutex_unlock(&mq->m_resp_mutex); - queue_message_set(mq->m_q, 0, msg_mgmt_rply, 0); - break; - - case msg_reset_targ: - case msg_reset_lu: - /* ---- these are safe to ignore, no data to free ---- */ - break; - } -} - -/* - * []---- - * | conn_queue_data_remove -- free any message data left on the conn queue - * []---- - */ -void -conn_queue_data_remove(msg_t *m) -{ - mgmt_request_t *mq; - - syslog(LOG_ERR, "conn_queue_data: type %d", m->msg_type); - switch (m->msg_type) { - case msg_cmd_data_rqst: - case msg_cmd_data_out: - case msg_cmd_cmplt: - syslog(LOG_ERR, "Free'ing data which should already be gone"); - free(m->msg_data); - break; - - case msg_mgmt_rqst: - mq = (mgmt_request_t *)m->msg_data; - (void) pthread_mutex_lock(&mq->m_resp_mutex); - if (mq->m_u.m_resp != NULL) - tgt_buf_add(mq->m_u.m_resp, "queue_freed", NULL); - (void) pthread_mutex_unlock(&mq->m_resp_mutex); - queue_message_set(mq->m_q, 0, msg_mgmt_rply, 0); - break; - - default: - syslog(LOG_ERR, "Unknown connection message being free'd: %d", - m->msg_type); - free(m->msg_data); - break; - } -} diff --git a/usr/src/cmd/iscsi/iscsitgtd/utility.h b/usr/src/cmd/iscsi/iscsitgtd/utility.h deleted file mode 100644 index f4e32d3222..0000000000 --- a/usr/src/cmd/iscsi/iscsitgtd/utility.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 _TARGET_UTILITY_H -#define _TARGET_UTILITY_H - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "iscsi_conn.h" -#include <sys/iscsi_protocol.h> -#include "errcode.h" - -#define SNA32_CHECK 2147483648UL - -/* - * Generates a lot more information on each transfer. Disabling this reduces - * one possible performance impact in the data path. Event with logging turned - * off the messages are still queued which requires malloc's and possible lock - * contention on the management queue. This is a gut feeling, rather than - * actual tests to confirm. - */ -#undef FULL_DEBUG - -typedef struct thick_provo { - struct thick_provo *next, - *prev; - char *targ_name; - int lun; - target_queue_t *q; -} thick_provo_t; - -/* - * in_mark presents the state in validate_xml() - * in_lt means it enters a '<' and wants a '>' to return normal - * in_amp means it meets a '&' and wants a ';' to return normal - */ -typedef enum { - in_none, - in_lt, - in_amp -} in_mark_t; - -void util_init(); -int read_retry(int fd, char *buf, int count); -Boolean_t parse_text(iscsi_conn_t *c, int dlen, char **text, - int *text_length, int *errcode); -Boolean_t add_text(char **text, int *current_length, char *name, char *val); -char *task_to_str(int func); -void create_geom(diskaddr_t size, int *cylinders, int *heads, int *spt); -void connection_parameters_default(iscsi_conn_t *c); -int sna_lt(uint32_t n1, uint32_t n2); -int sna_lte(uint32_t n1, uint32_t n2); -void xml_rtn_msg(char **buf, err_code_t code); -Boolean_t add_target_alias(iscsi_conn_t *c, char **text, int *test_length); -Boolean_t validate_version(tgt_node_t *node, int *maj, int *min); -char *create_tpgt_list(char *tname); -Boolean_t check_access(tgt_node_t *targ, char *initiator_name, - Boolean_t req_chap); -tgt_node_t *find_target_node(char *targ_name); -void util_title(target_queue_t *q, int type, int num, char *title); -Boolean_t util_create_guid(char **guid, uchar_t id_type); -Boolean_t strtoll_multiplier(char *str, uint64_t *sp); -void thick_provo_stop(char *targ, int lun); -void *thick_provo_start(void *v); -Boolean_t thick_provo_chk_thr(char *targ, int lun); -void remove_target_common(char *name, int lun, char **msg); -char *get_local_name(char *iname); -Boolean_t validate_xml(char *req); - - -#ifdef __cplusplus -} -#endif - -#endif /* _TARGET_UTILITY_H */ diff --git a/usr/src/cmd/svc/shell/mfsthistory b/usr/src/cmd/svc/shell/mfsthistory index ec86bd83f3..7a719d1c49 100644 --- a/usr/src/cmd/svc/shell/mfsthistory +++ b/usr/src/cmd/svc/shell/mfsthistory @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This file is for historical purposes only, and should not be modified. @@ -371,8 +371,6 @@ svc:/system/nws_ii:default var/svc/manifest/system/nws_ii.xml svc:/system/nws_ii var/svc/manifest/system/nws_ii.xml svc:/network/ipmievd:default var/svc/manifest/network/ipmievd.xml svc:/network/ipmievd var/svc/manifest/network/ipmievd.xml -svc:/system/iscsitgt:default var/svc/manifest/system/iscsi_target.xml -svc:/system/iscsitgt var/svc/manifest/system/iscsi_target.xml svc:/network/isns_server:default var/svc/manifest/network/isns_server.xml svc:/network/isns_server var/svc/manifest/network/isns_server.xml svc:/application/wnn8/server:default var/svc/manifest/application/wnn8/wnn8-server.xml diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c index 09ea03b92f..0bec448ea6 100644 --- a/usr/src/cmd/truss/codes.c +++ b/usr/src/cmd/truss/codes.c @@ -1216,8 +1216,6 @@ const struct ioc { "zfs_cmd_t" }, { (uint_t)ZFS_IOC_GET_FSACL, "ZFS_IOC_GET_FSACL", "zfs_cmd_t" }, - { (uint_t)ZFS_IOC_ISCSI_PERM_CHECK, "ZFS_IOC_ISCSI_PERM_CHECK", - "zfs_cmd_t" }, { (uint_t)ZFS_IOC_SHARE, "ZFS_IOC_SHARE", "zfs_cmd_t" }, { (uint_t)ZFS_IOC_INHERIT_PROP, "ZFS_IOC_INHERIT_PROP", diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index ce65fd57a8..d08f792080 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -3189,42 +3189,9 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol, return (1); break; } - } else { + } else assert(op == OP_SHARE); - /* - * Ignore any volumes that aren't shared. - */ - verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, - sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0); - - if (strcmp(shareopts, "off") == 0) { - if (!explicit) - return (0); - - (void) fprintf(stderr, gettext("cannot share '%s': " - "'shareiscsi' property not set\n"), - zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("set 'shareiscsi' " - "property or use iscsitadm(1M) to share this " - "volume\n")); - return (1); - } - - if (zfs_is_shared_iscsi(zhp)) { - if (!explicit) - return (0); - - (void) fprintf(stderr, gettext("cannot share " - "'%s': volume already shared\n"), - zfs_get_name(zhp)); - return (1); - } - - if (zfs_share_iscsi(zhp) != 0) - return (1); - } - return (0); } @@ -3345,11 +3312,9 @@ share_mount(int op, int argc, char **argv) if (strcmp(argv[0], "nfs") == 0 || strcmp(argv[0], "smb") == 0) { types = ZFS_TYPE_FILESYSTEM; - } else if (strcmp(argv[0], "iscsi") == 0) { - types = ZFS_TYPE_VOLUME; } else { (void) fprintf(stderr, gettext("share type " - "must be 'nfs', 'smb' or 'iscsi'\n")); + "must be 'nfs' or 'smb'\n")); usage(B_FALSE); } protocol = argv[0]; @@ -3432,7 +3397,7 @@ share_mount(int op, int argc, char **argv) } /* - * zfs mount -a [nfs | iscsi] + * zfs mount -a [nfs] * zfs mount filesystem * * Mount all filesystems, or mount the given filesystem. @@ -3444,7 +3409,7 @@ zfs_do_mount(int argc, char **argv) } /* - * zfs share -a [nfs | iscsi | smb] + * zfs share -a [nfs | smb] * zfs share filesystem * * Share all filesystems, or share the given filesystem. @@ -3600,7 +3565,7 @@ unshare_unmount(int op, int argc, char **argv) int ret = 0; int types, c; zfs_handle_t *zhp; - char nfsiscsi_mnt_prop[ZFS_MAXPROPLEN]; + char nfs_mnt_prop[ZFS_MAXPROPLEN]; char sharesmb[ZFS_MAXPROPLEN]; /* check options */ @@ -3685,25 +3650,25 @@ unshare_unmount(int op, int argc, char **argv) switch (op) { case OP_SHARE: verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, - nfsiscsi_mnt_prop, - sizeof (nfsiscsi_mnt_prop), + nfs_mnt_prop, + sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfsiscsi_mnt_prop, "off") != 0) + if (strcmp(nfs_mnt_prop, "off") != 0) break; verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, - nfsiscsi_mnt_prop, - sizeof (nfsiscsi_mnt_prop), + nfs_mnt_prop, + sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfsiscsi_mnt_prop, "off") == 0) + if (strcmp(nfs_mnt_prop, "off") == 0) continue; break; case OP_MOUNT: /* Ignore legacy mounts */ verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, - nfsiscsi_mnt_prop, - sizeof (nfsiscsi_mnt_prop), + nfs_mnt_prop, + sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) + if (strcmp(nfs_mnt_prop, "legacy") == 0) continue; /* Ignore canmount=noauto mounts */ if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == @@ -3771,29 +3736,6 @@ unshare_unmount(int op, int argc, char **argv) uu_avl_destroy(tree); uu_avl_pool_destroy(pool); - if (op == OP_SHARE) { - /* - * Finally, unshare any volumes shared via iSCSI. - */ - zfs_handle_t **dslist = NULL; - size_t i, count = 0; - - get_all_datasets(ZFS_TYPE_VOLUME, &dslist, &count, - B_FALSE); - - if (count != 0) { - qsort(dslist, count, sizeof (void *), - dataset_cmp); - - for (i = 0; i < count; i++) { - if (zfs_unshare_iscsi(dslist[i]) != 0) - ret = 1; - zfs_close(dslist[i]); - } - - free(dslist); - } - } } else { if (argc != 1) { if (argc == 0) @@ -3825,20 +3767,20 @@ unshare_unmount(int op, int argc, char **argv) if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) { verify(zfs_prop_get(zhp, op == OP_SHARE ? ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT, - nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop), NULL, + nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); switch (op) { case OP_SHARE: verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, - nfsiscsi_mnt_prop, - sizeof (nfsiscsi_mnt_prop), + nfs_mnt_prop, + sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0); verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, sharesmb, sizeof (sharesmb), NULL, NULL, 0, B_FALSE) == 0); - if (strcmp(nfsiscsi_mnt_prop, "off") == 0 && + if (strcmp(nfs_mnt_prop, "off") == 0 && strcmp(sharesmb, "off") == 0) { (void) fprintf(stderr, gettext("cannot " "unshare '%s': legacy share\n"), @@ -3858,7 +3800,7 @@ unshare_unmount(int op, int argc, char **argv) break; case OP_MOUNT: - if (strcmp(nfsiscsi_mnt_prop, "legacy") == 0) { + if (strcmp(nfs_mnt_prop, "legacy") == 0) { (void) fprintf(stderr, gettext("cannot " "unmount '%s': legacy " "mountpoint\n"), zfs_get_name(zhp)); @@ -3877,29 +3819,6 @@ unshare_unmount(int op, int argc, char **argv) } break; } - } else { - assert(op == OP_SHARE); - - verify(zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, - nfsiscsi_mnt_prop, sizeof (nfsiscsi_mnt_prop), - NULL, NULL, 0, B_FALSE) == 0); - - if (strcmp(nfsiscsi_mnt_prop, "off") == 0) { - (void) fprintf(stderr, gettext("cannot unshare " - "'%s': 'shareiscsi' property not set\n"), - zfs_get_name(zhp)); - (void) fprintf(stderr, gettext("set " - "'shareiscsi' property or use " - "iscsitadm(1M) to share this volume\n")); - ret = 1; - } else if (!zfs_is_shared_iscsi(zhp)) { - (void) fprintf(stderr, gettext("cannot " - "unshare '%s': not currently shared\n"), - zfs_get_name(zhp)); - ret = 1; - } else if (zfs_unshare_iscsi(zhp) != 0) { - ret = 1; - } } zfs_close(zhp); diff --git a/usr/src/common/zfs/zfs_prop.c b/usr/src/common/zfs/zfs_prop.c index b6f80614f8..340fb94a20 100644 --- a/usr/src/common/zfs/zfs_prop.c +++ b/usr/src/common/zfs/zfs_prop.c @@ -285,8 +285,6 @@ zfs_prop_init(void) ZFS_TYPE_FILESYSTEM, "<path> | legacy | none", "MOUNTPOINT"); register_string(ZFS_PROP_SHARENFS, "sharenfs", "off", PROP_INHERIT, ZFS_TYPE_FILESYSTEM, "on | off | share(1M) options", "SHARENFS"); - register_string(ZFS_PROP_SHAREISCSI, "shareiscsi", "off", PROP_INHERIT, - ZFS_TYPE_DATASET, "on | off | type=<type>", "SHAREISCSI"); register_string(ZFS_PROP_TYPE, "type", NULL, PROP_READONLY, ZFS_TYPE_DATASET, "filesystem | volume | snapshot", "TYPE"); register_string(ZFS_PROP_SHARESMB, "sharesmb", "off", PROP_INHERIT, @@ -345,7 +343,7 @@ zfs_prop_init(void) register_hidden(ZFS_PROP_NAME, "name", PROP_TYPE_STRING, PROP_READONLY, ZFS_TYPE_DATASET, "NAME"); register_hidden(ZFS_PROP_ISCSIOPTIONS, "iscsioptions", PROP_TYPE_STRING, - PROP_INHERIT, ZFS_TYPE_VOLUME, "ISCSIOPTIONS"); + PROP_READONLY, ZFS_TYPE_VOLUME, "ISCSIOPTIONS"); register_hidden(ZFS_PROP_STMF_SHAREINFO, "stmf_sbd_lu", PROP_TYPE_STRING, PROP_INHERIT, ZFS_TYPE_VOLUME, "STMF_SBD_LU"); diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index b4c910a1ed..8a2993d5af 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -114,7 +114,6 @@ SUBDIRS += \ libinetutil \ libipmp \ libiscsit \ - libiscsitgt \ libkmf \ libkstat \ libkvm \ @@ -423,7 +422,6 @@ HDRSUBDIRS= \ libipmp \ libipp \ libiscsit \ - libiscsitgt \ libkstat \ libkvm \ libmail \ @@ -640,7 +638,7 @@ librestart: libuutil libscf pkcs11: libcryptoutil print: libldap5 udapl/udapl_tavor: udapl/libdat -libzfs: libdevid libgen libnvpair libuutil libiscsitgt \ +libzfs: libdevid libgen libnvpair libuutil \ libadm libavl libefi libidmap libmd libzfs_jni: libdiskmgt libnvpair libzfs libzpool: libavl libumem libnvpair diff --git a/usr/src/lib/libiscsitgt/Makefile b/usr/src/lib/libiscsitgt/Makefile deleted file mode 100644 index 58d09d3c9b..0000000000 --- a/usr/src/lib/libiscsitgt/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.lib - -SUBDIRS = $(MACH) -$(BUILD64)SUBDIRS += $(MACH64) - -all := TARGET= all -clean := TARGET= clean -clobber := TARGET= clobber -install := TARGET= install -lint := TARGET= lint -test := TARGET= test - -HDRS= libiscsitgt.h iscsitgt_impl.h -HDRDIR= common - -.KEEP_STATE: - -all clean clobber install lint: $(SUBDIRS) - -install_h: $(ROOTHDRS) - -check: $(CHECKHDRS) - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: - -include ../Makefile.targ diff --git a/usr/src/lib/libiscsitgt/Makefile.com b/usr/src/lib/libiscsitgt/Makefile.com deleted file mode 100644 index 3d4559c7fd..0000000000 --- a/usr/src/lib/libiscsitgt/Makefile.com +++ /dev/null @@ -1,54 +0,0 @@ -# -# 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 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -LIBRARY= libiscsitgt.a -VERS= .1 -OBJECTS= if_zfs.o if_gen.o xml.o gen.o - -include ../../Makefile.lib -include ../../Makefile.rootfs - -SRCDIR = ../common - -LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lscf -lc -$(DYNLIB) := LDLIBS += -lxml2 -SRCS = $(OBJECTS:%.o=$(SRCDIR)/%.c) - -$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) - -CFLAGS += $(CCVERBOSE) -CPPFLAGS += -I/usr/include/libxml2 -I$(SRCDIR) \ - -I../../../cmd/iscsi/iscsitgtd - -.KEEP_STATE: - -all: $(LIBS) - -lint: lintcheck - -include ../../Makefile.targ diff --git a/usr/src/lib/libiscsitgt/amd64/Makefile b/usr/src/lib/libiscsitgt/amd64/Makefile deleted file mode 100644 index 2e8cdecf75..0000000000 --- a/usr/src/lib/libiscsitgt/amd64/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.com -include ../../Makefile.lib.64 - -install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libiscsitgt/common/gen.c b/usr/src/lib/libiscsitgt/common/gen.c deleted file mode 100644 index 12bc7bad64..0000000000 --- a/usr/src/lib/libiscsitgt/common/gen.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * 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. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Support routines for library - */ -#include <errno.h> -#include <strings.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include <libscf.h> -#include <door.h> -#include <libxml/xmlreader.h> -#include <sys/mman.h> - -#include "iscsitgt_impl.h" - -#define WAIT_FOR_SERVICE 15 -#define WAIT_FOR_DOOR 15 -static char *service = "system/iscsitgt:default"; - -static Boolean_t check_and_online(int); - -tgt_node_t * -tgt_door_call(char *str, int smf_flags) -{ - tgt_node_t *n = NULL; - door_arg_t d; - int s; - int allocated; - xmlTextReaderPtr r; - char *door_buf = NULL; - - /* - * Setup the door pointers for the initial try. - */ - allocated = MAX(DOOR_MIN_SPACE, strlen(str) + 1); - if ((door_buf = malloc(allocated)) == NULL) - return (NULL); - (void) strncpy(door_buf, str, allocated); - bzero(&d, sizeof (d)); - d.data_ptr = door_buf; - d.data_size = allocated; - d.rbuf = door_buf; - d.rsize = allocated; - - /* - * It's entirely possible that we'll be sending this request more - * than once. In the case of a list operation it's unknown how much - * data will be required, so the request will be sent and the daemon - * will return information on how large of a buffer is needed. - * It possible that the second request, with a larger buffer, also - * fails with not enough space since between the first and second - * calls a third party could have created another target increasing - * the space required. This is not an error, just need to handle it. - */ - do { - /* - * Open the door and if that doesn't work or the first door call - * fails, try to bring the service online. Then repeat one - * more time. If the second attempt at the door_call fails - * then bail out. - */ - if (((s = open(ISCSI_TARGET_MGMT_DOOR, 0)) == -1) || - (door_call(s, &d) == -1)) { - if (s != -1) { - (void) close(s); - s = -1; - } - if (check_and_online(smf_flags) == False) { - goto error; - } else if ((s = open(ISCSI_TARGET_MGMT_DOOR, 0)) == - -1) { - goto error; - } else if (door_call(s, &d) == -1) { - goto error; - } - } - - if (d.rbuf == NULL) - goto error; - - if ((r = (xmlTextReaderPtr)xmlReaderForMemory(d.rbuf, - strlen(d.rbuf), NULL, NULL, 0)) == NULL) - goto error; - - while (xmlTextReaderRead(r) == 1) - if (tgt_node_process(r, &n) == False) - break; - xmlFreeTextReader(r); - - /* - * Check to see if our request failed to provide enough - * buffer room. This can occur if: - * (1) The request caused an error and the message - * is larger than the request. - * (2) We're requesting a configuration list which is - * fairly large and need to reissue the request with - * a larger buffer, which the daemon is kind enough - * to tell us the size needed. - */ - if (tgt_find_value_int(n, XML_ELEMENT_MORESPACE, - &allocated) == True) { - - tgt_node_free(n); - n = NULL; - - /* - * It's possible that we've already done a request - * with a larger buffer, but before we could reissue - * the request the results got bigger. Targets being - * added to the configuration would be the common - * cause of this condition. - */ - if (door_buf != NULL) - free(door_buf); - - if ((door_buf = malloc(allocated)) == NULL) - goto error; - - (void) strncpy(door_buf, str, allocated); - d.data_ptr = door_buf; - d.data_size = allocated; - d.rbuf = door_buf; - d.rsize = allocated; - } - - (void) close(s); - s = -1; - } while (n == NULL); - -error: - if (door_buf) - free(door_buf); - (void) close(s); - return (n); -} - -static Boolean_t -is_online(void) -{ - char *s; - Boolean_t rval = False; - - if (getenv("iscsitgt_no_daemon") != NULL) { - rval = True; - } else { - if ((s = smf_get_state(service)) != NULL) { - if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0) - rval = True; - free(s); - } - } - - return (rval); -} - -static Boolean_t -is_auto_enabled(void) -{ - scf_simple_prop_t *prop; - uint8_t *ret; - Boolean_t rval = True; - - if ((prop = scf_simple_prop_get(NULL, service, "application", - "auto_enable")) == NULL) - return (True); - - if ((ret = scf_simple_prop_next_boolean(prop)) != NULL) - rval = (*ret != 0); - - scf_simple_prop_free(prop); - - return (rval); -} - -static Boolean_t -check_and_online(int smf_flags) -{ - int i; - int fd; - door_arg_t d; - - if (!is_online()) { - if (!is_auto_enabled()) - return (False); - - if (smf_enable_instance(service, smf_flags) != 0) - return (False); - - for (i = 0; i < WAIT_FOR_SERVICE; i++) { - if (is_online() == True) - break; - (void) sleep(1); - } - - if (i == WAIT_FOR_SERVICE) - return (False); - } - - for (i = 0; i < WAIT_FOR_DOOR; i++) { - if ((fd = open(ISCSI_TARGET_MGMT_DOOR, 0)) >= 0) { - /* - * There's at least a file with the same name as our - * door. Let's see if someone is currently answering - * by sending an empty XML request. - */ - d.data_ptr = "<config></config>"; - d.data_size = strlen(d.data_ptr) + 1; - d.desc_ptr = NULL; - d.desc_num = 0; - d.rbuf = NULL; - d.rsize = 0; - - if (door_call(fd, &d) == 0) { - /* - * The daemon is now ready to handle requests. - */ - (void) close(fd); - return (True); - } else - (void) close(fd); - - } - if (!is_online()) - break; - (void) sleep(1); - } - return (False); -} - -/* - * Not using Boolean_t here, since that is a - * private type to the library - */ -int -iscsitgt_svc_online() -{ - return ((is_online() == True) ? 0 : 1); -} diff --git a/usr/src/lib/libiscsitgt/common/if_gen.c b/usr/src/lib/libiscsitgt/common/if_gen.c deleted file mode 100644 index 1ab74664fe..0000000000 --- a/usr/src/lib/libiscsitgt/common/if_gen.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <libiscsitgt.h> - -/* - * iscsitgt_init -- Create a handle for each daemon - */ -/*ARGSUSED*/ -iscsit_handle_t -iscsitgt_init(char *host) -{ - return (NULL); -} - -/* - * iscsitgt_fini -- free resources allocated by iscsitgt_init() - */ -/*ARGSUSED*/ -void -iscsitgt_fini(iscsit_handle_t h) -{ -} diff --git a/usr/src/lib/libiscsitgt/common/if_zfs.c b/usr/src/lib/libiscsitgt/common/if_zfs.c deleted file mode 100644 index 3528872286..0000000000 --- a/usr/src/lib/libiscsitgt/common/if_zfs.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Methods for ZFS to notify the iSCSI Target about which ZVOLs - * need to be made available. - */ - -#include <libiscsitgt.h> -#include <strings.h> -#include <errno.h> -#include <libscf.h> -#include <errcode.h> - -#include "iscsitgt_impl.h" - -/* - * iscsitgt_zfs_share -- share a ZFS volume as an iSCSI target - */ -int -iscsitgt_zfs_share(const char *dataset) -{ - char *str = NULL; - tgt_node_t *n; - int code; - - tgt_buf_add_tag(&str, "create", Tag_Start); - tgt_buf_add_tag(&str, "zfs", Tag_Start); - tgt_buf_add(&str, "name", dataset); - tgt_buf_add_tag(&str, "zfs", Tag_End); - tgt_buf_add_tag(&str, "create", Tag_End); - - if ((n = tgt_door_call(str, SMF_TEMPORARY)) == NULL) { - if (iscsitgt_svc_online() != 0) { - errno = EPERM; - } else { - errno = EINVAL; - } - free(str); - return (-1); - } - - if (strcmp(n->x_name, XML_ELEMENT_ERROR) == 0 && - tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True) { - if (code == 1000) { - free(str); - tgt_node_free(n); - return (0); - } else { - errno = (code == ERR_NO_PERMISSION) ? EPERM : EINVAL; - } - } else { - errno = EINVAL; - } - free(str); - tgt_node_free(n); - return (-1); -} - -/* - * iscsitgt_zfs_unshare -- unshare a ZFS volume - */ -int -iscsitgt_zfs_unshare(const char *dataset) -{ - char *str = NULL; - tgt_node_t *n; - int code; - - tgt_buf_add_tag(&str, "delete", Tag_Start); - tgt_buf_add_tag(&str, "zfs", Tag_Start); - tgt_buf_add(&str, "name", dataset); - tgt_buf_add_tag(&str, "zfs", Tag_End); - tgt_buf_add_tag(&str, "delete", Tag_End); - - if ((n = tgt_door_call(str, SMF_TEMPORARY)) == NULL) { - errno = EINVAL; - free(str); - return (-1); - } - - if (strcmp(n->x_name, XML_ELEMENT_ERROR) == 0 && - tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True) { - if (code == 1000) { - free(str); - tgt_node_free(n); - return (0); - } else { - errno = (code == ERR_NO_PERMISSION) ? EPERM : EINVAL; - } - } else { - errno = EINVAL; - } - - free(str); - tgt_node_free(n); - return (-1); -} - -int -iscsitgt_zfs_is_shared(const char *dataset) -{ - char *str = NULL; - tgt_node_t *n; - int code; - - tgt_buf_add_tag(&str, "modify", Tag_Start); - tgt_buf_add_tag(&str, "zfs", Tag_Start); - tgt_buf_add(&str, "name", dataset); - tgt_buf_add(&str, XML_ELEMENT_VALIDATE, XML_VALUE_TRUE); - tgt_buf_add_tag(&str, "zfs", Tag_End); - tgt_buf_add_tag(&str, "modify", Tag_End); - - if ((n = tgt_door_call(str, SMF_TEMPORARY)) == NULL) { - errno = EINVAL; - free(str); - return (-1); - } - if (strcmp(n->x_name, XML_ELEMENT_ERROR) == 0 && - tgt_find_value_int(n, XML_ELEMENT_CODE, &code) == True && - code == 1000) { - free(str); - tgt_node_free(n); - return (1); - } - - free(str); - tgt_node_free(n); - return (0); -} diff --git a/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h b/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h deleted file mode 100644 index 415273871f..0000000000 --- a/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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 _ISCSITGT_IMPL_H -#define _ISCSITGT_IMPL_H - -/* - * Block comment which describes the contents of this file. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <libxml/xmlreader.h> - -#ifndef MIN -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#endif -#ifndef MAX -#define MAX(x, y) ((x) > (y) ? (x) : (y)) -#endif - -/* - * Solaris typedefs boolean_t to be an enum with B_TRUE and B_FALSE. - * MacOS X typedefs boolean_t to be an int with #defines for TRUE & FALSE - * I like the use of enum's for return codes so that compilers can catch - * sloppy coding practices so I've defined a Boolean_t which is unique here. - */ -typedef enum { - False = 0, - True = 1 -} Boolean_t; - -#ifndef DTYPE_OSD -#define DTYPE_OSD 0x11 -#endif - -#define DOOR_MIN_SPACE 128 - -#define ISCSI_TARGET_MGMT_DOOR "/var/run/iscsi_tgt_door" -/* - * XML element defines. - */ -#define XML_ELEMENT_ERROR "error" -#define XML_ELEMENT_CODE "code" -#define XML_ELEMENT_MESSAGE "message" -#define XML_ELEMENT_TRANSVERS "transport-version" -#define XML_ELEMENT_PROPS "props" -#define XML_ELEMENT_DATAOUT "data-out-size" -#define XML_ELEMENT_BASEDIR "base-directory" -#define XML_ELEMENT_CHAPSECRET "chap-secret" -#define XML_ELEMENT_DELETE_CHAPSECRET "delete-chap-secret" -#define XML_ELEMENT_CHAPNAME "chap-name" -#define XML_ELEMENT_DELETE_CHAPNAME "delete-chap-name" -#define XML_ELEMENT_RAD_ACCESS "radius-access" -#define XML_ELEMENT_RAD_SERV "radius-server" -#define XML_ELEMENT_DELETE_RAD_SERV "delete-radius-server" -#define XML_ELEMENT_RAD_SECRET "radius-secret" -#define XML_ELEMENT_DELETE_RAD_SECRET "delete-radius-secret" -#define XML_ELEMENT_ISNS_ACCESS "isns-access" -#define XML_ELEMENT_ISNS_SERV "isns-server" -#define XML_ELEMENT_ISNS_SERVER_STATUS "isns-server-status" -#define XML_ELEMENT_FAST "fast-write-ack" -#define XML_ELEMENT_NAME "name" -#define XML_ELEMENT_ACL "acl" -#define XML_ELEMENT_ACLLIST "acl-list" -#define XML_ELEMENT_TPGT "tpgt" -#define XML_ELEMENT_TPGTLIST "tpgt-list" -#define XML_ELEMENT_SIZE "size" -#define XML_ELEMENT_LUN "lun" -#define XML_ELEMENT_LUNLIST "lun-list" -#define XML_ELEMENT_TYPE "type" -#define XML_ELEMENT_ALIAS "alias" -#define XML_ELEMENT_BACK "backing-store" -#define XML_ELEMENT_DELETE_BACK "delete-backing-store" -#define XML_ELEMENT_TARG "target" -#define XML_ELEMENT_INIT "initiator" -#define XML_ELEMENT_ZFS "zfs" -#define XML_ELEMENT_ADMIN "admin" -#define XML_ELEMENT_INAME "iscsi-name" -#define XML_ELEMENT_MAXRECV "maxrecv" -#define XML_ELEMENT_IPADDR "ip-address" -#define XML_ELEMENT_IPADDRLIST "ip-address-list" -#define XML_ELEMENT_ALL "all" -#define XML_ELEMENT_VERBOSE "verbose" -#define XML_ELEMENT_LIST "list" -#define XML_ELEMENT_RESULT "result" -#define XML_ELEMENT_TIMECON "time-connected" -#define XML_ELEMENT_READCMDS "read-commands" -#define XML_ELEMENT_WRITECMDS "write-commands" -#define XML_ELEMENT_READBLKS "read-blks" -#define XML_ELEMENT_WRITEBLKS "write-blks" -#define XML_ELEMENT_STATS "statistics" -#define XML_ELEMENT_CONN "connection" -#define XML_ELEMENT_LUNINFO "lun-information" -#define XML_ELEMENT_VID "vid" -#define XML_ELEMENT_PID "pid" -#define XML_ELEMENT_GUID "guid" -#define XML_ELEMENT_DTYPE "dtype" -#define XML_ELEMENT_IOSTAT "iostat" -#define XML_ELEMENT_MACADDR "mac-addr" -#define XML_ELEMENT_MGMTPORT "mgmt-port" -#define XML_ELEMENT_ISCSIPORT "iscsi-port" -#define XML_ELEMENT_TARGLOG "target-log" -#define XML_ELEMENT_DBGLVL "dbg-lvl" -#define XML_ELEMENT_LOGLVL "qlog-lvl" -#define XML_ELEMENT_DBGDAEMON "daemonize" -#define XML_ELEMENT_ENFORCE "enforce-strict-guid" -#define XML_ELEMENT_VERS "version" -#define XML_ELEMENT_MMAP_LUN "mmap-lun" -#define XML_ELEMENT_RPM "rpm" -#define XML_ELEMENT_HEADS "heads" -#define XML_ELEMENT_CYLINDERS "cylinders" -#define XML_ELEMENT_SPT "spt" -#define XML_ELEMENT_BPS "bps" -#define XML_ELEMENT_INTERLEAVE "interleave" -#define XML_ELEMENT_PARAMS "params" -#define XML_ELEMENT_MAXCMDS "max-outstanding-cmds" -#define XML_ELEMENT_THIN_PROVO "thin-provisioning" -#define XML_ELEMENT_DISABLE_TPGS "disable-tpgs" -#define XML_ELEMENT_STATUS "status" -#define XML_ELEMENT_PROGRESS "progress" -#define XML_ELEMENT_TIMESTAMPS "time-stamps" -#define XML_ELEMENT_INCORE "in-core" -#define XML_ELEMENT_VALIDATE "validate" -#define XML_ELEMENT_MORESPACE "more-space-required" -#define XML_VALUE_TRUE "true" -#define XML_ELEMENT_PGR_PERSIST "PGR-persist" -#define XML_ELEMENT_PGR_BASEDIR "PGR-basedir" - -typedef enum { - NodeFree, - NodeAlloc, - NodeName, - NodeValue -} tgt_node_state; - -typedef enum { MatchName, MatchBoth } match_type_t; - -typedef struct tgt_node { - struct tgt_node *x_parent, - *x_child, - *x_sibling, - *x_attr; - char *x_name, - *x_value; - tgt_node_state x_state; -} tgt_node_t; - -typedef enum val_type { Tag_String, Tag_Start, Tag_End } val_type_t; -typedef enum xml_val_type { String, Int, Uint64 } xml_val_type_t; - -tgt_node_t *tgt_door_call(char *str, int smf_flags); -void tgt_dump2buf(tgt_node_t *t, char **buf); - -tgt_node_t *tgt_node_alloc(char *name, xml_val_type_t type, void *value); -void tgt_node_free(tgt_node_t *x); -void tgt_node_replace(tgt_node_t *parent, tgt_node_t *child, match_type_t m); -Boolean_t tgt_node_remove(tgt_node_t *parent, tgt_node_t *child, - match_type_t m); -tgt_node_t *tgt_node_next(tgt_node_t *n, char *name, tgt_node_t *cur); -tgt_node_t *tgt_node_next_child(tgt_node_t *n, char *name, tgt_node_t *cur); -tgt_node_t *tgt_node_dup(tgt_node_t *n); -tgt_node_t *tgt_node_find(tgt_node_t *n, char *name); -void tgt_node_add(tgt_node_t *p, tgt_node_t *c); -void tgt_node_add_attr(tgt_node_t *p, tgt_node_t *a); -Boolean_t tgt_node_process(xmlTextReaderPtr r, tgt_node_t **node); - -void tgt_buf_add(char **b, char *element, const char *cdata); -void tgt_buf_add_tag(char **b, const char *str, val_type_t type); -void tgt_buf_add_tag_and_attr(char **b, char *str, char *attr); - -Boolean_t tgt_xml_encode(uint8_t *ip, size_t ip_size, char **buf, - size_t *buf_size); -Boolean_t tgt_xml_decode(char *buf, uint8_t **ip, size_t *ip_size); -Boolean_t tgt_find_value_str(tgt_node_t *n, char *name, char **value); -Boolean_t tgt_find_value_int(tgt_node_t *n, char *name, int *value); -Boolean_t tgt_find_value_intchk(tgt_node_t *n, char *name, int *value); -Boolean_t tgt_find_value_boolean(tgt_node_t *n, char *name, Boolean_t *value); -Boolean_t tgt_find_attr_str(tgt_node_t *n, char *attr, char **value); -Boolean_t tgt_update_value_str(tgt_node_t *node, char *name, char *str); - -#ifdef __cplusplus -} -#endif - -#endif /* _ISCSITGT_IMPL_H */ diff --git a/usr/src/lib/libiscsitgt/common/libiscsitgt.h b/usr/src/lib/libiscsitgt/common/libiscsitgt.h deleted file mode 100644 index cf01a62fea..0000000000 --- a/usr/src/lib/libiscsitgt/common/libiscsitgt.h +++ /dev/null @@ -1,578 +0,0 @@ -/* - * 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 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _LIBISCSITGT_H -#define _LIBISCSITGT_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Management API for the iSCSI Target. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * These includes resolve - */ -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/iscsi_protocol.h> -#include <sys/scsi/generic/inquiry.h> - -#define EUI64_SIZE 16 -#define VID_SIZE 8 -#define PID_SIZE 16 - -/* - * []------------------------------------------------------------------[] - * | Structures and enums returned by the list functions | - * []------------------------------------------------------------------[] - */ - -typedef enum { LU_Offline, LU_Online } iscsit_status_t; -typedef enum { Target, Initiator, TPGT } iscsit_obj_type_t; - -/* - * Logical Unit (LU) Structure. - * Each iSCSI Target has one or more Logical Units. - */ -typedef struct iscsit_lu { - /* This is the LU number for SCSI commands */ - int l_num; - - /* Globally unique identifier */ - uint8_t l_guid[EUI64_SIZE]; - - /* - * VID/PID used in SCSI INQUIRY responses - */ - char l_vid[VID_SIZE], - l_pid[PID_SIZE]; - /* - * Value will be one of DTYPE_DIRECT, DTYPE_SEQUENTIAL, etc ... - * Look at sys/scsi/generic/inquiry.h for full list - */ - uint8_t l_dtype; - - /* Size of device in blocks */ - diskaddr_t l_size; - - iscsit_status_t l_status; -} iscsit_lu_t; - -/* - * iSCSI Session information. - */ -typedef struct iscsit_conn { - char c_name[ISCSI_MAX_NAME_LEN], - *c_alias; -} iscsit_conn_t; - -typedef struct iscsit_target { - /* This is the full IQN name of the target */ - char t_name[ISCSI_MAX_NAME_LEN]; - - /* - * The Alias which is the same as "friendly name" used during the - * creation of the target. - */ - char *t_alias; - - /* - * The number of Logical Units associated with this target. - * There will always be at least one LU with a value of 0. - * If there are more than LU the order is not guaranteed. - */ - int t_lu_count; - iscsit_lu_t **t_lu_list; - - /* - * A list of initiator which may access this target. This list - * may be 0 in length. - */ - int t_acl_count; - char **t_acl_list; - - /* - * Target Portal Group Tags. A value of zero for the count - * is valid. - */ - int t_tpgt_count; - char **t_tpgt_list; - - /* - * The number of sessions that are currently attached to the - * target. Zero is valid. - */ - int t_conn_count; - iscsit_conn_t **t_conn_list; -} iscsit_target_t; - -/* - * Information stored locally about initiators. Local initiator information - * is setup when administrators wish to control access to each target. The - * use of iSNS will be the prefered method once it's supported. - */ -typedef struct iscsit_initiator { - char i_name[ISCSI_MAX_NAME_LEN], - *i_chap_name; - /* - * While the target daemon has the CHAP secret available it's - * never returned. The CHAP name and secret can be changed at - * any time. This boolean will indicate if the CHAP secret is set - * and if so will cause the daemon to perform unidirectional - * authentication. - */ - boolean_t i_chap_secret_set; -} iscsit_initiator_t; - -/* - * The list of IP addresses associated with a Target Portal Group Tag - */ -typedef struct iscsit_tpgt { - int t_ip_count; - struct sockaddr_storage **t_ip_list; -} iscsit_tpgt_t; - -/* - * These are values which are used globally through the target daemon. - */ -typedef struct iscsit_admin { - /* - * This is the targets CHAP information. When an initiator needs - * to authenticate the target these values are used when creating - * the response. - */ - char *a_chap_name; - boolean_t a_chap_secret_set; - - /* - * The location of the target configuration and default storage for LUs - */ - char *a_base_directory; - - struct sockaddr_storage a_radius_server; - boolean_t a_radius_secret_set, - a_isns_discovery; - struct sockaddr_storage a_isns_ip; - boolean_t a_fast_write_ack; -} iscsit_admin_t; - -typedef void *iscsit_handle_t; - -/* - * []------------------------------------------------------------------[] - * | Funtion Prototypes | - * []------------------------------------------------------------------[] - */ - -/* - * []------------------------------------------------------------------[] - * | Functions for ZFS | - * []------------------------------------------------------------------[] - */ -/* - * iscsitgt_zfs_share -- advertise a ZFS volume through iSCSI - * iscsitgt_zfs_unshare -- unadvertise a ZFS volume through iSCSI - * - * dataset = this must be a valid ZFS dataset which has a "type" property - * of "volume". - * - * These functions will return 0 on success and -1 on failure setting errno - * thusly: - * - * ENODEV - dataset not found - * EINVAL - a share parameter has an invalid value - * ENOSYS - the option string cannot be understood for any other reason - */ -int iscsitgt_zfs_share(const char *dataset); -int iscsitgt_zfs_unshare(const char *dataset); - -/* - * iscsitgt_zfs_is_shared -- returns 1 and 0 otherwise - */ -int iscsitgt_zfs_is_shared(const char *dataset); - -/* - * []------------------------------------------------------------------[] - * | Functions to create handles which are used by methods defined below| - * []------------------------------------------------------------------[] - */ -/* - * iscsitgt_init -- Create a handle for each daemon - * - * A future release will enable this library to work to control multiple - * daemons on different hosts. For now, the argument 'host' should be - * set to NULL which will indicate the local host. - */ -iscsit_handle_t iscsitgt_init(char *host); - -/* - * iscsitgt_fini -- free resources allocated by iscsitgt_init() - */ -void iscsitgt_fini(iscsit_handle_t h); - -/* - * []------------------------------------------------------------------[] - * | Funtions for creating base objects | - * []------------------------------------------------------------------[] - */ -/* - * iscsitgt_creat_target -- creates a new target/lu - * - * h = This is handle which indicates to which target the request is sent. - * If NULL, the target daemon on the current host is used. - * friendly_name = any ASCII string with the following restrictions. - * - it must be no more than 163 characters - * - it must only contain charcters from the set of 'a-z', 'A-Z', '0-9', - * ':', '.', or '-' - * The friendly_name will also be used as the iSCSI TargetAlias which - * is sent to the initiator as part of the log in parameters. - * lun = If the friendly_name has never been used before then lun must be 0. - * If friendly_name has already been created other luns will be created - * under that target. 0 <= lun <= 65535. NOTE: Using LUNs larger than - * 255 is not guaranteed to work for all initiators. - * size = The requested size for the device in blocks. There must be - * available space on the device for the create to succeed. size may - * be zero if, and only if, a 'backing' argument is given which exists. - * dtype = This indicates which type of emulation is performed by the - * daemon. Currently DTYPE_DIRECT, DTYPE_SEQUENTIAL, and DTYPE_UNKNOWN - * are supported. A dtype of DTYPE_UNKNOWN indicates to the daemon - * that a pass through mode should be used. For the pass through mode - * to work 'backing' must be a character device which supports the USCSI - * ioctl. For ZVOLs the dtype should be DTYPE_DIRECT. - * backing = optional location for the backing store. Normally the storage - * for the LU is created in the directory supplied to iscsit_mod_adm_store(). - * If the 'backing' file name doesn't exist *and* a valid device 'size' is - * given then the backing store will be created in that location. When the - * target/lu is removed this backing store will also be removed. - * - * Return codes: - * EINVAL = one or more of the arguments are invalid - * ENOSPC = No space remains to create the backing store. - * EEXIST = A target with the same friendly_name already exists - */ -int iscsitgt_creat_target(iscsit_handle_t h, char *friendly_name, - int lun, diskaddr_t size, int dtype, char *backing); - -/* - * iscsitgt_creat_initiator -- creates an initiator object - * - * Associates a fully compliant iSCSI name (IQN or EUI type) with - * a really human readable name. - * - * h = Handle used to communicate with remote target daemons. A NULL - * value may be used to indicate that the local host target daemon - * friendly_name = Any ASCII string. - * iqn_name = An initiator IQN or EUI string. There will be no validation - * of the name to determine if it complies with RFC3720. This way if - * an initiator has a poorly formed name we can still be configured to - * work with it. - * - * Return codes: - * 0 = success - * EEXIST = The friendly_name is already used. - */ -int iscsitgt_creat_initiator(iscsit_handle_t h, char *friendly_name, - char *iqn_name); - -/* - * iscsitgt_creat_tpgt -- Create a Target Portal Group Tag - * - * Once a TPGT object has been created iscsitgt_add_tpgt_ip would be used - * to associate certain IP addresses with this TPGT. This is used to - * limit which NICs connections are accepted on for a given target. - * Once a TPGT is setup it can be added to a target using: - * iscsitgt_add_target_tpgt(). - * - * h = See iscsitgt_creat_target - * tpgt_num = a value between 1 and 65535 inclusive - * - * Return codes: - * 0 = success - * EEXIST = A tpgt with that number already exists. - * EINVAL = TPGT must be a value between 1 and 65535 inclusive - */ -int iscsitgt_creat_tpgt(iscsit_handle_t h, int tpgt_num); - -/* - * []------------------------------------------------------------------[] - * | Funtions for removing base objects | - * []------------------------------------------------------------------[] - */ - -/* - * iscsitgt_rem_target -- Removes a target/LU from the system - * - * Logical Unit Number 0 *must* be the last LUN removed from a target - * If not, an error will be returned. When LUN0 is removed all references - * to friendly_name are also removed from the system. e.g. Once the LU's - * are removed there's nothing else required to remove the target. - * - * h = See iscsitgt_creat_target() - * friendly_name = This is the same name used during the creation of - * the target. - * lun = Logical Unit Number - * - * Return codes: - * 0 = success - * ENOENT = either friendly_name wasn't found or lun not found - * EINVAL = attempt made to remove LUN0 while other LUs still exist. - */ -int iscsitgt_rem_target(iscsit_handle_t h, char *friendly_name, - int lun); - -/* - * iscsitgt_rem_initiator -- Removes initiator object - * - * This method removes just the initiator object, but not any references - * to this object. For example let's say an initiator was called - * payroll_server and that this server was replaced with a new server - * that had the same function, but with a new IQN value and CHAP secret. - * The user of this library could then remove the initiator object - * and create a new one with the changes *without* needing to update all - * of the target objects that have a reference to 'payroll_server' in - * their ACLs. This is a security feature. If a target has a reference - * to an initiator object which doesn't exist, nobody will be able to - * log into the target. If the daemon we're to remove all references - * along with the object it would then be possible for an initiator to - * log into the target during the time the target didn't have a reference. - * - * h = See iscsitgt_creat_target() - * friendly_name = same value as that used during create. - * - * Return codes: - * 0 = success - * ENOENT = Can't find friendly_name - */ -int iscsitgt_rem_initiator(iscsit_handle_t h, char *friendly_name); - -/* - * iscsitgt_rem_tpgt -- Removes a tpgt object - * - * Similar in function to iscsitgt_rem_initiator. This method only - * removes the TPGT object, but not any references to the object. This - * alows the administrator to remove an old TPGT and create a new one - * without needing to update each and every target first. - * - * h = See iscsitgt_creat_target - * tpgt_num = value used during create - * - * Return codes: - * 0 = success - * ENOENT = tpgt_num wasn't found - * EINVAL = a value outside of the accepted range for tpgt_num was used. - */ -int iscsitgt_rem_tpgt(iscsit_handle_t h, int tpgt_num); - -/* - * []------------------------------------------------------------------[] - * | Funtions for adding attributes to base objects | - * []------------------------------------------------------------------[] - */ -/* - * iscsitgt_add_target_initiator -- Adds an initiator object to ACL for target - * - * h = See iscsitgt_creat_target - * friendly_name = Existing target - * initiator = name of initiator object which doesn't need to exist before - * it's added. - * - * Return codes: - * 0 = success - * ENOENT = friendly_name doesn't exist. - */ -int iscsitgt_add_target_initiator(iscsit_handle_t h, char *friendly_name, - char *initiator); - -/* - * iscsitgt_add_target_tpgt -- adds TPGT to the target - * - * h = See iscsitgt_creat_target() - * friendly_name = Must be a valid target object name - * tpgt_num = While the TPGT object doesn't need to exist, the value will - * be validated to see if it's within the valid range of 1 to 65535 inclusive - * - * Return codes: - * 0 = success - * ENOENT = friendly_name not found - * EINVAL = tpgt_num is not within the valid range. - */ -int iscsitgt_add_target_tpgt(iscsit_handle_t h, char *friendly_name, - int tpgt_num); - -/* - * iscsitgt_add_tpgt_ip -- Adds IP address to TPGT object - * - * Return codes: - * 0 = success - * ENOENT = tpgt_num doesn't exist - * EINVAL = tpgt_num is not within the valid range - */ -int iscsitgt_add_tpgt_ip(iscsit_handle_t h, int tpgt_num, - struct sockaddr_storage *s); - -/* - * []------------------------------------------------------------------[] - * | Funtions for deleting attributes from base objects | - * []------------------------------------------------------------------[] - */ -/* - * iscsitgt_del_target_initiator -- Removes initiator from target ACL - * - * h = See iscsitgt_creat_target() - * friendly_name = target object - * initiator = initiator object to remove from ACL - * - * Return codes: - * 0 = success - * ENOENT = friendly_name or initiator don't exist - */ -int iscsitgt_del_target_initiator(iscsit_handle_t h, char *friendly_name, - char *initiator); - -/* - * iscsitgt_del_target_tpgt -- Removes TPGT from specific target - * - * Return codes: - * 0 = success - * ENOENT = Either friendly_name or tpgt_num doesn't exist as a valid - * type - * EINVAL = tpgt_num is outside of the valid range (1 to 65535) - */ -int iscsitgt_del_target_tpgt(iscsit_handle_t h, char *friendly_name, - int tpgt_num); - -/* - * iscsitgt_del_tpgt_ip -- Removes IP address from TPGT - * - * Return codes: - * 0 = success - * ENOENT = tpgt_num wasn't found or the IP address wasn't found within a valid - * tpgt - * EINVAL = tpgt_num is outside of the valid range (1 to 65535) - */ -int iscsitgt_del_tpgt_ip(iscsit_handle_t h, int tpgt_num, - struct sockaddr_storage *s); - -/* - * []------------------------------------------------------------------[] - * | Funtions for modifying singular attributes for base objects | - * []------------------------------------------------------------------[] - */ -/* - * iscsitgt_mode_target_alias -- Modifies the TargetAlias associated with target - * - * By default the TargetAlias is the same as that given for the friendly_name. - * If another name is desired then it can be changed using this interface. - * - * h = See iscsitgt_creat_target() - * friendly_name = target object - * - * Return codes: - * 0 = success - * ENOENT = friendly_name doesn't exist - */ -int iscsitgt_mod_target_alias(iscsit_handle_t h, char *friendly_name, - char *alias); -int iscsitgt_mod_target_maxrec(iscsit_handle_t h, char *friendly_name, - size_t maxrecv); -int iscsitgt_mod_initiator_chap(iscsit_handle_t h, - char *friendly_name, char *chap_name, char *chap_secret); -int iscsitgt_mod_adm_store(iscsit_handle_t h, char *base); -int iscsitgt_mod_adm_chap(iscsit_handle_t h, char *chap_name, - char *chap_secret); -int iscsitgt_mod_adm_radius(iscsit_handle_t h, struct sockaddr_storage *s, - char *secret); -int iscsitgt_mod_adm_isns_discover(iscsit_handle_t h, - boolean_t find); -int iscsitgt_mod_adm_isns(iscsit_handle_t h, - struct sockaddr_storage *s); -int iscsitgt_mod_adm_fwa(iscsit_handle_t h, boolean_t enable); - -/* - * []------------------------------------------------------------------[] - * | Funtions for listing objects | - * | | - * | NOTE: Each of the following function have a specific free routine | - * | which must be called to free the data. | - * []------------------------------------------------------------------[] - */ -/* - * iscsit_list_find -- returns list of specific object names. - * - * There are three types of objects which are manipulated by these - * interfaces (Target, Initiator, and TPGT). This function will return - * an array of character strings which represent all of the available - * objects of the specific type. These strings are the same ones that - * where used during the creation. - * - * NOTE: Since there's no locking a call to this this function may - * return a name which then doesn't exist when the user attempts to - * get the specific information on that object. This would be caused - * when another operator deletes an object between the first and second - * calls. - */ -char **iscsit_list_find(iscsit_handle_t h, iscsit_obj_type_t t); -void iscsit_list_free(char **list); - -/* - * iscsit_list_target -- returns detailed information about a target - */ -iscsit_target_t *iscsit_list_target(iscsit_handle_t h, char *targ); -void iscsit_list_target_free(iscsit_target_t *t); - -/* - * iscsit_list_initiator -- returns detailed information about an initiator - */ -iscsit_initiator_t *iscsit_list_initiator(iscsit_handle_t h, char *initiator); -void iscsit_list_initiator_free(iscsit_initiator_t *t); - -/* - * iscsit_list_tpgt -- returns detailed information about a target port group - */ -iscsit_tpgt_t *iscsit_list_tpgt(iscsit_handle_t h, char *tpgt); -void iscsit_list_tpgt_free(iscsit_tpgt_t *t); - -/* - * iscsit_list_adm -- returns information about the global variables used. - */ -iscsit_admin_t *iscsit_list_adm(iscsit_handle_t h); -void iscsit_list_adm_free(iscsit_admin_t *t); - -/* - * Misc functions - */ -int iscsitgt_svc_online(); - -#ifdef __cplusplus -} -#endif - -#endif /* _LIBISCSITGT_H */ diff --git a/usr/src/lib/libiscsitgt/common/llib-liscsitgt b/usr/src/lib/libiscsitgt/common/llib-liscsitgt deleted file mode 100644 index 2b28fe63ff..0000000000 --- a/usr/src/lib/libiscsitgt/common/llib-liscsitgt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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 - */ -/*LINTLIBRARY*/ -/*PROTOLIB1*/ -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <libiscsitgt.h> diff --git a/usr/src/lib/libiscsitgt/common/mapfile-vers b/usr/src/lib/libiscsitgt/common/mapfile-vers deleted file mode 100644 index 792d56f156..0000000000 --- a/usr/src/lib/libiscsitgt/common/mapfile-vers +++ /dev/null @@ -1,72 +0,0 @@ -# -# 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. -# - -# -# MAPFILE HEADER START -# -# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. -# Object versioning must comply with the rules detailed in -# -# usr/src/lib/README.mapfiles -# -# You should not be making modifications here until you've read the most current -# copy of that file. If you need help, contact a gatekeeper for guidance. -# -# MAPFILE HEADER END -# - -SUNWprivate_1.1 { - global: - iscsitgt_svc_online; - iscsitgt_zfs_is_shared; - iscsitgt_zfs_share; - iscsitgt_zfs_unshare; - tgt_door_call; - tgt_node_free; - tgt_dump2buf; - tgt_node_process; - tgt_find_attr_str; - tgt_find_value_str; - tgt_find_value_int; - tgt_find_value_intchk; - tgt_find_value_boolean; - tgt_node_next; - tgt_node_next_child; - tgt_node_add; - tgt_node_add_attr; - tgt_node_alloc; - tgt_node_remove; - tgt_node_replace; - tgt_node_find; - tgt_node_dup; - tgt_xml_encode; - tgt_xml_decode; - tgt_update_value_str; - tgt_buf_add; - tgt_buf_add_tag; - tgt_buf_add_tag_and_attr; - local: - *; -}; diff --git a/usr/src/lib/libiscsitgt/common/xml.c b/usr/src/lib/libiscsitgt/common/xml.c deleted file mode 100644 index 3441bf2a42..0000000000 --- a/usr/src/lib/libiscsitgt/common/xml.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - * 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. - */ -#include <stdio.h> -#include <unistd.h> -#include <sys/types.h> -#include <inttypes.h> -#include <assert.h> -#include <libxml/xmlreader.h> -#include <strings.h> -#include <ctype.h> -#include <stdlib.h> -#include <syslog.h> -#include <sys/stat.h> - -#include "iscsitgt_impl.h" - -/* - * Forward declarations - */ -static char *strip_space(char *value); -static tgt_node_t *node_alloc(); -static void node_free(tgt_node_t *x); -static Boolean_t node_name(tgt_node_t *x, const xmlChar *n); -static Boolean_t node_value(tgt_node_t *x, const xmlChar *n, Boolean_t s); -static tgt_node_t *node_parent(tgt_node_t *x); -static tgt_node_t *node_child(tgt_node_t *x); -static tgt_node_t *node_alloc_attr(tgt_node_t *x); -static void buf_add_node_attr(char **b, tgt_node_t *x); -static void buf_add_comment(char **b, char *comment); -static void buf_add_str(char **b, char *str); - -#define XML_COMMENT_STR "!--" -#define XML_COMMENT_END "--" - -void -tgt_node_free(tgt_node_t *n) -{ - tgt_node_t *c; - tgt_node_t *c1; - - if (n == NULL) - return; - for (c = n->x_child; c; ) { - c1 = c->x_sibling; - tgt_node_free(c); - c = c1; - } - for (c = n->x_attr; c; ) { - c1 = c->x_sibling; - node_free(c); - c = c1; - } - node_free(n); - -} - -/* - * tgt_dump2buf -- dumps node tree to buffer, allocating memory as it goes - * - * It is up to the caller, when finished with 'buf', to call free() - */ -void -tgt_dump2buf(tgt_node_t *n, char **buf) -{ - tgt_node_t *c; - - if (n == NULL) - return; - if (strcmp(n->x_name, XML_COMMENT_STR) == 0) { - buf_add_comment(buf, n->x_value); - return; - } - buf_add_node_attr(buf, n); - if (n->x_value != NULL) - tgt_buf_add_tag(buf, n->x_value, Tag_String); - for (c = n->x_child; c; c = c->x_sibling) - tgt_dump2buf(c, buf); - tgt_buf_add_tag(buf, n->x_name, Tag_End); -} - -char *common_attr_list[] = { - XML_ELEMENT_NAME, - XML_ELEMENT_VERS, - XML_ELEMENT_INCORE, - 0 -}; - -Boolean_t -tgt_node_process(xmlTextReaderPtr r, tgt_node_t **node) -{ - const xmlChar *name; - const xmlChar *value; - char **ap; - xmlElementType node_type; - tgt_node_t *n; - tgt_node_t *an; - - n = *node; - if (n == NULL) { - n = node_alloc(); - if (n == NULL) - return (False); - *node = n; - } - - name = (xmlChar *)xmlTextReaderConstName(r); - if (name == NULL) { - node_free(n); - *node = NULL; - return (False); - } - - node_type = (xmlElementType)xmlTextReaderNodeType(r); - - value = (xmlChar *)xmlTextReaderConstValue(r); - - if (node_type == XML_ELEMENT_NODE) { - if (n->x_state != NodeAlloc) { - n = node_child(n); - *node = n; - if (n == NULL) - return (False); - } - if (xmlTextReaderAttributeCount(r) > 0) { - - for (ap = common_attr_list; *ap; ap++) { - value = xmlTextReaderGetAttribute(r, - (xmlChar *)*ap); - - if (value != NULL) { - if ((an = node_alloc_attr(n)) == NULL) - return (False); - if (node_name(an, (xmlChar *)*ap) == - False) { - node_free(an); - return (False); - } - if (node_value(an, value, True) == - False) { - node_free(an); - return (False); - } - free((char *)value); - } - } - } - - if (node_name(n, name) == False) { - node_free(n); - *node = NULL; - return (False); - } - } else if ((value != NULL) && (node_type == XML_TEXT_NODE)) { - if (node_value(n, value, True) == False) { - node_free(n); - *node = NULL; - return (False); - } - } else if (node_type == XML_ELEMENT_DECL) { - n = node_parent(n); - if (n == NULL) - return (False); - *node = n; - } else if (node_type == XML_COMMENT_NODE) { - n = node_child(n); - if (node_name(n, (xmlChar *)XML_COMMENT_STR) == False) { - node_free(n); - *node = NULL; - return (False); - } - if (node_value(n, (xmlChar *)value, False) == False) { - node_free(n); - *node = NULL; - return (False); - } - } else if (node_type != XML_DTD_NODE) { - node_free(n); - *node = NULL; - return (False); - } - return (True); -} - -Boolean_t -tgt_find_attr_str(tgt_node_t *n, char *attr, char **value) -{ - tgt_node_t *a; - - if ((n == NULL) || (n->x_attr == NULL)) - return (False); - - for (a = n->x_attr; a; a = a->x_sibling) - if (strcmp(a->x_name, attr) == 0) { - *value = a->x_value ? strdup(a->x_value) : NULL; - return (True); - } - return (False); -} - -Boolean_t -tgt_find_value_str(tgt_node_t *n, char *name, char **value) -{ - tgt_node_t *c; - - if ((n == NULL) || (n->x_name == NULL)) - return (False); - - if (strcmp(n->x_name, name) == 0) { - *value = n->x_value ? strdup(n->x_value) : NULL; - return (True); - } - for (c = n->x_child; c; c = c->x_sibling) { - if (tgt_find_value_str(c, name, value) == True) - return (True); - } - return (False); -} - -Boolean_t -tgt_find_value_int(tgt_node_t *n, char *name, int *value) -{ - tgt_node_t *c; - - if ((n == NULL) || (n->x_name == NULL)) - return (False); - - if (strcmp(n->x_name, name) == 0) { - if (n->x_value == NULL) - return (False); - *value = strtol(n->x_value, NULL, 0); - return (True); - } - for (c = n->x_child; c; c = c->x_sibling) { - if (tgt_find_value_int(c, name, value) == True) - return (True); - } - return (False); -} - -/* - * []---- - * | xml_find_value_intchk -- if node exists, check to see if value is okay - * []---- - */ -Boolean_t -tgt_find_value_intchk(tgt_node_t *n, char *name, int *value) -{ - char *str; - char chk[32]; - Boolean_t rval; - - if (tgt_find_value_str(n, name, &str) == True) { - - *value = strtol(str, NULL, 0); - /* - * Validate that the input string hasn't overrun what - * what an integer can handle. This is done by simply - * printing out the result of the conversion into a buffer - * and comparing it to the incoming string. That way when - * someone enters 4294967296 which strtol returns as 0 - * we'll catch it. - */ - if ((str[0] == '0') && (str[1] != '\0')) { - if (str[1] == 'x') - (void) snprintf(chk, sizeof (chk), "0x%x", - *value); - else if (str[1] == 'X') - (void) snprintf(chk, sizeof (chk), "0X%x", - *value); - else - (void) snprintf(chk, sizeof (chk), "0%o", - *value); - } else - (void) snprintf(chk, sizeof (chk), "%d", *value); - if (strcmp(chk, str) == 0) - rval = True; - else - rval = False; - free(str); - return (rval); - } else - return (True); -} - -Boolean_t -tgt_find_value_boolean(tgt_node_t *n, char *name, Boolean_t *value) -{ - tgt_node_t *c; - - if ((n == NULL) || (n->x_name == NULL)) - return (False); - - if (strcmp(n->x_name, name) == 0) { - if (n->x_value == NULL) - return (False); - *value = strcmp(n->x_value, "true") == 0 ? True : False; - return (True); - } - for (c = n->x_child; c; c = c->x_sibling) { - if (tgt_find_value_boolean(c, name, value) == True) - return (True); - } - return (False); -} - -tgt_node_t * -tgt_node_next(tgt_node_t *n, char *name, tgt_node_t *cur) -{ - tgt_node_t *x; - tgt_node_t *p; - - if (n == NULL) - return (NULL); - - if (cur != NULL) { - for (x = cur->x_sibling; x; x = x->x_sibling) - if (strcmp(x->x_name, name) == 0) - return (x); - return (NULL); - } - - if (n->x_name == NULL) - return (NULL); - - if (strcmp(n->x_name, name) == 0) - return (n); - for (x = n->x_child; x; x = x->x_sibling) - if ((p = tgt_node_next(x, name, 0)) != NULL) - return (p); - return (NULL); -} - -tgt_node_t * -tgt_node_next_child(tgt_node_t *n, char *name, tgt_node_t *cur) -{ - if (cur != NULL) { - n = cur->x_sibling; - } else { - if (n != NULL) - n = n->x_child; - else - return (NULL); - } - while (n) { - if (strcmp(n->x_name, name) == 0) - return (n); - n = n->x_sibling; - } - return (NULL); -} - -void -tgt_node_add(tgt_node_t *p, tgt_node_t *c) -{ - if ((p == NULL) || (c == NULL)) - return; - - c->x_parent = p; - if (p->x_child == NULL) - p->x_child = c; - else { - c->x_sibling = p->x_child; - p->x_child = c; - } -} - -void -tgt_node_add_attr(tgt_node_t *p, tgt_node_t *a) -{ - if ((p == NULL) || (a == NULL)) - return; - - if (p->x_attr == NULL) - p->x_attr = a; - else { - a->x_sibling = p->x_attr; - p->x_attr = a; - } -} - -tgt_node_t * -tgt_node_alloc(char *name, xml_val_type_t type, void *value) -{ - tgt_node_t *d = node_alloc(); - int value_len = 0; - char *value_str = NULL; - - if (d == NULL) - return (NULL); - switch (type) { - case String: - if (value) - value_len = strlen((char *)value) + 1; - break; - case Int: - value_len = sizeof (int) * 2 + 3; - break; - case Uint64: - value_len = sizeof (uint64_t) * 2 + 3; - break; - } - if (value_len && - (value_str = (char *)calloc(sizeof (char), value_len)) == NULL) - return (NULL); - if (node_name(d, (xmlChar *)name) == False) { - free(value_str); - return (NULL); - } - if (value_str) { - switch (type) { - case String: - (void) snprintf(value_str, value_len, "%s", - (char *)value); - break; - case Int: - (void) snprintf(value_str, value_len, "%d", - *(int *)value); - break; - case Uint64: - (void) snprintf(value_str, value_len, "0x%llx", - *(uint64_t *)value); - break; - } - } - (void) node_value(d, (xmlChar *)value_str, True); - free(value_str); - - return (d); -} - -Boolean_t -tgt_xml_encode(uint8_t *ip, size_t ip_size, char **buf, size_t *buf_size) -{ - char *bp; - *buf_size = (ip_size * 2) + 1; - - if ((*buf = (char *)malloc(*buf_size)) == NULL) { - *buf_size = 0; - return (False); - } - - for (bp = *buf; ip_size; ip_size--) { - (void) sprintf(bp, "%.2x", *ip); - ip++; - bp += 2; - } - - /* make it null terminated */ - *bp = 0; - - return (True); -} - -Boolean_t -tgt_xml_decode(char *buf, uint8_t **ip, size_t *ip_size) -{ - uint8_t *i; - size_t buf_size = strlen(buf); - *ip_size = buf_size / 2; - - if ((*ip = (uint8_t *)malloc(*ip_size)) == NULL) { - *ip_size = 0; - return (False); - } - - for (i = *ip; buf_size; buf_size -= 2) { - char x[3]; - bcopy(buf, x, 2); - x[2] = 0; - *i++ = strtol(x, NULL, 16); - buf += 2; - } - return (True); -} - -Boolean_t -tgt_node_remove(tgt_node_t *parent, tgt_node_t *child, match_type_t m) -{ - tgt_node_t *s; - tgt_node_t *c = NULL; - - if ((parent == NULL) || (child == NULL)) - return (False); - - for (s = parent->x_child; s; c = s, s = s->x_sibling) { - - /* - * See if the new child node matches one of the children - * in the parent. - */ - if ((strcmp(s->x_name, child->x_name) == 0) && - ((m == MatchName) || (strcmp(s->x_value, - child->x_value) == 0))) { - - if (parent->x_child == s) { - parent->x_child = s->x_sibling; - } else { - c->x_sibling = s->x_sibling; - } - tgt_node_free(s); - break; - } - } - if (s == NULL) - return (False); - else - return (True); -} - -void -tgt_node_replace(tgt_node_t *parent, tgt_node_t *child, match_type_t m) -{ - tgt_node_t *s; - tgt_node_t *c; - - if ((parent == NULL) || (child == NULL)) - return; - - for (s = parent->x_child; s; s = s->x_sibling) { - - /* - * See if the new child node matches one of the children - * in the parent. - */ - if ((strcmp(s->x_name, child->x_name) == 0) && - ((m == MatchName) || (strcmp(s->x_value, - child->x_value) == 0))) { - - /* - * We have a match. Now save the values of the new - * child in this current node. - */ - free(s->x_name); - free(s->x_value); - s->x_name = strdup(child->x_name); - s->x_value = strdup(child->x_value); - if (s->x_child) { - tgt_node_free(s->x_child); - s->x_child = NULL; - } - for (c = child->x_child; c; c = c->x_sibling) - (void) tgt_node_add(s, tgt_node_dup(c)); - break; - } - } - - if (s == NULL) { - /* - * Never found the child so add it - */ - (void) tgt_node_add(parent, tgt_node_dup(child)); - } -} - -Boolean_t -tgt_update_value_str(tgt_node_t *node, char *name, char *str) -{ - if ((node == NULL) || (strcmp(name, node->x_name) != 0)) - return (False); - if (node->x_value != NULL) - free(node->x_value); - node->x_value = strdup(str); - node->x_state = NodeValue; - return (True); -} - -tgt_node_t * -tgt_node_find(tgt_node_t *n, char *name) -{ - tgt_node_t *rval; - - for (rval = n->x_child; rval; rval = rval->x_sibling) - if (strcmp(rval->x_name, name) == 0) - break; - return (rval); -} - -tgt_node_t * -tgt_node_dup(tgt_node_t *n) -{ - tgt_node_t *d = node_alloc(); - tgt_node_t *c; - - if (d == NULL) - return (NULL); - if (node_name(d, (xmlChar *)n->x_name) == False) - return (NULL); - if (n->x_value && (node_value(d, (xmlChar *)n->x_value, True) == False)) - return (NULL); - for (c = n->x_child; c; c = c->x_sibling) - (void) tgt_node_add(d, tgt_node_dup(c)); - for (c = n->x_attr; c; c = c->x_sibling) - (void) tgt_node_add_attr(d, tgt_node_dup(c)); - return (d); -} - -#define MAX_REPLACEMENT_ENTITY 8 -#define MAX_REPLACEMENT_BUFFER 1024 -void -tgt_buf_add(char **b, char *element, const char *cdata) -{ - char entity[MAX_REPLACEMENT_ENTITY]; - char buf[MAX_REPLACEMENT_BUFFER]; - int len, i; - - bzero(buf, sizeof (buf)); - - tgt_buf_add_tag(b, element, Tag_Start); - /* - * we have to transform the predefined xml entities; - */ - if (cdata != NULL) { - len = strlen(cdata); - for (i = 0; i < len; i++) { - switch (cdata[i]) { - case '&': - (void) strcpy(entity, "&"); - break; - case '<': - (void) strcpy(entity, "<"); - break; - case '>': - (void) strcpy(entity, ">"); - break; - case '\'': - (void) strcpy(entity, "'"); - break; - case '"': - (void) strcpy(entity, """); - break; - default: - entity[0] = cdata[i]; - entity[1] = '\0'; - break; - } - (void) strlcat(buf, entity, sizeof (buf)); - } - tgt_buf_add_tag(b, buf, Tag_String); - } - tgt_buf_add_tag(b, element, Tag_End); -} - -/* - * []---- - * | tgt_buf_add_tag -- adds string to buffer allocating space, sets up tags too - * | - * | Helper function to build a string by allocating memory as we go. - * | If the string argument 'str' is defined to be a start or end tag - * | as declared by 'type' argument add the appropriate characters. - * []---- - */ -void -tgt_buf_add_tag(char **b, const char *str, val_type_t type) -{ - char *buf; - int len; - - /* - * We will add potentially up to 3 extra characters plus the NULL byte - */ - len = strlen(str) + 4; - if ((buf = malloc(len)) == NULL) - return; - - (void) snprintf(buf, len, "%s%s%s%s", type == Tag_String ? "" : "<", - type == Tag_End ? "/" : "", str, type == Tag_String ? "" : ">"); - buf_add_str(b, buf); - free(buf); -} - -/* - * []---- - * | tgt_buf_add_tag_and_attr -- variant on tgt_buf_add_tag which also gives - * | attr - * []---- - */ -void -tgt_buf_add_tag_and_attr(char **b, char *str, char *attr) -{ - char *buf; - int len; - - /* - * In addition to the 'str' and 'attr' strings the code will add - * three characters plus a null byte. - */ - len = strlen(str) + strlen(attr) + 4; - if ((buf = malloc(len)) == NULL) - return; - - (void) snprintf(buf, len, "<%s %s>", str, attr); - buf_add_str(b, buf); - free(buf); -} - -/* - * []---- - * | Utility functions - * []---- - */ -static tgt_node_t * -node_alloc() -{ - tgt_node_t *x = (tgt_node_t *)calloc(sizeof (tgt_node_t), 1); - - if (x == NULL) - return (NULL); - - x->x_state = NodeAlloc; - return (x); -} - -static void -node_free(tgt_node_t *x) -{ - x->x_state = NodeFree; - if (x->x_name) - free(x->x_name); - if (x->x_value) - free(x->x_value); - free(x); -} - -static Boolean_t -node_name(tgt_node_t *x, const xmlChar *n) -{ - assert(x->x_state == NodeAlloc); - if ((n == NULL) || (strlen((char *)n) == 0)) - return (False); - - x->x_state = NodeName; - x->x_name = strip_space((char *)n); - return (True); -} - -static Boolean_t -node_value(tgt_node_t *x, const xmlChar *n, Boolean_t do_strip) -{ - assert(x->x_state == NodeName); - if ((n == NULL) || (strlen((char *)n) == NULL)) - return (False); - - x->x_state = NodeValue; - x->x_value = (do_strip == True) ? - strip_space((char *)n) : strdup((char *)n); - return (True); -} - -static tgt_node_t * -node_parent(tgt_node_t *x) -{ - return (x->x_parent); -} - -static tgt_node_t * -node_child(tgt_node_t *x) -{ - tgt_node_t *n; - - if ((n = node_alloc()) == NULL) - return (NULL); - - if (x->x_child == NULL) { - x->x_child = n; - } else { - n->x_sibling = x->x_child; - x->x_child = n; - } - n->x_parent = x; - return (n); -} - -static tgt_node_t * -node_alloc_attr(tgt_node_t *x) -{ - tgt_node_t *n; - tgt_node_t *next; - - n = node_alloc(); - if (x->x_attr == NULL) { - x->x_attr = n; - } else { - for (next = x->x_attr; next->x_sibling; next = next->x_sibling) - ; - next->x_sibling = n; - } - if (n != NULL) - n->x_parent = x; - return (n); -} - -static void -buf_add_str(char **b, char *str) -{ - int len; - int olen = 0; - char *p = *b; - - /* - * Make sure we have enough room for the string and tag characters - * plus a NULL byte. - */ - if (str == NULL) - return; - - len = strlen(str) + 1; - if (p == NULL) { - if ((p = malloc(len)) == NULL) - return; - } else { - olen = strlen(p); - p = realloc(p, olen + len); - } - (void) strncpy(p + olen, str, len); - *b = p; -} - -static void -buf_add_node_attr(char **b, tgt_node_t *x) -{ - char *buf; - tgt_node_t *n; - int len; - - /* ---- null byte and starting '<' character ---- */ - len = strlen(x->x_name) + 2; - if ((buf = malloc(len)) == NULL) - return; - (void) snprintf(buf, len, "<%s", x->x_name); - buf_add_str(b, buf); - free(buf); - - for (n = x->x_attr; n; n = n->x_sibling) { - len = strlen(n->x_name) + strlen(n->x_value) + 5; - if ((buf = malloc(len)) == NULL) - return; - (void) snprintf(buf, len, " %s='%s'", n->x_name, n->x_value); - buf_add_str(b, buf); - free(buf); - } - buf_add_str(b, ">"); -} - -static void -buf_add_comment(char **b, char *comment) -{ - char *p = *b; - int len; - int olen; - - if (comment == NULL) - return; - - /* - * Room for the strings, plus the brackets and NULL byte - */ - len = strlen(comment) + strlen(XML_COMMENT_STR) + - strlen(XML_COMMENT_END) + 3; - - if (p == NULL) - p = malloc(len); - else { - olen = strlen(p); - p = realloc(p, olen + len); - } - (void) snprintf(p + olen, len, "<%s%s%s>", XML_COMMENT_STR, comment, - XML_COMMENT_END); - *b = p; -} - -static char * -strip_space(char *value) -{ - char *p; - char *n; - - for (p = value; p && *p; p++) - if (!isspace(*p)) - break; - if ((p == NULL) || (*p == '\0')) - return (NULL); - - p = strdup(p); - for (n = (p + strlen(p) - 1); n >= p; n--) - if (!isspace(*n)) { - n++; - break; - } - *n = '\0'; - return (p); -} diff --git a/usr/src/lib/libiscsitgt/i386/Makefile b/usr/src/lib/libiscsitgt/i386/Makefile deleted file mode 100644 index a333224278..0000000000 --- a/usr/src/lib/libiscsitgt/i386/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.com - -install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libiscsitgt/sparc/Makefile b/usr/src/lib/libiscsitgt/sparc/Makefile deleted file mode 100644 index a333224278..0000000000 --- a/usr/src/lib/libiscsitgt/sparc/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.com - -install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libiscsitgt/sparcv9/Makefile b/usr/src/lib/libiscsitgt/sparcv9/Makefile deleted file mode 100644 index 2e8cdecf75..0000000000 --- a/usr/src/lib/libiscsitgt/sparcv9/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" -# - -include ../Makefile.com -include ../../Makefile.lib.64 - -install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt index 84dee31da3..0a10c10a11 100644 --- a/usr/src/lib/libsecdb/auth_attr.txt +++ b/usr/src/lib/libsecdb/auth_attr.txt @@ -201,11 +201,7 @@ solaris.system.power.cpu:::Manage CPU related power::help=SysCpuPowerMgmt.html solaris.system.sysevent.read:::Retrieve Sysevents::help=SysSyseventRead.html solaris.system.sysevent.write:::Publish Sysevents::help=SysSyseventWrite.html # -solaris.smf.manage.iscsitgt:::Manage ISCSI Target Service States::help=SmfValueIscsitgt.html -solaris.smf.read.iscsitgt:::Read ISCSI Target secrets::help=SmfValueIscsitgt.html -solaris.smf.modify.iscsitgt:::Add/Remove Values of ISCSI Target Service Properties::help=SmfValueIscsitgt.html solaris.smf.modify.stmf:::Modify STMF Properties::help=SmfSTMFValue.html -solaris.smf.value.iscsitgt:::Change Values of ISCSI Target Service Properties::help=SmfValueIscsitgt.html # solaris.smf.manage.mms:::Manage MMS Service States::help=SmfManageMMS.html solaris.smf.value.mms:::Change Values of MMS Service Properties::help=SmfValueMMS.html diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt index c660d44510..d6258a1e2c 100644 --- a/usr/src/lib/libsecdb/exec_attr.txt +++ b/usr/src/lib/libsecdb/exec_attr.txt @@ -90,7 +90,6 @@ File System Management:suser:cmd:::/usr/sbin/fsdb:euid=0 File System Management:suser:cmd:::/usr/sbin/fstyp:euid=0 File System Management:suser:cmd:::/usr/sbin/fuser:euid=0 File System Management:solaris:cmd:::/usr/sbin/iscsiadm:euid=0;privs=basic -File System Management:solaris:cmd:::/usr/sbin/iscsitadm:euid=0;privs=basic File System Management:suser:cmd:::/usr/sbin/mkfile:euid=0 File System Management:suser:cmd:::/usr/sbin/mkfs:euid=0 File System Management:suser:cmd:::/usr/sbin/mount:uid=0 diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile index b56ddefdd6..cb9361c94e 100644 --- a/usr/src/lib/libsecdb/help/auths/Makefile +++ b/usr/src/lib/libsecdb/help/auths/Makefile @@ -106,7 +106,6 @@ HTMLENTS = \ SmfValueHeader.html \ SmfValueInetd.html \ SmfValueIPsec.html \ - SmfValueIscsitgt.html \ SmfValueMDNS.html \ SmfValueNADD.html \ SmfValueNDMP.html \ diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt index 28d0107d29..a8d5fc56b6 100644 --- a/usr/src/lib/libsecdb/prof_attr.txt +++ b/usr/src/lib/libsecdb/prof_attr.txt @@ -110,8 +110,6 @@ WUSB Management:::Manage Wireless USB:auths=solaris.admin.wusb.*,solaris.smf.man Information Security:::Maintains MAC and DAC security policies:profiles=Device Security,File System Security,Name Service Security,Network Security,Object Access Management,Object Label Management;help=RtInfoSec.html Object Label Management:::Change labels on files.:auths=solaris.device.allocate,solaris.label.file.downgrade,solaris.label.win.downgrade,solaris.label.win.upgrade,solaris.label.file.upgrade,solaris.label.range,solaris.smf.manage.labels;help=RtObjectLabelMngmnt.html Outside Accred:::Allow a user to operate outside the user accreditation range.:auths=solaris.label.range;help=RtOutsideAccred.html -ISCSI Target Administration:::Configure ISCSI Target service:auths=solaris.smf.modify.iscsitgt,solaris.smf.read.iscsitgt,solaris.smf.value.iscsitgt -ISCSI Target Management:::Start/Stop ISCSI Target service:auths=solaris.smf.manage.iscsitgt # # Power Management profiles: # diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index b3123ad38a..7a8d3d769a 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -93,8 +93,6 @@ enum { EZFS_INVALCONFIG, /* invalid vdev configuration */ EZFS_RECURSIVE, /* recursive dependency */ EZFS_NOHISTORY, /* no history object */ - EZFS_UNSHAREISCSIFAILED, /* iscsitgtd failed request to unshare */ - EZFS_SHAREISCSIFAILED, /* iscsitgtd failed request to share */ EZFS_POOLPROPS, /* couldn't retrieve pool props */ EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */ EZFS_POOL_INVALARG, /* invalid argument for this pool operation */ @@ -102,7 +100,6 @@ enum { EZFS_OPENFAILED, /* open of device failed */ EZFS_NOCAP, /* couldn't get capacity */ EZFS_LABELFAILED, /* write of label failed */ - EZFS_ISCSISVCUNAVAIL, /* iscsi service unavailable */ EZFS_BADWHO, /* invalid permission who */ EZFS_BADPERM, /* invalid permission */ EZFS_BADPERMSET, /* invalid permission set name */ @@ -621,10 +618,6 @@ extern int zfs_unshareall_nfs(zfs_handle_t *); extern int zfs_unshareall_smb(zfs_handle_t *); extern int zfs_unshareall_bypath(zfs_handle_t *, const char *); extern int zfs_unshareall(zfs_handle_t *); -extern boolean_t zfs_is_shared_iscsi(zfs_handle_t *); -extern int zfs_share_iscsi(zfs_handle_t *); -extern int zfs_unshare_iscsi(zfs_handle_t *); -extern int zfs_iscsi_perm_check(libzfs_handle_t *, char *, ucred_t *); extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *, void *, void *, int, zfs_share_op_t); diff --git a/usr/src/lib/libzfs/common/libzfs_changelist.c b/usr/src/lib/libzfs/common/libzfs_changelist.c index c970d1e488..4328d38a2c 100644 --- a/usr/src/lib/libzfs/common/libzfs_changelist.c +++ b/usr/src/lib/libzfs/common/libzfs_changelist.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Portions Copyright 2007 Ramprakash Jelari @@ -116,22 +116,7 @@ changelist_prefix(prop_changelist_t *clp) if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned) continue; - if (ZFS_IS_VOLUME(cn->cn_handle)) { - switch (clp->cl_realprop) { - case ZFS_PROP_NAME: - /* If this was a rename, unshare the zvol */ - (void) zfs_unshare_iscsi(cn->cn_handle); - break; - - case ZFS_PROP_VOLSIZE: - /* - * If this was a change to the volume size, we - * need to unshare and reshare the volume. - */ - (void) zfs_unshare_iscsi(cn->cn_handle); - break; - } - } else { + if (!ZFS_IS_VOLUME(cn->cn_handle)) { /* * Do the property specific processing. */ @@ -224,24 +209,8 @@ changelist_postfix(prop_changelist_t *clp) zfs_refresh_properties(cn->cn_handle); - if (ZFS_IS_VOLUME(cn->cn_handle)) { - if (cn->cn_shared || - clp->cl_prop == ZFS_PROP_SHAREISCSI) { - if (zfs_prop_get(cn->cn_handle, - ZFS_PROP_SHAREISCSI, shareopts, - sizeof (shareopts), NULL, NULL, 0, - B_FALSE) == 0 && - strcmp(shareopts, "off") == 0) { - errors += - zfs_unshare_iscsi(cn->cn_handle); - } else { - errors += - zfs_share_iscsi(cn->cn_handle); - } - } - + if (ZFS_IS_VOLUME(cn->cn_handle)) continue; - } /* * Remount if previously mounted or mountpoint was legacy, @@ -640,8 +609,7 @@ changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags, if (clp->cl_prop != ZFS_PROP_MOUNTPOINT && clp->cl_prop != ZFS_PROP_SHARENFS && - clp->cl_prop != ZFS_PROP_SHARESMB && - clp->cl_prop != ZFS_PROP_SHAREISCSI) + clp->cl_prop != ZFS_PROP_SHARESMB) return (clp); /* diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index e9725e96b4..773e05896a 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -938,19 +938,6 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl, } break; - case ZFS_PROP_SHAREISCSI: - if (strcmp(strval, "off") != 0 && - strcmp(strval, "on") != 0 && - strcmp(strval, "type=disk") != 0) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "'%s' must be 'on', 'off', or 'type=disk'"), - propname); - (void) zfs_error(hdl, EZFS_BADPROP, errbuf); - goto error; - } - - break; - case ZFS_PROP_MLSLABEL: { /* @@ -1318,6 +1305,14 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err, } break; + case EINVAL: + if (prop == ZPROP_INVAL) { + (void) zfs_error(hdl, EZFS_BADPROP, errbuf); + } else { + (void) zfs_standard_error(hdl, err, errbuf); + } + break; + case EOVERFLOW: /* * This platform can't address a volume this big. @@ -2936,15 +2931,6 @@ zfs_destroy(zfs_handle_t *zhp, boolean_t defer) (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (ZFS_IS_VOLUME(zhp)) { - /* - * If user doesn't have permissions to unshare volume, then - * abort the request. This would only happen for a - * non-privileged user. - */ - if (zfs_unshare_iscsi(zhp) != 0) { - return (-1); - } - zc.zc_objset_type = DMU_OST_ZVOL; } else { zc.zc_objset_type = DMU_OST_ZFS; @@ -3740,52 +3726,6 @@ zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received) } int -zfs_iscsi_perm_check(libzfs_handle_t *hdl, char *dataset, ucred_t *cred) -{ - zfs_cmd_t zc = { 0 }; - nvlist_t *nvp; - gid_t gid; - uid_t uid; - const gid_t *groups; - int group_cnt; - int error; - - if (nvlist_alloc(&nvp, NV_UNIQUE_NAME, 0) != 0) - return (no_memory(hdl)); - - uid = ucred_geteuid(cred); - gid = ucred_getegid(cred); - group_cnt = ucred_getgroups(cred, &groups); - - if (uid == (uid_t)-1 || gid == (uid_t)-1 || group_cnt == (uid_t)-1) - return (1); - - if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_UID, uid) != 0) { - nvlist_free(nvp); - return (1); - } - - if (nvlist_add_uint32(nvp, ZFS_DELEG_PERM_GID, gid) != 0) { - nvlist_free(nvp); - return (1); - } - - if (nvlist_add_uint32_array(nvp, - ZFS_DELEG_PERM_GROUPS, (uint32_t *)groups, group_cnt) != 0) { - nvlist_free(nvp); - return (1); - } - (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); - - if (zcmd_write_src_nvlist(hdl, &zc, nvp)) - return (-1); - - error = ioctl(hdl->libzfs_fd, ZFS_IOC_ISCSI_PERM_CHECK, &zc); - nvlist_free(nvp); - return (error); -} - -int zfs_deleg_share_nfs(libzfs_handle_t *hdl, char *dataset, char *path, char *resource, void *export, void *sharetab, int sharemax, zfs_share_op_t operation) diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h index ef34591fe3..fabd454de8 100644 --- a/usr/src/lib/libzfs/common/libzfs_impl.h +++ b/usr/src/lib/libzfs/common/libzfs_impl.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -128,7 +128,6 @@ typedef enum { */ typedef enum { SHARED_NOT_SHARED = 0x0, - SHARED_ISCSI = 0x1, SHARED_NFS = 0x2, SHARED_SMB = 0x4 } zfs_share_type_t; diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c index 8392fc9fb1..c225ad562a 100644 --- a/usr/src/lib/libzfs/common/libzfs_mount.c +++ b/usr/src/lib/libzfs/common/libzfs_mount.c @@ -44,17 +44,14 @@ * * zfs_is_shared_nfs() * zfs_is_shared_smb() - * zfs_is_shared_iscsi() * zfs_share_proto() * zfs_shareall(); - * zfs_share_iscsi() * zfs_unshare_nfs() * zfs_unshare_smb() * zfs_unshareall_nfs() * zfs_unshareall_smb() * zfs_unshareall() * zfs_unshareall_bypath() - * zfs_unshare_iscsi() * * The following functions are available for pool consumers, and will * mount/unmount and share/unshare all datasets within pool: @@ -89,11 +86,6 @@ static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, zfs_share_proto_t); -static int (*iscsitgt_zfs_share)(const char *); -static int (*iscsitgt_zfs_unshare)(const char *); -static int (*iscsitgt_zfs_is_shared)(const char *); -static int (*iscsitgt_svc_online)(); - /* * The share protocols table must be in the same order as the zfs_share_prot_t * enum in libzfs_impl.h @@ -125,29 +117,6 @@ zfs_share_proto_t share_all_proto[] = { PROTO_END }; -#pragma init(zfs_iscsi_init) -static void -zfs_iscsi_init(void) -{ - void *libiscsitgt; - - if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", - RTLD_LAZY | RTLD_GLOBAL)) == NULL || - (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_zfs_share")) == NULL || - (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_zfs_unshare")) == NULL || - (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_zfs_is_shared")) == NULL || - (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, - "iscsitgt_svc_online")) == NULL) { - iscsitgt_zfs_share = NULL; - iscsitgt_zfs_unshare = NULL; - iscsitgt_zfs_is_shared = NULL; - iscsitgt_svc_online = NULL; - } -} - /* * Search the sharetab for the given mountpoint and protocol, returning * a zfs_share_type_t value. @@ -455,7 +424,7 @@ zfs_is_shared(zfs_handle_t *zhp) zfs_share_proto_t *curr_proto; if (ZFS_IS_VOLUME(zhp)) - return (zfs_is_shared_iscsi(zhp)); + return (B_FALSE); for (curr_proto = share_all_proto; *curr_proto != PROTO_END; curr_proto++) @@ -468,7 +437,7 @@ int zfs_share(zfs_handle_t *zhp) { if (ZFS_IS_VOLUME(zhp)) - return (zfs_share_iscsi(zhp)); + return (0); return (zfs_share_proto(zhp, share_all_proto)); } @@ -477,7 +446,7 @@ int zfs_unshare(zfs_handle_t *zhp) { if (ZFS_IS_VOLUME(zhp)) - return (zfs_unshare_iscsi(zhp)); + return (0); return (zfs_unshareall(zhp)); } @@ -1009,81 +978,6 @@ remove_mountpoint(zfs_handle_t *zhp) } } -boolean_t -zfs_is_shared_iscsi(zfs_handle_t *zhp) -{ - - /* - * If iscsi deamon isn't running then we aren't shared - */ - if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) - return (B_FALSE); - else - return (iscsitgt_zfs_is_shared != NULL && - iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); -} - -int -zfs_share_iscsi(zfs_handle_t *zhp) -{ - char shareopts[ZFS_MAXPROPLEN]; - const char *dataset = zhp->zfs_name; - libzfs_handle_t *hdl = zhp->zfs_hdl; - - /* - * Return success if there are no share options. - */ - if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, - sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || - strcmp(shareopts, "off") == 0) - return (0); - - if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { - int error = EZFS_SHAREISCSIFAILED; - - /* - * If service isn't availabele and EPERM was - * returned then use special error. - */ - if (iscsitgt_svc_online && errno == EPERM && - (iscsitgt_svc_online() != 0)) - error = EZFS_ISCSISVCUNAVAIL; - - return (zfs_error_fmt(hdl, error, - dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); - } - - return (0); -} - -int -zfs_unshare_iscsi(zfs_handle_t *zhp) -{ - const char *dataset = zfs_get_name(zhp); - libzfs_handle_t *hdl = zhp->zfs_hdl; - - /* - * Return if the volume is not shared - */ - if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) - return (0); - - /* - * If this fails with ENODEV it indicates that zvol wasn't shared so - * we should return success in that case. - */ - if (iscsitgt_zfs_unshare == NULL || - (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { - if (errno == EPERM) - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "Insufficient privileges to unshare iscsi")); - return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, - dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); - } - - return (0); -} - typedef struct mount_cbdata { zfs_handle_t **cb_datasets; int cb_used; @@ -1225,21 +1119,6 @@ out: return (ret); } -/*ARGSUSED1*/ -static int -zvol_cb(zfs_handle_t *zhp, void *unused) -{ - int error = 0; - - if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) - (void) zfs_iter_children(zhp, zvol_cb, NULL); - if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) - error = zfs_unshare_iscsi(zhp); - zfs_close(zhp); - - return (error); -} - static int mountpoint_compare(const void *a, const void *b) { @@ -1265,23 +1144,12 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) struct mnttab entry; size_t namelen; char **mountpoints = NULL; - zfs_handle_t *zfp; zfs_handle_t **datasets = NULL; libzfs_handle_t *hdl = zhp->zpool_hdl; int i; int ret = -1; int flags = (force ? MS_FORCE : 0); - /* - * First unshare all zvols. - */ - zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, - ZFS_TYPE_FILESYSTEM); - if (zfp != NULL) { - (void) zfs_iter_children(zfp, zvol_cb, NULL); - zfs_close(zfp); - } - namelen = strlen(zhp->zpool_name); rewind(hdl->libzfs_mnttab); diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c index 09a1631925..98b56ff79a 100644 --- a/usr/src/lib/libzfs/common/libzfs_util.c +++ b/usr/src/lib/libzfs/common/libzfs_util.c @@ -136,10 +136,6 @@ libzfs_error_description(libzfs_handle_t *hdl) return (dgettext(TEXT_DOMAIN, "smb remove share failed")); case EZFS_SHARESMBFAILED: return (dgettext(TEXT_DOMAIN, "smb add share failed")); - case EZFS_ISCSISVCUNAVAIL: - return (dgettext(TEXT_DOMAIN, - "iscsitgt service need to be enabled by " - "a privileged user")); case EZFS_PERM: return (dgettext(TEXT_DOMAIN, "permission denied")); case EZFS_NOSPC: @@ -159,12 +155,6 @@ libzfs_error_description(libzfs_handle_t *hdl) return (dgettext(TEXT_DOMAIN, "recursive dataset dependency")); case EZFS_NOHISTORY: return (dgettext(TEXT_DOMAIN, "no history available")); - case EZFS_UNSHAREISCSIFAILED: - return (dgettext(TEXT_DOMAIN, - "iscsitgtd failed request to unshare")); - case EZFS_SHAREISCSIFAILED: - return (dgettext(TEXT_DOMAIN, - "iscsitgtd failed request to share")); case EZFS_POOLPROPS: return (dgettext(TEXT_DOMAIN, "failed to retrieve " "pool properties")); diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers index 4e2eeb38fa..672129e017 100644 --- a/usr/src/lib/libzfs/common/mapfile-vers +++ b/usr/src/lib/libzfs/common/mapfile-vers @@ -75,10 +75,8 @@ SUNWprivate_1.1 { zfs_get_type; zfs_hold; zfs_hold_range; - zfs_iscsi_perm_check; zfs_is_mounted; zfs_is_shared; - zfs_is_shared_iscsi; zfs_is_shared_nfs; zfs_is_shared_smb; zfs_iter_children; @@ -130,7 +128,6 @@ SUNWprivate_1.1 { zfs_shareall; zfs_share_nfs; zfs_share_smb; - zfs_share_iscsi; zfs_smb_acl_add; zfs_smb_acl_purge; zfs_smb_acl_remove; @@ -141,7 +138,6 @@ SUNWprivate_1.1 { zfs_unmount; zfs_unmountall; zfs_unshare; - zfs_unshare_iscsi; zfs_unshare_nfs; zfs_unshare_smb; zfs_unshareall; diff --git a/usr/src/pkg/manifests/SUNWcs.mf b/usr/src/pkg/manifests/SUNWcs.mf index 5ad00495da..004d8894b8 100644 --- a/usr/src/pkg/manifests/SUNWcs.mf +++ b/usr/src/pkg/manifests/SUNWcs.mf @@ -992,7 +992,6 @@ file path=usr/lib/help/auths/locale/C/SmfValueHeader.html file path=usr/lib/help/auths/locale/C/SmfValueIPsec.html file path=usr/lib/help/auths/locale/C/SmfValueIdmap.html file path=usr/lib/help/auths/locale/C/SmfValueInetd.html -file path=usr/lib/help/auths/locale/C/SmfValueIscsitgt.html file path=usr/lib/help/auths/locale/C/SmfValueMDNS.html file path=usr/lib/help/auths/locale/C/SmfValueMMS.html file path=usr/lib/help/auths/locale/C/SmfValueNADD.html diff --git a/usr/src/pkg/manifests/SUNWiscsitgt.mf b/usr/src/pkg/manifests/SUNWiscsitgt.mf deleted file mode 100644 index 5b41ebafbd..0000000000 --- a/usr/src/pkg/manifests/SUNWiscsitgt.mf +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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. -# - -set name=pkg.fmri value=pkg:/SUNWiscsitgt@0.5.11,5.11-0.133 -set name=pkg.renamed value=true -set name=variant.arch value=$(ARCH) -set name=variant.opensolaris.zone value=global value=nonglobal -depend fmri=pkg:/network/iscsi/target/legacy@0.5.11,5.11-0.133 type=require diff --git a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf index b3dc1bd736..fc19087040 100644 --- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf +++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf @@ -194,7 +194,6 @@ file path=usr/lib/help/auths/locale/SmfValueHeader.html file path=usr/lib/help/auths/locale/SmfValueIPsec.html file path=usr/lib/help/auths/locale/SmfValueIdmap.html file path=usr/lib/help/auths/locale/SmfValueInetd.html -file path=usr/lib/help/auths/locale/SmfValueIscsitgt.html file path=usr/lib/help/auths/locale/SmfValueMDNS.html file path=usr/lib/help/auths/locale/SmfValueMMS.html file path=usr/lib/help/auths/locale/SmfValueNADD.html diff --git a/usr/src/pkg/manifests/network-iscsi-target-legacy.mf b/usr/src/pkg/manifests/network-iscsi-target-legacy.mf deleted file mode 100644 index 78055778a6..0000000000 --- a/usr/src/pkg/manifests/network-iscsi-target-legacy.mf +++ /dev/null @@ -1,77 +0,0 @@ -# -# 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. -# - -# -# This package will install successfully into any zone, global or -# non-global. The files, directories, links, and hardlinks, however, -# will only be installed into the global zone. -# -<include hollow_zone_pkg> -set name=pkg.fmri value=pkg:/network/iscsi/target/legacy@$(PKGVERS) -set name=pkg.description value="Sun iSCSI Target" -set name=pkg.summary value="Sun iSCSI Target" -set name=info.classification value=org.opensolaris.category.2008:System/Hardware -set name=variant.arch value=$(ARCH) -set name=variant.opensolaris.zone value=global value=nonglobal -dir path=etc group=sys -dir path=etc/iscsi group=sys -dir path=lib -dir path=lib/$(ARCH64) -dir path=lib/svc -dir path=lib/svc/method -dir path=usr group=sys -dir path=usr/lib -dir path=usr/lib/$(ARCH64) -dir path=usr/lib/dtrace -dir path=usr/sbin -$(i386_ONLY)dir path=usr/sbin/$(ARCH32) -dir path=usr/sbin/$(ARCH64) -dir path=var group=sys -dir path=var/svc group=sys -dir path=var/svc/manifest group=sys -dir path=var/svc/manifest/system group=sys -file path=lib/$(ARCH64)/libiscsitgt.so.1 -file path=lib/libiscsitgt.so.1 -file path=lib/svc/method/svc-iscsitgt mode=0555 -file path=usr/lib/dtrace/iscsi.d -$(i386_ONLY)file path=usr/sbin/$(ARCH32)/iscsitgtd mode=0555 -file path=usr/sbin/$(ARCH64)/iscsitgtd mode=0555 -file path=usr/sbin/iscsitadm mode=0555 -file path=var/svc/manifest/system/iscsi_target.xml group=sys mode=0444 -hardlink path=usr/sbin/iscsitgtd target=../../usr/lib/isaexec -legacy pkg=SUNWiscsitgtr arch=$(ARCH) category=system desc="Sun iSCSI Target" \ - hotline="Please contact your local service provider" \ - name="Sun iSCSI Target (Root)" vendor="Sun Microsystems, Inc." \ - version=11.11,REV=2009.11.11 -legacy pkg=SUNWiscsitgtu arch=$(ARCH) category=system desc="Sun iSCSI Target" \ - hotline="Please contact your local service provider" \ - name="Sun iSCSI Target (Usr)" vendor="Sun Microsystems, Inc." \ - version=11.11,REV=2009.11.11 -license cr_Sun license=cr_Sun -license lic_CDDL license=lic_CDDL -link path=usr/lib/$(ARCH64)/libiscsitgt.so.1 \ - target=../../../lib/$(ARCH64)/libiscsitgt.so.1 -link path=usr/lib/libiscsitgt.so.1 target=../../lib/libiscsitgt.so.1 diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh index ae53e733c5..4b0aecc8d1 100644 --- a/usr/src/tools/scripts/bfu.sh +++ b/usr/src/tools/scripts/bfu.sh @@ -1532,6 +1532,7 @@ smf_obsolete_manifests=" var/svc/manifest/network/iscsi_initiator.xml var/svc/manifest/network/fcoe_config.xml var/svc/manifest/network/rpc/ocfserv.xml + var/svc/manifest/system/iscsi_target.xml " # smf services whose manifests have been renamed @@ -1555,6 +1556,7 @@ smf_obsolete_methods=" lib/svc/share/krb_include.sh lib/svc/method/iscsid lib/svc/method/fcoeconfig + lib/svc/method/svc-iscsitgt " smf_cleanup () { @@ -4076,6 +4078,59 @@ SUNWocfr SUNWpamsc SUNWscmhdlr' printf 'done.\n' } +# +# Remove iSCSI Target Daemon +# +remove_eof_iscsitgtd() +{ + # Packages to remove + typeset -r iscsitgtd_pkgs='SUNWiscsitgtu SUNWiscsitgtr' + typeset pkg + + printf 'Removing iSCSI Target Daemon... ' + + # + # First, attempt to remove the packages cleanly if possible. + # + for pkg in $iscsitgtd_pkgs + do + if pkginfo $pkgroot -q $pkg; then + printf ' %s' $pkg + pkgrm $pkgroot -n $pkg >/dev/null 2>&1 + fi + done + printf '\n' + + # + # In case that didn't work, do it manually. + # Remove iSCSI Target Daemon from $rootprefix/var/sadm/install/contents + # + for pkg in $iscsitgtd_pkgs + do + if [ -d $rootprefix/var/sadm/pkg/$pkg ]; then + rm -rf $rootprefix/var/sadm/pkg/$pkg + grep -vw $pkg $rootprefix/var/sadm/install/contents > \ + /tmp/contents.$$ + cp /tmp/contents.$$ $rootprefix/var/sadm/install/contents.$$ + rm /tmp/contents.$$ + fi + done + + # + # Cleanup if any remaining files, symlinks, and directories. + # + rm -f $usr/sbin/iscsitadm + rm -f $usr/sbin/amd64/iscsitgtd + rm -f $usr/sbin/i86/iscsitgtd + rm -f $usr/sbin/sparv9/iscsitgtd + rm -f $usr/sbin/iscsitgtd + rm -f $usr/lib/dtrace/iscsi.d + rm -f $usr/lib/amd64/libiscsitgt.so.1 + rm -f $usr/lib/sparcv9/libiscsitgt.so.1 + rm -f $usr/lib/libiscsitgt.so.1 + rm -f $usr/svc/method/svc-iscsitgt +} + remove_properties() { # @@ -6843,6 +6898,13 @@ mondo_loop() { fi # + # Remove obsolete iSCSI Target Daemon software + # + if [ -f $usr/sbin/iscsitadm ]; then + remove_eof_iscsitgtd + fi + + # # Remove SUNWcoff package # pkg=SUNWcoff diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 8375d2aa94..e06fcff58f 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -625,16 +625,6 @@ zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, cred_t *cr) return (error); } -/* - * Must have sys_config privilege to check the iscsi permission - */ -/* ARGSUSED */ -static int -zfs_secpolicy_iscsi(zfs_cmd_t *zc, cred_t *cr) -{ - return (secpolicy_zfs(cr)); -} - int zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) { @@ -2423,53 +2413,6 @@ zfs_ioc_pool_get_props(zfs_cmd_t *zc) return (error); } -static int -zfs_ioc_iscsi_perm_check(zfs_cmd_t *zc) -{ - nvlist_t *nvp; - int error; - uint32_t uid; - uint32_t gid; - uint32_t *groups; - uint_t group_cnt; - cred_t *usercred; - - if ((error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size, - zc->zc_iflags, &nvp)) != 0) { - return (error); - } - - if ((error = nvlist_lookup_uint32(nvp, - ZFS_DELEG_PERM_UID, &uid)) != 0) { - nvlist_free(nvp); - return (EPERM); - } - - if ((error = nvlist_lookup_uint32(nvp, - ZFS_DELEG_PERM_GID, &gid)) != 0) { - nvlist_free(nvp); - return (EPERM); - } - - if ((error = nvlist_lookup_uint32_array(nvp, ZFS_DELEG_PERM_GROUPS, - &groups, &group_cnt)) != 0) { - nvlist_free(nvp); - return (EPERM); - } - usercred = cralloc(); - if ((crsetugid(usercred, uid, gid) != 0) || - (crsetgroups(usercred, group_cnt, (gid_t *)groups) != 0)) { - nvlist_free(nvp); - crfree(usercred); - return (EPERM); - } - nvlist_free(nvp); - error = dsl_deleg_access(zc->zc_name, - zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred); - crfree(usercred); - return (error); -} - /* * inputs: * zc_name name of filesystem @@ -4358,8 +4301,6 @@ static zfs_ioc_vec_t zfs_ioc_vec[] = { B_TRUE }, { zfs_ioc_get_fsacl, zfs_secpolicy_read, DATASET_NAME, B_FALSE, B_FALSE }, - { zfs_ioc_iscsi_perm_check, zfs_secpolicy_iscsi, DATASET_NAME, B_FALSE, - B_FALSE }, { zfs_ioc_share, zfs_secpolicy_share, DATASET_NAME, B_FALSE, B_FALSE }, { zfs_ioc_inherit_prop, zfs_secpolicy_inherit, DATASET_NAME, B_TRUE, B_TRUE }, diff --git a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c index ba0ca1aa50..e68a50291d 100644 --- a/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c +++ b/usr/src/uts/common/io/comstar/port/iscsit/iscsit.c @@ -2888,8 +2888,7 @@ iscsit_config_merge(it_config_t *in_cfg) * Compare serial numbers using serial number arithmetic as defined in * RFC 1982. * - * NOTE: This code is duplicated in the isns server as well as iscsitgtd. It - * ought to be common. + * NOTE: This code is duplicated in the isns server. It ought to be common. */ static int diff --git a/usr/src/uts/common/sys/fs/zfs.h b/usr/src/uts/common/sys/fs/zfs.h index e986759a2d..6538ac1ca9 100644 --- a/usr/src/uts/common/sys/fs/zfs.h +++ b/usr/src/uts/common/sys/fs/zfs.h @@ -91,7 +91,6 @@ typedef enum { ZFS_PROP_CREATETXG, /* not exposed to the user */ ZFS_PROP_NAME, /* not exposed to the user */ ZFS_PROP_CANMOUNT, - ZFS_PROP_SHAREISCSI, ZFS_PROP_ISCSIOPTIONS, /* not exposed to the user */ ZFS_PROP_XATTR, ZFS_PROP_NUMCLONES, /* not exposed to the user */ @@ -707,7 +706,6 @@ typedef enum zfs_ioc { ZFS_IOC_POOL_GET_PROPS, ZFS_IOC_SET_FSACL, ZFS_IOC_GET_FSACL, - ZFS_IOC_ISCSI_PERM_CHECK, ZFS_IOC_SHARE, ZFS_IOC_INHERIT_PROP, ZFS_IOC_SMB_ACL, |