changeset 4348:f06efcce7faa

PSARC 2007/175 iSCSI Target iSNS 6415430 iSCSI target needs iSNS client support
author ts143224
date Tue, 29 May 2007 17:13:54 -0700
parents 65fb0c27d51e
children 53be14f175bd
files usr/src/cmd/iscsi/iscsitadm/main.c usr/src/cmd/iscsi/iscsitgtd/Makefile usr/src/cmd/iscsi/iscsitgtd/Makefile.com usr/src/cmd/iscsi/iscsitgtd/errcode.h usr/src/cmd/iscsi/iscsitgtd/iscsi_login.c usr/src/cmd/iscsi/iscsitgtd/isns.c usr/src/cmd/iscsi/iscsitgtd/isns_client.c usr/src/cmd/iscsi/iscsitgtd/isns_client.h usr/src/cmd/iscsi/iscsitgtd/isns_protocol.h usr/src/cmd/iscsi/iscsitgtd/main.c usr/src/cmd/iscsi/iscsitgtd/mgmt_create.c usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c usr/src/cmd/iscsi/iscsitgtd/mgmt_remove.c usr/src/cmd/iscsi/iscsitgtd/queue.h usr/src/cmd/iscsi/iscsitgtd/target.h usr/src/cmd/iscsi/iscsitgtd/util.c usr/src/cmd/iscsi/iscsitgtd/util_err.c usr/src/lib/libiscsitgt/common/iscsitgt_impl.h
diffstat 18 files changed, 3002 insertions(+), 267 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/iscsi/iscsitadm/main.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitadm/main.c	Tue May 29 17:13:54 2007 -0700
@@ -122,6 +122,7 @@
 	{"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"},
@@ -220,7 +221,7 @@
 	{TPGT, MODIFY, "i", B_TRUE, NULL},
 	{TPGT, DELETE, "Ai", B_TRUE, NULL},
 	{TPGT, LIST,   "v", B_FALSE, NULL},
-	{ADMIN, MODIFY, "dHCRrPSf", B_TRUE, NULL},
+	{ADMIN, MODIFY, "dHCRrPSsf", B_TRUE, NULL},
 	{STATS, SHOW, "vIN", B_FALSE, NULL},
 };
 
@@ -359,8 +360,8 @@
 static int
 formatErrString(tgt_node_t *node)
 {
-	int	code	= 0,
-		rtn	= 0;
+	int	code	= 0;
+	int	rtn	= 0;
 	char	*msg	= NULL;
 
 	if (node == NULL) {
@@ -679,9 +680,9 @@
 	char		*first_str	= NULL;
 	tgt_node_t	*node;
 	cmdOptions_t	*optionList	= options;
-	char		chapSecret[MAX_CHAP_SECRET_LEN],
-			olddir[MAXPATHLEN],
-			newdir[MAXPATHLEN];
+	char		chapSecret[MAX_CHAP_SECRET_LEN];
+	char		olddir[MAXPATHLEN];
+	char		newdir[MAXPATHLEN];
 	int		secretLen	= 0;
 	int		ret		= 0;
 
@@ -743,19 +744,19 @@
 				break;
 			case 'R': /* radius access */
 				if (strcmp(optionList->optarg,
-					OPT_ENABLE) == 0) {
+				    OPT_ENABLE) == 0) {
 					tgt_buf_add(&first_str,
 					    XML_ELEMENT_RAD_ACCESS, OPT_TRUE);
 				} else
 					if (strcmp(optionList->optarg,
-						OPT_DISABLE) == 0) {
+					    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"));
+					    "enable/disable"));
 					free(first_str);
 					return (1);
 				}
@@ -782,38 +783,42 @@
 				break;
 			case 'S': /* iSNS access */
 				if (strcmp(optionList->optarg,
-					OPT_ENABLE) == 0) {
+				    OPT_ENABLE) == 0) {
 					tgt_buf_add(&first_str,
 					    XML_ELEMENT_ISNS_ACCESS, OPT_TRUE);
 				} else
 					if (strcmp(optionList->optarg,
-						OPT_DISABLE) == 0) {
+					    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"));
+					    "enable/disable"));
 					free(first_str);
 					return (1);
 				}
 				break;
+			case 's': /* iSNS server */
+				tgt_buf_add(&first_str, XML_ELEMENT_ISNS_SERV,
+				    optionList->optarg);
+				break;
 			case 'f': /* fast write back */
 				if (strcmp(optionList->optarg,
-					OPT_ENABLE) == 0) {
+				    OPT_ENABLE) == 0) {
 					tgt_buf_add(&first_str,
 					    XML_ELEMENT_FAST, OPT_TRUE);
 				} else
 					if (strcmp(optionList->optarg,
-						OPT_DISABLE) == 0) {
+					    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"));
+					    "enable/disable"));
 					free(first_str);
 					return (1);
 				}
@@ -1119,8 +1124,8 @@
 				(void) printf("%s%s: %s\n", dospace(3),
 				    gettext("Size"),
 				    number_to_scaled_string(buf,
-					strtoll(n4->x_value,
-					NULL, 0), 512, 1024));
+				    strtoll(n4->x_value,
+				    NULL, 0), 512, 1024));
 			} else {
 				(void) printf("%s%s: %s\n", dospace(3),
 				    gettext("Size"), gettext("unknown"));
@@ -1168,7 +1173,7 @@
 		case 'v':
 			verbose = True;
 			tgt_buf_add(&first_str,
-				    XML_ELEMENT_VERBOSE, OPT_TRUE);
+			    XML_ELEMENT_VERBOSE, OPT_TRUE);
 			break;
 
 		default:
@@ -1247,7 +1252,7 @@
 		case 'v':
 			verbose = True;
 			tgt_buf_add(&first_str,
-				    XML_ELEMENT_VERBOSE, OPT_TRUE);
+			    XML_ELEMENT_VERBOSE, OPT_TRUE);
 			break;
 		default:
 			(void) fprintf(stderr, "%s: %c: %s\n",
@@ -1376,6 +1381,10 @@
 	} 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_FAST, NULL);
 	(void) printf("%s%s: ", dospace(1), gettext("Fast Write ACK"));
 	if (n2) {
@@ -1392,15 +1401,13 @@
 static int
 showStats(int operandLen, char *operand[], cmdOptions_t *options)
 {
-	char		*first_str	= NULL,
-			scale_buf[16];
-	tgt_node_t	*node,
-			*n1;
-	int		interval	= -1,
-			count		= -1,
-			header;
-	stat_delta_t	cur_data,
-			*pd;
+	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);
--- a/usr/src/cmd/iscsi/iscsitgtd/Makefile	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/Makefile	Tue May 29 17:13:54 2007 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -32,6 +32,7 @@
 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	+= util.o util_err.o util_ifname.o util_port.o util_queue.o
+OBJS	+= isns_client.o isns.o
 POFILE= iscsitgtd.po
 POFILES	= $(OBJS:%.o=%.po)
 
--- a/usr/src/cmd/iscsi/iscsitgtd/Makefile.com	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/Makefile.com	Tue May 29 17:13:54 2007 -0700
@@ -32,6 +32,7 @@
 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	+= util.o util_err.o util_ifname.o util_port.o util_queue.o
+OBJS	+= isns_client.o isns.o
 SRCS=	$(OBJS:%.o=../%.c) $(COMMON_SRCS)
 
 include ../../../Makefile.cmd
--- a/usr/src/cmd/iscsi/iscsitgtd/errcode.h	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/errcode.h	Tue May 29 17:13:54 2007 -0700
@@ -107,7 +107,10 @@
 	ERR_TAPE_NOT_SUPPORTED_IN_32BIT,
 	ERR_INTERNAL_ERROR,
 	ERR_BAD_CREDS,
-	ERR_NO_PERMISSION
+	ERR_NO_PERMISSION,
+	ERR_INVALID_ISNS_SRV,
+	ERR_ISNS_ERROR,
+	ERR_TPGT_NO_IPADDR
 } err_code_t;
 
 char *
--- a/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/iscsi_login.c	Tue May 29 17:13:54 2007 -0700
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <syslog.h>
 #include <sys/iscsi_protocol.h>
 #include <iscsitgt_impl.h>
 #include "queue.h"
@@ -39,6 +40,7 @@
 #include "iscsi_login.h"
 #include "utility.h"
 #include "target.h"
+#include "isns_client.h"
 
 typedef enum auth_action {
 	LOGIN_NO_AUTH,
@@ -132,16 +134,16 @@
 	iscsi_login_rsp_hdr_t	*rsp		= NULL;
 	Boolean_t		rval		= False;
 	IscsiAuthClient		*auth_client	= NULL;
-	char			*text		= NULL,
-				*end		= NULL,
-				*text_rsp	= NULL,
-				debug[128];
-	int			debug_status	= 0,
-				errcode		= 0,
-				text_length	= 0,
-				keytype		= 0,
-				transit		= 0,
-				rc		= 0;
+	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;
 
@@ -220,7 +222,7 @@
 
 	auth_client =
 	    (c->c_sess->sess_auth.auth_buffers &&
-		c->c_sess->sess_auth.num_auth_buffers) ?
+	    c->c_sess->sess_auth.num_auth_buffers) ?
 	    (IscsiAuthClient *) c->c_sess->sess_auth.auth_buffers[0].address :
 	    NULL;
 
@@ -305,7 +307,7 @@
 		}
 
 		if (iscsiAuthClientRecvTransitBit(auth_client,
-			transit) != iscsiAuthStatusNoError) {
+		    transit) != iscsiAuthStatusNoError) {
 			(void) snprintf(debug, sizeof (debug),
 			    "iscsi connection(%u) login failed - "
 			    "authentication transmit failed", c->c_num);
@@ -340,13 +342,13 @@
 				    (char *)iscsiAuthClientGetKeyName(keytype);
 				if ((key) &&
 				    (iscsi_find_key_value(key, text, end,
-					&value, &value_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)
+					    auth_client, keytype, value)
 					    != iscsiAuthStatusNoError) {
 						(void) snprintf(debug,
 						    sizeof (debug),
@@ -396,11 +398,9 @@
 			    &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);
+			    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) |
@@ -603,7 +603,7 @@
 
 		if ((lh.flags & ISCSI_FLAG_LOGIN_TRANSIT) &&
 		    (ISCSI_LOGIN_NEXT_STAGE(lh.flags) ==
-			ISCSI_FULL_FEATURE_PHASE)) {
+		    ISCSI_FULL_FEATURE_PHASE)) {
 
 			conn_state(c, T5);
 
@@ -718,7 +718,7 @@
 		    &szIniAlias);
 
 		if (tgt_find_value_str(xnInitiator, XML_ELEMENT_INAME,
-			&szIscsiName) == True) {
+		    &szIscsiName) == True) {
 
 			comp = strcmp(s->s_i_name, szIscsiName);
 			free(szIscsiName);
@@ -727,8 +727,8 @@
 			if (comp == 0) {
 
 				if (tgt_find_value_str(xnInitiator,
-					XML_ELEMENT_CHAPNAME,
-					&szChapName) == True) {
+				    XML_ELEMENT_CHAPNAME,
+				    &szChapName) == True) {
 					/*CSTYLED*/
 					(void) strcpy((char *)sess_auth->username_in,
 					    szChapName);
@@ -736,8 +736,8 @@
 				}
 
 				if (tgt_find_value_str(xnInitiator,
-					XML_ELEMENT_CHAPSECRET,
-					&szChapSecret) == True) {
+				    XML_ELEMENT_CHAPSECRET,
+				    &szChapSecret) == True) {
 					/*CSTYLED*/
 					(void) strcpy((char *)sess_auth->password_in,
 					    szChapSecret);
@@ -762,6 +762,15 @@
 	}
 
 	/*
+	 * If iSNS enabled set LOGIN_AUTH
+	 */
+	if (isns_enabled() == True) {
+		if (sess_auth->password_length_in == 0)
+			return (LOGIN_NO_AUTH);
+		return (LOGIN_AUTH);
+	}
+
+	/*
 	 * If no acc_list for current target, transit.
 	 * If acc_list exists for the target, and
 	 * If the initiator not in the list, drop it.
@@ -785,7 +794,7 @@
 		if (comp == 0) {
 
 			if ((xnAcl = tgt_node_next(xnTarget,
-				XML_ELEMENT_ACLLIST, 0)) == NULL) {
+			    XML_ELEMENT_ACLLIST, 0)) == NULL) {
 				/*
 				 * No acl_list found, return True for no auth
 				 */
@@ -799,7 +808,7 @@
 			 */
 			xnInitiator = NULL;
 			while ((xnInitiator = tgt_node_next(xnAcl,
-				    XML_ELEMENT_INIT, xnInitiator)) != NULL) {
+			    XML_ELEMENT_INIT, xnInitiator)) != NULL) {
 
 				if ((tgt_find_value_str(xnInitiator,
 				    XML_ELEMENT_INIT, &possible) == False) ||
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns.c	Tue May 29 17:13:54 2007 -0700
@@ -0,0 +1,573 @@
+/*
+ * 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"
+
+#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 <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;
+
+	pthread_mutex_lock(&xid_lock);
+	tmp = xid++;
+	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));
+					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;
+				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;
+
+	if (server == NULL) {
+		syslog(LOG_ERR, "ISNS server ID required");
+		return (-1);
+	}
+
+	bzero(&hints, sizeof (struct addrinfo));
+	hints.ai_family = AF_UNSPEC;
+	if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
+		syslog(LOG_ALERT, "ISNS server %s not found", server);
+		return (-1);
+	}
+
+	aip = ai;
+	do {
+		so = socket(aip->ai_family, SOCK_STREAM, 0);
+		if (so != -1) {
+			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:
+					continue;
+			}
+			while (((ret = connect(so, sa, sa_len)) == -1) &&
+			    (errno == EINTR))
+				;
+			if (ret == 0) {
+				freeaddrinfo(ai);
+				return (so);
+			} else {
+				syslog(LOG_ALERT, "Connect failed");
+				close(so);
+			}
+		}
+	} while ((aip = aip->ai_next) != NULL);
+
+	if (ai != NULL)
+		freeaddrinfo(ai);
+	return (-1);
+}
+
+void
+isns_close(int so)
+{
+	if (so) {
+		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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns_client.c	Tue May 29 17:13:54 2007 -0700
@@ -0,0 +1,1630 @@
+/*
+ * 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"
+
+#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;
+static	ip_t	eid_ip;
+static	int	num_reg = 0;
+static	pthread_t	scn_tid = 0;
+static	Boolean_t	isns_shutdown = False;
+
+Boolean_t	isns_initialized = False;
+sema_t		isns_sema;
+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 **);
+
+/*
+ * 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(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(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	*ip	= NULL;
+	tgt_node_t	*tpgt	= NULL;
+	ip_t		eid;
+
+	/* Always add the default TPGT (1) */
+	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(main_config,
+			    XML_ELEMENT_TPGT, tpgt)) != NULL) {
+				if (strcmp(pgt->x_value, tpgt->x_value) != 0)
+					continue;
+				if ((ip = tgt_node_next(tpgt,
+				    XML_ELEMENT_IPADDR, NULL)) != NULL)
+					break;
+			}
+			if (tpgt == NULL || ip == 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 = tpgt->x_child; x; x = x->x_sibling) {
+				get_ip_addr(x->x_value, &eid);
+				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	len = scn->payload_len;
+	uint32_t	done = 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", len);
+
+	if (len < TAG_LEN_SZ) {
+		syslog(LOG_ALERT, "ISNS SCN message error\n");
+		return;
+	}
+
+	while (done == 0) {
+		/* 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;
+			case ISNS_DELIMITER_ATTR_ID:
+				queue_prt(mgmtq, Q_ISNS_DBG,
+				    "PROCESS_SCN DELIMIT\n");
+				done = 1;
+				break;
+			default:
+				queue_prt(mgmtq, Q_ISNS_DBG,
+				    "PROCESS_SCN DEFAULT\n");
+				break;
+		}
+
+		if (done)
+			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");
+					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 */
+		len -= 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);
+}
+
+/*
+ * 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;
+	socklen_t		len;
+	char			strport[NI_MAXSERV];
+	int	pf;
+	esi_scn_arg_t		*args = (esi_scn_arg_t *)arg;
+	isns_pdu_t		*scn = NULL;
+
+	/*
+	 * open isns server connect and determine which PF_INET
+	 * to use
+	 */
+	if ((so = isns_open(args->server)) < 0) {
+		syslog(LOG_ERR,
+		    "esi_scn_thr: isns server %s not found", args->server);
+		return (NULL);
+	}
+	len = sizeof (sa);
+	if (getsockname(so, &sa, &len) < 0) {
+		isns_close(so);
+		syslog(LOG_ALERT, "getsockname failed");
+		return (NULL);
+	}
+	pf = sa.sa_family;
+	isns_close(so);
+
+	if (pf != PF_INET && pf != PF_INET6) {
+		syslog(LOG_ERR, "esi_scn_thr: unknown domain type");
+		return (NULL);
+	}
+
+	/*
+	 * create and bind SCN socket
+	 * save the scn port info
+	 */
+	if ((so = socket(pf, SOCK_STREAM, 0)) == -1) {
+		syslog(LOG_ALERT, "socket failed");
+		return (NULL);
+	}
+
+	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 {
+		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);
+	}
+
+	(void) setsockopt(so, SOL_SOCKET, SO_REUSEADDR, 0, 0);
+
+	if (bind(so, ai, len) < 0) {
+		syslog(LOG_ALERT, "esi_scn_thr: bind failed");
+		return (NULL);
+	}
+
+	/* get scn port info */
+	len = sizeof (sa);
+	if (getsockname(so, &sa, &len) < 0) {
+		syslog(LOG_ALERT, "getsockname failed");
+		return (NULL);
+	}
+	if (getnameinfo(&sa, len, NULL, 0, strport, NI_MAXSERV,
+	    NI_NUMERICSERV) != 0) {
+		syslog(LOG_ALERT, "getnameinfo failed");
+		return (NULL);
+	}
+	scn_port = atoi(strport);
+
+	sema_post(&isns_sema);
+
+	if (listen(so, 5) < 0) {
+		syslog(LOG_ALERT, "esi_scn_thr: failed listen");
+		return (NULL);
+	}
+
+	/* listen for esi or scn messages */
+	while (isns_shutdown == False) {
+		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 ");
+		}
+
+		close(fd);
+	}
+	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 ((so = isns_open(isns_args.server)) == -1) {
+		syslog(LOG_ERR, "isns_reg failed");
+		return (-1);
+	}
+
+	while ((tgt = tgt_node_next(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);
+}
+
+/*
+ * 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)
+{
+	char		*isns_srv, *isns_port;
+
+	if (q != NULL)
+		mgmtq = q;
+
+	if (isns_enabled() == False)
+		return (0);
+
+	/* initialize */
+	sema_init(&isns_sema, 0, USYNC_THREAD, NULL);
+
+	/* get isns server info */
+	tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, &isns_srv);
+	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';
+	}
+	bcopy(isns_srv, isns_args.server, MAXHOSTNAMELEN);
+	free(isns_srv);
+
+	/* 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 fails to get ENTITY properties");
+		return (-1);
+	}
+
+	if (pthread_create(&scn_tid, NULL, esi_scn_thr, (void *)&isns_args) !=
+	    0) {
+		syslog(LOG_ALERT, "isns_init failed to pthread_create");
+		return (-1);
+	}
+
+	if (sema_wait(&isns_sema) != 0) {
+		syslog(LOG_ERR, "sema_wait error\n");
+	}
+
+	isns_initialized = True;
+
+	/*
+	 * 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");
+			isns_op_all(ISNS_DEV_DEREG);
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * isns_update gets call on modify_admin, this is changes to
+ * isns access and/or isns server
+ */
+int
+isns_update()
+{
+	char	*isns_srv = NULL, *isns_port;
+
+	if (isns_initialized == False) {
+		/* isns enabled after iscsi started */
+		if (isns_enabled() == True) {
+			isns_init(NULL);
+		}
+		return (0);
+	}
+
+	/*
+	 * isns is disabled after enabled,
+	 * log off all targets and fini isns service
+	 */
+	if (isns_initialized == True && isns_enabled() == False) {
+		isns_fini();
+		return (0);
+	}
+
+	/*
+	 * isns is already initialized and isns_access is still enabled,
+	 * let's update the isns_server name
+	 */
+	tgt_find_value_str(main_config, XML_ELEMENT_ISNS_SERV, &isns_srv);
+	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 (strcmp(isns_srv, isns_args.server) != 0) {
+		/* de-reg from old iSNS server */
+		(void) isns_dereg_all();
+	}
+
+	bcopy(isns_srv, isns_args.server, MAXHOSTNAMELEN);
+	free(isns_srv);
+
+	if (isns_reg_all() == 0) {
+		/* scn register all targets */
+		if (isns_op_all(ISNS_SCN_REG) != 0) {
+			syslog(LOG_ERR, "SCN registrations failed\n");
+			isns_op_all(ISNS_DEV_DEREG);
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * isns_fini is called when isns access is disable
+ */
+void
+isns_fini()
+{
+	/*
+	 * de-register all targets 1st, this prevents initiator from
+	 * logging back in
+	 */
+	isns_op_all(ISNS_SCN_DEREG);
+	isns_op_all(ISNS_DEV_DEREG);
+
+	/* log off all targets */
+	isns_op_all(ISNS_TGT_LOGOUT);
+}
+
+static int
+get_ip_addr(char *node, ip_t *sa)
+{
+	struct addrinfo		*ai, *aip;
+	struct sockaddr_in	*sin;
+	struct sockaddr_in6	*sin6;
+
+	if (getaddrinfo(node, NULL, NULL, &ai) != 0) {
+		syslog(LOG_ALERT, "ISNS server not found");
+		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);
+				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);
+				return (0);
+			default:
+				continue;
+		}
+	} while ((aip = aip->ai_next) != NULL);
+
+	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 */
+	/* EID */
+	if (isns_append_attr(cmd, ISNS_EID_ATTR_ID,
+	    STRLEN(isns_args.entity), isns_args.entity, 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) {
+		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);
+				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;
+
+	if ((so = isns_open(isns_args.server)) == -1) {
+		syslog(LOG_ERR, "isns_reg failed");
+		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);
+		}
+		if (isns_scn_reg(so, iqn) == -1) {
+			syslog(LOG_ERR, "ISNS SCN register failed\n");
+		}
+		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;
+	isns_rsp_t	*rsp;
+	char		*n = NULL;
+	char		*a = NULL;
+	char		alias[MAXNAMELEN];
+	char		iname[MAXNAMELEN];
+	tgt_node_t	*tgt = NULL;
+	int		ret = -1;
+	int		tgt_cnt = 0;
+
+	/*
+	 * get the 1st target and use it for the source attribute
+	 */
+	if ((tgt = tgt_node_next(targets_config, XML_ELEMENT_TARG, tgt))
+	    == NULL) {
+		syslog(LOG_ALERT, "ISNS: no iscsi target found\n");
+		return (-1);
+	}
+	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);
+	}
+	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(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 */
+		strcpy(alias, tgt->x_value);
+
+		if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
+		    == FALSE) {
+			continue;
+		}
+		strcpy(iname, n);
+		free(n);
+
+		/* find alias */
+		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a)
+		    == TRUE) {
+			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 ((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 ((tgt = find_tgt_by_name(targ, &iname)) != NULL) {
+		if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &dummy) ==
+		    True) {
+			strcpy(alias, dummy);
+			free(dummy);
+		} else
+			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
+		 */
+		isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname),
+		    iname, 0);
+		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 ((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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns_client.h	Tue May 29 17:13:54 2007 -0700
@@ -0,0 +1,167 @@
+/*
+ * 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_CLIENT_H
+#define	_ISNS_CLIENT_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#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];	/* iscsi target entity */
+	char		server[MAXHOSTNAMELEN];	/* 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 *);
+
+#endif	/* _ISNS_CLIENT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns_protocol.h	Tue May 29 17:13:54 2007 -0700
@@ -0,0 +1,200 @@
+
+/*
+ * 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 */
--- a/usr/src/cmd/iscsi/iscsitgtd/main.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/main.c	Tue May 29 17:13:54 2007 -0700
@@ -68,6 +68,8 @@
 #include "errcode.h"
 #include "t10.h"
 
+#include "isns_client.h"
+
 #define	EMPTY_CONFIG "<config version='1.0'>\n</config>\n"
 
 /* ---- Forward declarations ---- */
@@ -116,6 +118,7 @@
 	{XML_ELEMENT_RAD_SERV,		valid_radius_srv},
 	{XML_ELEMENT_RAD_SECRET,	0},
 	{XML_ELEMENT_ISNS_ACCESS,	0},
+	{XML_ELEMENT_ISNS_SERV,		valid_isns_srv},
 	{XML_ELEMENT_FAST,		0},
 	{0,				0}
 };
@@ -153,11 +156,11 @@
 process_target_config()
 {
 	xmlTextReaderPtr	r			= NULL;
-	char			path[MAXPATHLEN],
-				*target			= NULL;
+	char			path[MAXPATHLEN];
+	char			*target			= NULL;
 	struct stat		ss;
-	tgt_node_t		*node			= NULL,
-				*next			= NULL;
+	tgt_node_t		*node			= NULL;
+	tgt_node_t		*next			= NULL;
 	int			xml_fd			= -1;
 
 	if (target_basedir != NULL) {
@@ -300,8 +303,8 @@
 process_config(char *file)
 {
 	xmlTextReaderPtr	r;
-	int			ret,
-				xml_fd		= -1;
+	int			ret;
+	int			xml_fd		= -1;
 	tgt_node_t		*node = NULL;
 
 #ifndef lint
@@ -403,8 +406,7 @@
 static void *
 logout_cleanup(void *v)
 {
-	int		msg_sent,
-			i;
+	int		msg_sent, i;
 	char		*targ = (char *)v;
 	mgmt_request_t	m;
 	iscsi_conn_t	*conn;
@@ -446,8 +448,7 @@
 {
 	mgmt_request_t	m;
 	iscsi_conn_t	*conn;
-	int		i,
-			msg_sent;
+	int		i, msg_sent;
 	pthread_t	junk;
 	extern pthread_mutex_t	port_mutex;
 
@@ -690,8 +691,7 @@
 static void
 setup_door(target_queue_t *q, char *door_name)
 {
-	int		did,
-			fd;
+	int		did, fd;
 	struct stat	s;
 	door_arg_t	d;
 	char		*msg = NULL;
@@ -810,16 +810,13 @@
 int
 main(int argc, char **argv)
 {
-	char			c,
-				*p,
-				*door_name;
+	char			c, *p, *door_name;
 	msg_t			*msg;
 	target_queue_t		*q;
-	port_args_t		port1,
-				port2;
-	Boolean_t		mgmt_up		= False,
-				daemonize	= True,
-				console_output	= True;
+	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;
@@ -971,6 +968,7 @@
 	port_init();
 	queue_init();
 	util_init();
+	isns_init(q);
 
 	/*
 	 * If there's no MAC address currently available don't worry about
--- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_create.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/mgmt_create.c	Tue May 29 17:13:54 2007 -0700
@@ -54,6 +54,7 @@
 #include "utility.h"
 #include "errcode.h"
 #include "t10_spc.h"
+#include "isns_client.h"
 
 extern char *getfullrawname();
 
@@ -86,8 +87,8 @@
     ucred_t *cred)
 {
 	tgt_node_t	*x;
-	char		msgbuf[80],
-			*reply_msg	= NULL;
+	char		msgbuf[80];
+	char		*reply_msg	= NULL;
 
 	if (p->x_child == NULL) {
 		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
@@ -120,19 +121,17 @@
 static char *
 create_target(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*name		= NULL,
-			*alias		= NULL,
-			*size		= NULL,
-			*type		= NULL,
-			*backing	= NULL,
-			*node_name	= NULL,
-			path[MAXPATHLEN];
-	int		lun		= 0, /* default to LUN 0 */
-			i;
-	tgt_node_t	*n,
-			*c,
-			*l;
+	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;
 	const priv_set_t	*eset;
 
@@ -270,6 +269,14 @@
 		if (update_config_targets(&msg) == False)
 			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)) {
 
 		/*
@@ -308,12 +315,11 @@
 static char *
 create_initiator(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*name		= NULL,
-			*iscsi_name	= NULL;
-	tgt_node_t	*inode		= NULL,
-			*n,
-			*c;
+	char		*msg		= NULL;
+	char		*name		= NULL;
+	char		*iscsi_name	= NULL;
+	tgt_node_t	*inode		= NULL;
+	tgt_node_t	*n, *c;
 	const priv_set_t	*eset;
 
 	eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
@@ -364,11 +370,11 @@
 static char *
 create_tpgt(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg	= NULL,
-			*tpgt	= NULL,
-			*extra	 = NULL;
-	tgt_node_t	*tnode	= NULL,
-			*n;
+	char		*msg	= NULL;
+	char		*tpgt	= NULL;
+	char		*extra	 = NULL;
+	tgt_node_t	*tnode	= NULL;
+	tgt_node_t	*n;
 	int		tpgt_val;
 	const priv_set_t	*eset;
 
@@ -422,20 +428,20 @@
 static char *
 create_zfs(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*dataset	= NULL,
-			*node_name	= NULL,
-			*prop		= NULL,
-			path[MAXPATHLEN],
-			*cp,	/* current pair */
-			*np,	/* next pair */
-			*vp;	/* value pointer */
-	tgt_node_t	*dnode		= NULL,
-			*n,
-			*c,
-			*attr,
-			*ll,
-			*l;
+	char		*msg		= NULL;
+	char		*dataset	= NULL;
+	char		*node_name	= NULL;
+	char		*prop		= NULL;
+	char		path[MAXPATHLEN];
+	char		*cp;	/* current pair */
+	char		*np;	/* next pair */
+	char		*vp;	/* value pointer */
+	tgt_node_t	*dnode		= NULL;
+	tgt_node_t	*n;
+	tgt_node_t	*c;
+	tgt_node_t	*attr;
+	tgt_node_t	*ll;
+	tgt_node_t	*l;
 	libzfs_handle_t	*zh		= NULL;
 	zfs_handle_t	*zfsh		= NULL;
 	uint64_t	size;
@@ -583,6 +589,7 @@
 
 		c = tgt_node_alloc(XML_ELEMENT_INAME, String, node_name);
 		tgt_node_add(n, c);
+		free(node_name);
 
 		c = tgt_node_alloc(XML_ELEMENT_LUNLIST, String, "");
 		tgt_node_add(n, c);
@@ -636,6 +643,16 @@
 
 	tgt_node_add(targets_config, n);
 
+	/* register with iSNS */
+	node_name = NULL;
+	if (isns_enabled() == True) {
+		(void) tgt_find_value_str(n, XML_ELEMENT_INAME, &node_name);
+		if (isns_reg(node_name) != 0) {
+			xml_rtn_msg(&msg, ERR_ISNS_ERROR);
+			goto error;
+		}
+	}
+
 	xml_rtn_msg(&msg, ERR_SUCCESS);
 error:
 	if (zfsh)
@@ -666,9 +683,9 @@
 create_node_name(char *local_nick, char *alias)
 {
 	uuid_t	id;
-	char	id_str[37],
-		*p,
-		*anp;		/* alias or nick pointer */
+	char	id_str[37];
+	char	*p;
+	char	*anp;		/* alias or nick pointer */
 
 	if ((p = (char *)malloc(ISCSI_MAX_NAME_LEN)) == NULL)
 		return (NULL);
@@ -718,8 +735,8 @@
 static Boolean_t
 create_target_dir(char *targ_name, char *local_name)
 {
-	char	path[MAXPATHLEN],
-		sympath[MAXPATHLEN];
+	char	path[MAXPATHLEN];
+	char	sympath[MAXPATHLEN];
 
 	if ((mkdir(target_basedir, 0777) == -1) && (errno != EEXIST))
 		return (False);
@@ -750,16 +767,16 @@
     err_code_t *code)
 {
 	uint64_t	size;
-	int		fd		= -1,
-			rpm		= DEFAULT_RPM,
-			heads		= DEFAULT_HEADS,
-			cylinders	= DEFAULT_CYLINDERS,
-			spt		= DEFAULT_SPT,
-			bytes_sect	= DEFAULT_BYTES_PER,
-			interleave	= DEFAULT_INTERLEAVE;
-	char		*vid		= DEFAULT_VID,
-			*pid		= DEFAULT_PID,
-			path[MAXPATHLEN];
+	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];
 	FILE		*fp		= NULL;
 
 	/*
@@ -918,11 +935,11 @@
 {
 	struct stat		s;
 	int			fd			= -1;
-	char			path[MAXPATHLEN],
-				buf[512];
+	char			path[MAXPATHLEN];
+	char			buf[512];
 	struct statvfs		fs;
-	tgt_node_t		*node			= NULL,
-				*c;
+	tgt_node_t		*node			= NULL;
+	tgt_node_t		*c;
 	xmlTextReaderPtr	r;
 
 	/*
@@ -1088,12 +1105,10 @@
     uint64_t *size)
 {
 	struct stat	s;
-	char		*raw_name,
-			buf[512];
+	char		*raw_name, buf[512];
 	struct vtoc	vtoc;
 	struct dk_gpt	*efi;
-	int		slice,
-			fd;
+	int		slice, fd;
 
 	/*
 	 * Error checking regarding size and backing store has already
@@ -1293,11 +1308,8 @@
 zfs_lun(tgt_node_t *l, uint64_t size, char *dataset)
 {
 	tgt_node_t	*c;
-	int		cylinders,
-			heads,
-			spt,
-			val,
-			guid;
+	int		cylinders, heads, spt, val, guid;
+
 	create_geom(size, &cylinders, &heads, &spt);
 
 	guid = 0;
--- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/mgmt_modify.c	Tue May 29 17:13:54 2007 -0700
@@ -47,6 +47,7 @@
 #include "iscsi_cmd.h"
 #include "target.h"
 #include "errcode.h"
+#include "isns_client.h"
 
 static char *modify_target(tgt_node_t *x, ucred_t *cred);
 static char *modify_initiator(tgt_node_t *x, ucred_t *cred);
@@ -101,28 +102,27 @@
 static char *
 modify_target(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*name		= NULL,
-			*iscsi,
-			*prop		= NULL,
-			size_str[16],
-			path[MAXPATHLEN],
-			*m,
-			buf[512];		/* one sector size block */
-	tgt_node_t	*t		= NULL,
-			*list		= NULL,
-			*c		= NULL,
-			*node;
+	char		*msg		= NULL;
+	char		*name		= NULL;
+	char		*iscsi;
+	char		*prop		= NULL;
+	char		size_str[16];
+	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;
+	tgt_node_t	*tpgt		= NULL;
 	Boolean_t	change_made	= False;
-	int		lun		= 0,
-			fd,
-			xml_fd;
-	uint64_t	val,
-			new_lu_size,
-			cur_lu_size;
+	int		lun		= 0;
+	int		fd, xml_fd;
+	uint64_t	val, new_lu_size, cur_lu_size;
 	struct stat	st;
 	xmlTextReaderPtr	r;
 	const priv_set_t	*eset;
+	uint32_t		isns_mods	= 0;
 
 	eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
 	if (eset != NULL ? !priv_ismember(eset, PRIV_SYS_CONFIG) :
@@ -294,7 +294,7 @@
 
 	if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) {
 		if (prop == NULL) {
-			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL);
+			xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT);
 			return (msg);
 		}
 
@@ -309,6 +309,21 @@
 			return (msg);
 		}
 
+		/* update isns only if TPGT contains ip_addr */
+		while ((tpgt = tgt_node_next(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);
+				return (msg);
+			}
+		}
+
 		if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) ==
 		    NULL) {
 			free(prop);
@@ -335,8 +350,10 @@
 			tgt_node_add(list, c);
 			tgt_node_add(t, list);
 		}
+
 		free(prop);
 		prop = NULL;
+
 		change_made = True;
 	}
 
@@ -383,6 +400,7 @@
 		}
 		free(prop);
 		prop = NULL;
+		isns_mods |= ISNS_MOD_ALIAS;
 		change_made = True;
 	}
 
@@ -417,8 +435,17 @@
 	}
 
 	if (change_made == True) {
-		if (update_config_targets(&msg) == True)
-			xml_rtn_msg(&msg, ERR_SUCCESS);
+		if (update_config_targets(&msg) == False) {
+			xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED);
+			return (msg);
+		}
+		if (isns_enabled() == True) {
+			if (isns_dev_update(t->x_value, isns_mods) != 0) {
+				xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED);
+				return (msg);
+			}
+		}
+		xml_rtn_msg(&msg, ERR_SUCCESS);
 	} else {
 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND);
 	}
@@ -434,9 +461,9 @@
 static char *
 modify_initiator(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*name		= NULL,
-			*prop		= NULL;
+	char		*msg		= NULL;
+	char		*name		= NULL;
+	char		*prop		= NULL;
 	tgt_node_t	*inode		= NULL;
 	Boolean_t	changes_made	= False;
 	const priv_set_t	*eset;
@@ -519,8 +546,8 @@
 static char *
 modify_admin(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg	= NULL,
-			*prop;
+	char		*msg	= NULL;
+	char		*prop;
 	Boolean_t	changes_made = False;
 	admin_table_t	*ap;
 	const priv_set_t	*eset;
@@ -557,6 +584,11 @@
 	}
 
 	if (changes_made == True) {
+		/* isns_update updates isns_access & isns server name */
+		if (isns_update() != 0) {
+			xml_rtn_msg(&msg, ERR_ISNS_ERROR);
+			return (msg);
+		}
 		if (update_config_main(&msg) == True)
 			xml_rtn_msg(&msg, ERR_SUCCESS);
 	} else {
@@ -575,9 +607,9 @@
 modify_tpgt(tgt_node_t *x, ucred_t *cred)
 {
 	struct addrinfo	*res	= NULL;
-	char		*msg	= NULL,
-			*name	= NULL,
-			*ip_str	= NULL;
+	char		*msg	= NULL;
+	char		*name	= NULL;
+	char		*ip_str	= NULL;
 	tgt_node_t	*tnode	= NULL;
 	const priv_set_t	*eset;
 
@@ -618,6 +650,14 @@
 	if (update_config_main(&msg) == True)
 		xml_rtn_msg(&msg, ERR_SUCCESS);
 
+	/*
+	 * Re-register all targets, currently there's no method to
+	 * update TPGT for individual target
+	 */
+	if (isns_enabled() == True) {
+		isns_reg_all();
+	}
+
 error:
 	if (name)
 		free(name);
@@ -636,9 +676,9 @@
 static char *
 modify_zfs(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*prop		= NULL,
-			*dataset	= NULL;
+	char		*msg		= NULL;
+	char		*prop		= NULL;
+	char		*dataset	= NULL;
 	libzfs_handle_t	*zh		= NULL;
 	zfs_handle_t	*zfsh		= NULL;
 	tgt_node_t	*n		= NULL;
@@ -724,8 +764,8 @@
 {
 	tgt_node_t	*targ	= NULL;
 	int		count	= 0;
-	char		*msg	= NULL,
-			*val	= NULL;
+	char		*msg	= NULL;
+	char		*val	= NULL;
 
 	if ((prop == NULL) || (strlen(prop) == 0) || (prop[0] != '/')) {
 		xml_rtn_msg(&msg, ERR_INVALID_BASEDIR);
@@ -781,9 +821,8 @@
 valid_radius_srv(char *name, char *prop)
 {
 	struct addrinfo	*res	= NULL;
-	char		*msg	= NULL,
-			*sp,
-			*p;
+	char		*msg	= NULL;
+	char		*sp, *p;
 	int		port;
 
 	if ((sp = strdup(prop)) == NULL) {
@@ -805,3 +844,36 @@
 	free(sp);
 	return (msg);
 }
+
+/*
+ * []----
+ * | validate_isns_server -- validate that server[:port] are valid
+ * []----
+ */
+char *
+valid_isns_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_ISNS_SRV);
+			free(sp);
+			return (msg);
+		}
+	}
+	if ((getaddrinfo(sp, NULL, NULL, &res) != 0) || (res == NULL))
+		xml_rtn_msg(&msg, ERR_INVALID_ISNS_SRV);
+	else
+		freeaddrinfo(res);
+	free(sp);
+	return (msg);
+}
--- a/usr/src/cmd/iscsi/iscsitgtd/mgmt_remove.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/mgmt_remove.c	Tue May 29 17:13:54 2007 -0700
@@ -36,6 +36,7 @@
 #include <strings.h>
 #include <unistd.h>
 #include <priv.h>
+#include <syslog.h>
 
 #include <iscsitgt_impl.h>
 #include "utility.h"
@@ -43,6 +44,7 @@
 #include "target.h"
 #include "iscsi_cmd.h"
 #include "errcode.h"
+#include "isns_client.h"
 
 static char *remove_target(tgt_node_t *x, ucred_t *cred);
 static char *remove_initiator(tgt_node_t *x, ucred_t *cred);
@@ -56,8 +58,8 @@
     ucred_t *cred)
 {
 	tgt_node_t	*x;
-	char		msgbuf[80],
-			*reply_msg	= NULL;
+	char		msgbuf[80];
+	char		*reply_msg	= NULL;
 
 	if (p->x_child == NULL) {
 		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
@@ -90,8 +92,8 @@
 static char *
 remove_zfs(tgt_node_t *x, ucred_t *cred)
 {
-	char		*prop,
-			*msg		= NULL;
+	char		*prop;
+	char		*msg		= NULL;
 	tgt_node_t	*targ		= NULL;
 	const priv_set_t	*eset;
 
@@ -137,6 +139,10 @@
 	 * to issue the logout we'll have removed reference to the target
 	 * such that this can't happen.
 	 */
+	if (isns_enabled() == True) {
+		if (isns_dereg(prop) != 0)
+			syslog(LOG_INFO, "ISNS dereg failed\n");
+	}
 	logout_targ(prop);
 	free(prop);
 
@@ -147,11 +153,11 @@
 static char *
 remove_target(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg			= NULL,
-			*prop			= NULL;
-	tgt_node_t	*targ			= NULL,
-			*list,
-			*c			= NULL;
+	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;
 	const priv_set_t	*eset;
@@ -221,6 +227,13 @@
 		if (list->x_child == NULL)
 			(void) tgt_node_remove(targ, list, MatchName);
 		free(prop);
+
+		/* update isns */
+		if (isns_enabled()) {
+			if (isns_dev_update(targ->x_value, ISNS_MOD_TPGT) != 0)
+				syslog(LOG_ALERT, "ISNS register failed\n");
+		}
+
 		change_made = True;
 	}
 	if (tgt_find_value_int(x, XML_ELEMENT_LUN, &lun_num) == True) {
@@ -247,6 +260,12 @@
 		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;
@@ -272,8 +291,8 @@
 static char *
 remove_initiator(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg	= NULL,
-			*name;
+	char		*msg	= NULL;
+	char		*name;
 	tgt_node_t	*node	= NULL;
 	const priv_set_t	*eset;
 
@@ -314,10 +333,10 @@
 static char *
 remove_tpgt(tgt_node_t *x, ucred_t *cred)
 {
-	char		*msg		= NULL,
-			*prop		= NULL;
-	tgt_node_t	*node		= NULL,
-			*c		= NULL;
+	char		*msg		= NULL;
+	char		*prop		= NULL;
+	tgt_node_t	*node		= NULL;
+	tgt_node_t	*c		= NULL;
 	Boolean_t	change_made	= False;
 	const priv_set_t	*eset;
 
@@ -364,6 +383,9 @@
 	}
 
 	if (change_made == True) {
+		/* Isns re-register all target */
+		if (isns_enabled() == True)
+			isns_reg_all();
 		if (update_config_main(&msg) == True)
 			xml_rtn_msg(&msg, ERR_SUCCESS);
 	} else {
--- a/usr/src/cmd/iscsi/iscsitgtd/queue.h	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/queue.h	Tue May 29 17:13:54 2007 -0700
@@ -58,6 +58,8 @@
 #define	Q_GEN_ERRS	0x01000
 #define	Q_GEN_DETAILS	0x02000
 
+#define	Q_ISNS_DBG	0x10000
+
 /*
  * When used the queue request will be place at the head of the queue.
  */
--- a/usr/src/cmd/iscsi/iscsitgtd/target.h	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/target.h	Tue May 29 17:13:54 2007 -0700
@@ -179,6 +179,7 @@
 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);
 Boolean_t process_target_config();
@@ -195,7 +196,8 @@
 extern int		main_vers_maj,
 			main_vers_min,
 			targets_vers_maj,
-			targets_vers_min;
+			targets_vers_min,
+			iscsi_port;
 extern Boolean_t	enforce_strict_guid,
 			thin_provisioning,
 			disable_tpgs,
--- a/usr/src/cmd/iscsi/iscsitgtd/util.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/util.c	Tue May 29 17:13:54 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,6 +46,7 @@
 #include "target.h"
 #include "utility.h"
 #include "errcode.h"
+#include "isns_client.h"
 #include <sys/scsi/generic/commands.h>
 
 #define	CRC32_STR	"CRC32C"
@@ -74,12 +75,51 @@
 Boolean_t
 check_access(tgt_node_t *targ, char *initiator_name, Boolean_t req_chap)
 {
-	tgt_node_t	*acl,
-			*inode		= NULL,
-			*tgt_initiator	= NULL;
+	tgt_node_t	*acl;
+	tgt_node_t	*inode		= NULL;
+	tgt_node_t	*tgt_initiator	= NULL;
 	char		*dummy;
-	Boolean_t	valid		= False,
-			found_chap	= False;
+	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(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.
@@ -153,8 +193,8 @@
 static Boolean_t
 convert_local_tpgt(char **text, int *text_length, char *local_tpgt)
 {
-	tgt_node_t	*tpgt	= NULL,
-	*x;
+	tgt_node_t	*tpgt	= NULL;
+	tgt_node_t 	*x;
 	char		buf[80];
 	char		ipaddr[4];
 
@@ -207,15 +247,15 @@
 add_target_address(iscsi_conn_t *c, char **text, int *text_length,
     tgt_node_t *targ)
 {
-	tgt_node_t	*tpgt_list,
-			*tpgt		= NULL;
+	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],
-		net_buf[INET6_ADDRSTRLEN];
+	char	buf[INET6_ADDRSTRLEN + 7];
+	char	net_buf[INET6_ADDRSTRLEN];
 
 	if ((tpgt_list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST,
 	    NULL)) == NULL) {
@@ -233,16 +273,16 @@
 				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)),
+				    (void *)&sp4->sin_addr,
+				    net_buf, sizeof (net_buf)),
 				    tpgt->x_value);
 			} else {
 				/*CSTYLED*/
 				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)),
+				    (void *)&sp6->sin6_addr,
+				    net_buf, sizeof (net_buf)),
 				    tpgt->x_value);
 			}
 			(void) add_text(text, text_length, "TargetAddress",
@@ -298,8 +338,8 @@
 Boolean_t
 add_text(char **text, int *current_length, char *name, char *val)
 {
-	int	dlen = *current_length,
-		plen;
+	int	dlen = *current_length;
+	int	plen;
 	char	*p;
 
 	/*
@@ -385,10 +425,10 @@
 parse_text(iscsi_conn_t *c, int dlen, char **text, int *text_length,
     int *errcode)
 {
-	char		*p		= NULL,
-			*n,
-			*cur_pair,
-			param_rsp[32];
+	char		*p		= NULL;
+	char		*n;
+	char		*cur_pair;
+	char		param_rsp[32];
 	int		plen;		/* pair length */
 	Boolean_t	rval		= True;
 	char		param_buf[16];
@@ -544,7 +584,7 @@
 			if ((rval = connection_parameters_get(c, n)) == False) {
 				*errcode =
 				    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
-					ISCSI_LOGIN_STATUS_TGT_FORBIDDEN;
+				    ISCSI_LOGIN_STATUS_TGT_FORBIDDEN;
 			} else if ((rval = add_text(text, text_length,
 			    "TargetAlias", c->c_targ_alias)) == True) {
 
@@ -767,7 +807,7 @@
 			 * for future processing.
 			 */
 			rval = add_text(text, text_length,
-					cur_pair, "NotUnderstood");
+			    cur_pair, "NotUnderstood");
 
 			/*
 			 * Go ahead a log this information in case we see
@@ -822,8 +862,8 @@
 find_main_tpgt(struct sockaddr_storage *pst)
 {
 	char		ip_addr[16];
-	tgt_node_t	*tpgt				= NULL,
-			*ip_node			= NULL;
+	tgt_node_t	*tpgt				= NULL;
+	tgt_node_t	*ip_node			= NULL;
 	struct in_addr	addr;
 	struct in6_addr	addr6;
 
@@ -844,7 +884,7 @@
 			if (pst->ss_family == AF_INET) {
 
 				if (inet_pton(AF_INET, ip_node->x_value,
-					ip_addr) != 1) {
+				    ip_addr) != 1) {
 					continue;
 				}
 				if (bcmp(ip_addr, &addr,
@@ -854,7 +894,7 @@
 			} else if (pst->ss_family == AF_INET6) {
 
 				if (inet_pton(AF_INET6, ip_node->x_value,
-					ip_addr) != 1) {
+				    ip_addr) != 1) {
 					continue;
 				}
 				if (bcmp(ip_addr, &addr6,
@@ -880,10 +920,9 @@
 static int
 convert_to_tpgt(iscsi_conn_t *c, tgt_node_t *targ)
 {
-	tgt_node_t	*list,
-			*tpgt		= NULL;
-	int		addr_tpgt,
-			pos_tpgt;
+	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
@@ -938,8 +977,7 @@
 static Boolean_t
 connection_parameters_get(iscsi_conn_t *c, char *targ_name)
 {
-	tgt_node_t	*targ,
-			*alias;
+	tgt_node_t	*targ, *alias;
 	Boolean_t	rval	= False;
 
 	if ((targ = find_target_node(targ_name)) != NULL) {
@@ -973,10 +1011,9 @@
 Boolean_t
 validate_version(tgt_node_t *node, int *maj_p, int *min_p)
 {
-	char	*vers_str	= NULL,
-		*minor_part;
-	int	maj,
-		min;
+	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))
@@ -1005,8 +1042,8 @@
 sna_lt(uint32_t n1, uint32_t n2)
 {
 	return ((n1 != n2) &&
-		(((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) ||
-		    ((n1 > n2) && ((n2 - n1) < SNA32_CHECK))));
+	    (((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) ||
+	    ((n1 > n2) && ((n2 - n1) < SNA32_CHECK))));
 }
 
 /*
@@ -1018,8 +1055,8 @@
 sna_lte(uint32_t n1, uint32_t n2)
 {
 	return ((n1 == n2) ||
-		(((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) ||
-		    ((n1 > n2) && ((n2 - n1) < SNA32_CHECK))));
+	    (((n1 < n2) && ((n2 - n1) < SNA32_CHECK)) ||
+	    ((n1 > n2) && ((n2 - n1) < SNA32_CHECK))));
 }
 
 Boolean_t
@@ -1057,8 +1094,7 @@
 	 */
 	uint32_t	tval = (uint_t)time((time_t *)0);
 	size_t		guid_size;
-	int		i,
-			fd;
+	int		i, fd;
 
 	if ((mac_len == 0) && (if_find_mac(NULL) == False)) {
 
@@ -1126,8 +1162,8 @@
 void
 create_geom(diskaddr_t size, int *cylinder, int *heads, int *spt)
 {
-	diskaddr_t	sects	= size >> 9,
-			c, h, s, t;
+	diskaddr_t	sects	= size >> 9;
+	diskaddr_t	c, h, s, t;
 	int		pass;
 
 	/*
@@ -1226,8 +1262,7 @@
 util_title(target_queue_t *q, int type, int num, char *title)
 {
 	char	*type_str;
-	int	len,
-		pad;
+	int	len, pad;
 
 	len	= strlen(title);
 	pad	= len & 1;
@@ -1475,17 +1510,13 @@
 void
 remove_target_common(char *name, int lun_num, char **msg)
 {
-	tgt_node_t	*targ			= NULL,
-			*list,
-			*lun,
-			*node,
-			*c;
-	char		path[MAXPATHLEN],
-			*tname			= NULL,
-			*iname			= NULL,
-			*bs_path		= NULL;
-	int		chk,
-			xml_fd;
+	tgt_node_t	*targ			= NULL;
+	tgt_node_t	*list, *lun, *node, *c;
+	char		path[MAXPATHLEN];
+	char		*tname			= NULL;
+	char		*iname			= NULL;
+	char		*bs_path		= NULL;
+	int		chk, xml_fd;
 	Boolean_t	bs_delete		= False;
 	xmlTextReaderPtr	r;
 
--- a/usr/src/cmd/iscsi/iscsitgtd/util_err.c	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/util_err.c	Tue May 29 17:13:54 2007 -0700
@@ -39,7 +39,7 @@
 		return ((char *)gettext("Null XML message"));
 	case ERR_SYNTAX_EMPTY:
 		return ((char *)gettext("Syntax error: "
-			    "Empty XML message or 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:
@@ -111,10 +111,10 @@
 		return ((char *)gettext("TPGT not found"));
 	case ERR_ACCESS_RAW_DEVICE_FAILED:
 		return ((char *)gettext("Failed to "
-			    "access direct access device"));
+		    "access direct access device"));
 	case ERR_CREATE_METADATA_FAILED:
 		return ((char *)gettext("Failed to "
-			    "create meta data for tape device"));
+		    "create meta data for tape device"));
 	case ERR_CREATE_SYMLINK_FAILED:
 		return ((char *)gettext("Failed to "
 		    "create symbol link to backing store"));
@@ -129,19 +129,19 @@
 		    "exists"));
 	case ERR_DISK_BACKING_MUST_BE_REGULAR_FILE:
 		return ((char *)gettext("For type "
-			    "'disk' backing must be a regular file"));
+		    "'disk' backing must be a regular file"));
 	case ERR_DISK_BACKING_NOT_VALID_RAW:
 		return ((char *)gettext("Backing store is not valid raw "
 		    "device"));
 	case ERR_STAT_BACKING_FAILED:
 		return ((char *)gettext("Failed to "
-			    "stat(2) backing for 'disk'"));
+		    "stat(2) backing for 'disk'"));
 	case ERR_RAW_PART_NOT_CAP:
 		return ((char *)gettext("Partition size doesn't match capacity"
 		    " of device, use p0 or ctd name"));
 	case ERR_CREATE_TARGET_DIR_FAILED:
 		return ((char *)gettext("Failed to "
-			    "create target directory"));
+		    "create target directory"));
 	case ERR_ENCODE_GUID_FAILED:
 		return ((char *)gettext("Failed to encode GUID value"));
 	case ERR_INIT_XML_READER_FAILED:
@@ -150,16 +150,16 @@
 		return ((char *)gettext("Failed to open parameter file"));
 	case ERR_UPDATE_MAINCFG_FAILED:
 		return ((char *)gettext("Failed to "
-			    "update main configuration file"));
+		    "update main configuration file"));
 	case ERR_UPDATE_TARGCFG_FAILED:
 		return ((char *)gettext("Failed to "
-			    "update target configuration file"));
+		    "update target configuration file"));
 	case ERR_VALID_TARG_EXIST:
 		return ((char *)gettext("Valid targets "
-			    "exist under current base directory"));
+		    "exist under current base directory"));
 	case ERR_TARGCFG_MISSING_INAME:
 		return ((char *)gettext("Missing "
-			    "iscsi name in target configuration"));
+		    "iscsi name in target configuration"));
 	case ERR_NO_MATCH:
 		return ((char *)gettext("No match"));
 	case ERR_NO_MEM:
@@ -193,6 +193,10 @@
 		return ((char *)gettext("No credentials available from door"));
 	case ERR_NO_PERMISSION:
 		return ((char *)gettext("Permission denied"));
+	case ERR_ISNS_ERROR:
+		return ((char *)gettext("ISNS error"));
+	case ERR_TPGT_NO_IPADDR:
+		return ((char *)gettext("TPGT has no ip-addr"));
 	default:
 		return ((char *)gettext("Internal error: unknown message"));
 	}
--- a/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h	Tue May 29 17:10:21 2007 -0700
+++ b/usr/src/lib/libiscsitgt/common/iscsitgt_impl.h	Tue May 29 17:13:54 2007 -0700
@@ -80,6 +80,7 @@
 #define	XML_ELEMENT_RAD_SERV	"radius-server"
 #define	XML_ELEMENT_RAD_SECRET	"radius-secret"
 #define	XML_ELEMENT_ISNS_ACCESS	"isns-access"
+#define	XML_ELEMENT_ISNS_SERV	"isns-server"
 #define	XML_ELEMENT_FAST	"fast-write-ack"
 #define	XML_ELEMENT_NAME	"name"
 #define	XML_ELEMENT_ACL		"acl"