diff usr/src/cmd/iscsi/iscsitgtd/isns_client.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/iscsi/iscsitgtd/isns_client.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,1632 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)isns_client.c	1.5	08/02/11 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	cnt = 0;
+	uint32_t	got_dest = 0;
+	uint32_t	got_source = 0;
+	uint32_t	bitmap = 0;
+	uint32_t	got_bitmap = 0;
+	char		dest[MAXNAMELEN];
+	char		source[MAXNAMELEN];
+
+	queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u\n",
+	    scn->payload_len);
+
+	if (scn->payload_len < TAG_LEN_SZ) {
+		syslog(LOG_ALERT, "ISNS SCN message error\n");
+		return;
+	}
+
+	while (cnt < scn->payload_len) {
+		/* LINTED */
+		tlv = (isns_tlv_t *)ptr;
+		tlv->attr_id = ntohl(tlv->attr_id);
+		tlv->attr_len = ntohl(tlv->attr_len);
+		queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_SCN %u %u\n",
+		    tlv->attr_id, tlv->attr_len);
+		/*
+		 * devAttrQry the source attribute, process if node_type
+		 * is initiator
+		 */
+		switch (tlv->attr_id) {
+			case ISNS_ISCSI_NAME_ATTR_ID:
+				if (got_dest == 0) {
+					bcopy(tlv->attr_value, dest,
+					    tlv->attr_len);
+					queue_prt(mgmtq, Q_ISNS_DBG,
+					    "PROCESS_SCN dest %s\n", dest);
+					got_dest = 1;
+				} else {
+					bcopy(tlv->attr_value, source,
+					    tlv->attr_len);
+					queue_prt(mgmtq, Q_ISNS_DBG,
+					    "PROCESS_SCN source %s\n", source);
+					got_source = 1;
+				}
+				break;
+			case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
+				bcopy(tlv->attr_value, &bitmap, tlv->attr_len);
+				bitmap = ntohl(bitmap);
+				queue_prt(mgmtq, Q_ISNS_DBG,
+				    "PROCESS_SCN bitmap %u\n", bitmap);
+				got_bitmap = 1;
+				break;
+			default:
+				queue_prt(mgmtq, Q_ISNS_DBG,
+				    "PROCESS_SCN DEFAULT\n");
+				break;
+		}
+
+		if (got_source && !got_bitmap) {
+			queue_prt(mgmtq, Q_ISNS_DBG,
+			    "process_scn: message out-of-order\n");
+			return;
+		}
+
+		if (got_source && got_bitmap) {
+			switch (bitmap) {
+				case ISNS_OBJ_ADDED:
+				case ISNS_OBJ_UPDATED:
+					queue_prt(mgmtq, Q_ISNS_DBG,
+					    "PROCESS_SCN OBJ ADDED");
+					isns_update();
+					break;
+				case ISNS_OBJ_REMOVED:
+					queue_prt(mgmtq, Q_ISNS_DBG,
+					    "PROCESS_SCN OBJ REMOVED");
+					/* logout target */
+					if (got_dest == 0) {
+						syslog(LOG_ALERT,
+						    "ISNS protocol error\n");
+						continue;
+					}
+					logout_targ(dest);
+					break;
+				default:
+					break;
+			}
+
+			/* clear got_xxx */
+			got_source = 0;
+			got_bitmap = 1;
+		}
+
+		/* next attribute */
+		cnt += ISNS_ATTR_SZ(tlv->attr_len);
+		ptr += ISNS_ATTR_SZ(tlv->attr_len);
+	}
+	queue_prt(mgmtq, Q_ISNS_DBG, "DONE PROCESS_SCN\n");
+}
+
+/*
+ * Process ESI requires a success response only
+ */
+static void
+process_esi(int so, isns_pdu_t *esi)
+{
+	isns_rsp_t	*cmd;
+	int		pl_len;
+
+	if (isns_create_pdu(ISNS_ESI_RSP, 0, (isns_pdu_t **)&cmd) != 0) {
+		return;
+	}
+
+	pl_len = esi->payload_len + ISNS_STATUS_SZ;
+	if (pl_len > MAX_PDU_PAYLOAD_SZ) {
+		syslog(LOG_ALERT, "process_esi: payload size exceeded");
+		isns_free_pdu(cmd);
+		return;
+	}
+
+	/* change the xid to the request xid */
+	cmd->xid = htons(esi->xid);
+	cmd->status = htonl(ISNS_RSP_SUCCESSFUL);
+
+	/* copy original data */
+	bcopy(esi->payload, cmd->data, esi->payload_len);
+	cmd->pdu_len = htons(pl_len);
+
+	if (isns_send(so, (isns_pdu_t *)cmd) < 0) {
+		syslog(LOG_ALERT, "process_esi failed to isns_send");
+	}
+
+	isns_free_pdu(cmd);
+}
+
+/*
+ * 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 the iSNS server is different, then dregister all from
+	 * the old iSNS server, and register all to the new iSNS server
+	 */
+
+	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);
+
+		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);
+			}
+		}
+	}
+	if (isns_srv != NULL)
+		free(isns_srv);
+
+	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);
+
+	isns_initialized = False;
+}
+
+static int
+get_ip_addr(char *node, ip_t *sa)
+{
+	struct addrinfo		*ai = NULL, *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);
+				freeaddrinfo(ai);
+				return (0);
+			case PF_INET6:
+				/* LINTED */
+				sin6 = (struct sockaddr_in6 *)aip->ai_addr;
+				sa->ip_len = sizeof (in6_addr_t);
+				bcopy(&sin6->sin6_addr, &sa->ip_adr.in6,
+				    sa->ip_len);
+				freeaddrinfo(ai);
+				return (0);
+			default:
+				continue;
+		}
+	} while ((aip = aip->ai_next) != NULL);
+
+	freeaddrinfo(ai);
+	return (-1);
+}
+
+/*
+ * Process isns response, need to verify same transaction id, func_id
+ * as the isns command, the isns command is in network byte order,
+ * the isns response is in host byte order
+ */
+static int
+process_rsp(isns_pdu_t *cmd, isns_rsp_t *rsp)
+{
+	queue_prt(mgmtq, Q_ISNS_DBG, "PROCESS_RSP");
+	/*
+	 * Process responses:
+	 *	-verify sucessful response
+	 *	-verify match xid
+	 *	-process operating attributes
+	 * For DevAttrReg & DevAttrQry and most isns command,
+	 * the response func_id is  command_func_id | 0x8000.
+	 */
+	rsp->status = ntohl(rsp->status);
+	if (rsp->status != ISNS_RSP_SUCCESSFUL ||
+	    rsp->xid != ntohs(cmd->xid) ||
+	    rsp->func_id != (ntohs(cmd->func_id) | 0x8000)) {
+		queue_prt(mgmtq, Q_ISNS_DBG,
+		    "cmd failed with: status= %d xid= %d %d "\
+		    "response attribute %x\n", rsp->status, rsp->xid,\
+		    ntohs(cmd->xid), rsp->func_id);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * DevAttrDereg
+ */
+static int
+isns_dev_attr_dereg(int so, char *node)
+{
+	isns_pdu_t	*cmd = NULL;
+	isns_rsp_t	*rsp = NULL;
+	uint32_t	flags = 0;
+	int		ret = -1;
+
+	queue_prt(mgmtq, Q_ISNS_DBG, "ISNS_DEV_ATTR_DEREG");
+
+	if (isns_create_pdu(ISNS_DEV_DEREG, flags, &cmd) != 0) {
+		return (-1);
+	}
+
+	/* add source attribute */
+	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
+	    STRLEN(node), node, 0) != 0) {
+		goto error;
+	}
+
+	/* add delimiter */
+	if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) {
+		goto error;
+	}
+
+	/* add operation attributes */
+	if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID,
+	    STRLEN(node), node, 0) != 0) {
+		goto error;
+	}
+
+	/* send pdu */
+	if (isns_send(so, cmd) == -1) {
+		syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_send");
+		goto error;
+	}
+
+	/* get isns response */
+	if (isns_recv(so, &rsp) == -1) {
+		syslog(LOG_ERR, "isns_dev_attr_dereg fails isns_recv ");
+		goto error;
+	}
+
+	/* process response */
+	if (process_rsp(cmd, rsp) == 0) {
+		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) {
+		return (0);
+	}
+	if (tgt->x_value == NULL) {
+		syslog(LOG_ALERT, "ISNS: target with NULL local name\n");
+		return (-1);
+	}
+	if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n)
+	    == FALSE) {
+		syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n");
+		return (-1);
+	}
+	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);
+}