changeset 13181:88e527ca878f

sync with onnv-gate 13149:b23a4dab3d50 Reviewed by: garrett@nexenta.com, gwr@nexenta.com Approved by: garrett@nexenta.com
author Richard Lowe <richlowe@richlowe.net>
date Thu, 09 Sep 2010 11:46:43 -0400
parents 5f6c3c121560 (current diff) b23a4dab3d50 (diff)
children 35bf26976d42
files
diffstat 57 files changed, 2050 insertions(+), 1901 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Sep 03 23:10:16 2010 +0200
+++ b/.hgtags	Thu Sep 09 11:46:43 2010 -0400
@@ -128,3 +128,4 @@
 96016f1d98371e79260cf42cd053532602fe964a onnv_144
 87e07d18c459a7f43c3175ec35f4536eaf3f78cf onnv_145
 51b1767a74cbfba539a0dfdd5df2cefd1964b2ce onnv_146
+67d1861e02c15565f9bc5a6e271fa99c13d0d4c8 onnv_147
--- a/usr/src/Makefile.buildnum	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/Makefile.buildnum	Thu Sep 09 11:46:43 2010 -0400
@@ -37,4 +37,4 @@
 # currently open build in the onnv-gate.
 #
 
-ONNV_BUILDNUM= 147
+ONNV_BUILDNUM= 148
--- a/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd.h	Thu Sep 09 11:46:43 2010 -0400
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 #ifndef _ILBD_H
 #define	_ILBD_H
@@ -284,7 +283,8 @@
  * data. Not all events use all members of the structure.
  */
 typedef struct audit_sg_event_data {
-	char	*ed_server_address;	/* server's IP address */
+	int32_t	ed_ipaddr_type;	/* ADT_IPv4 or ADT_IPv6 */
+	uint32_t ed_server_address[4];  /* server's IP address */
 	char	*ed_serverid;   /* serverid. */
 	uint16_t	ed_minport;	/* server's minport */
 	uint16_t	ed_maxport;	/* server's maxport */
@@ -421,11 +421,10 @@
 		    const struct passwd *, ucred_t *), void *, void *);
 ilb_status_t	ilbd_walk_hc_pgs(ilb_status_t (*)(const ilb_hc_info_t *, int,
 		    const struct passwd *, ucred_t *), void *, void *);
-void		ilbd_addr2str(struct in6_addr *, char *, size_t);
-void		addr2str(ilb_ip_addr_t, char *, size_t);
 void		ilbd_algo_to_str(ilb_algo_t, char *);
 void		ilbd_topo_to_str(ilb_topo_t, char *);
 void		ilbd_ip_to_str(uint16_t, struct in6_addr *, char *);
+void		cvt_addr(uint32_t *, int32_t, struct in6_addr);
 int		ilberror2auditerror(ilb_status_t);
 
 #ifdef __cplusplus
--- a/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd_rules.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd_rules.c	Thu Sep 09 11:46:43 2010 -0400
@@ -512,10 +512,7 @@
 	char			*valstr1 = NULL;
 	char			*valstr2 = NULL;
 	char			pbuf[PROTOCOL_LEN]; /* protocol */
-	char			pxbuf[ADDR_LEN]; /* prxy src range */
 	char			hcpbuf[PORT_LEN]; /* hcport */
-	char			addrstr_buf[INET6_ADDRSTRLEN];
-	char			addrstr_buf1[INET6_ADDRSTRLEN];
 	int			audit_error;
 
 	if ((ucredp == NULL) && (cmd == ILBD_CREATE_RULE))  {
@@ -577,12 +574,18 @@
 
 		event->adt_ilb_create_rule.auth_used = NET_ILB_CONFIG_AUTH;
 
-		/* Fill in virtual IP address */
-		addrstr_buf[0] = '\0';
-		ilbd_addr2str(&rlinfo->rl_vip, addrstr_buf,
-		    sizeof (addrstr_buf));
-		event->adt_ilb_create_rule.virtual_ipaddress = addrstr_buf;
-
+		/* Fill in virtual IP address type */
+		if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_vip)) {
+			event->adt_ilb_create_rule.virtual_ipaddress_type =
+			    ADT_IPv4;
+			cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress,
+			    ADT_IPv4, rlinfo->rl_vip);
+		} else {
+			event->adt_ilb_create_rule.virtual_ipaddress_type =
+			    ADT_IPv6;
+			cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress,
+			    ADT_IPv6, rlinfo->rl_vip);
+		}
 		/* Fill in port - could be a single value or a range */
 		event->adt_ilb_create_rule.min_port = ntohs(rlinfo->rl_minport);
 		if (ntohs(rlinfo->rl_maxport) > ntohs(rlinfo->rl_minport)) {
@@ -614,20 +617,53 @@
 
 		/* Fill in proxy-src for the NAT case */
 		if (rlinfo->rl_topo == ILB_TOPO_NAT)  {
-			ilbd_addr2str(&rlinfo->rl_nat_src_start, addrstr_buf,
-			    sizeof (addrstr_buf));
-			if (&rlinfo->rl_nat_src_end == 0) {
-				/* Single address */
-				(void) snprintf(pxbuf, ADDR_LEN,
-				    "%s", addrstr_buf);
+			/* copy starting proxy-src address */
+			if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_start)) {
+				/* V4 case */
+				event->adt_ilb_create_rule.proxy_src_min_type =
+				    ADT_IPv4;
+				cvt_addr(
+				    event->adt_ilb_create_rule.proxy_src_min,
+				    ADT_IPv4, rlinfo->rl_nat_src_start);
 			} else {
-				/* address range */
-				ilbd_addr2str(&rlinfo->rl_nat_src_end,
-				    addrstr_buf1, sizeof (addrstr_buf1));
-				(void) snprintf(pxbuf, ADDR_LEN,
-				    "%s-%s", addrstr_buf, addrstr_buf1);
+				/* V6 case */
+				event->adt_ilb_create_rule.proxy_src_min_type =
+				    ADT_IPv6;
+				cvt_addr(
+				    event->adt_ilb_create_rule.proxy_src_min,
+				    ADT_IPv6, rlinfo->rl_nat_src_start);
 			}
-			event->adt_ilb_create_rule.proxy_src = pxbuf;
+
+			/* copy ending proxy-src address */
+			if (&rlinfo->rl_nat_src_end == 0) {
+				/* proxy-src is a single address */
+				event->adt_ilb_create_rule.proxy_src_max_type =
+				    event->
+				    adt_ilb_create_rule.proxy_src_min_type;
+				(void) memcpy(
+				    event->adt_ilb_create_rule.proxy_src_max,
+				    event->adt_ilb_create_rule.proxy_src_min,
+				    (4 * sizeof (uint32_t)));
+			} else if (
+			    IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_end)) {
+				/*
+				 * proxy-src is a address range - copy ending
+				 * proxy-src address
+				 * V4 case
+				 */
+				event->adt_ilb_create_rule.proxy_src_max_type =
+				    ADT_IPv4;
+				cvt_addr(
+				    event->adt_ilb_create_rule.proxy_src_max,
+				    ADT_IPv4, rlinfo->rl_nat_src_end);
+			} else {
+				/* V6 case */
+				event->adt_ilb_create_rule.proxy_src_max_type =
+				    ADT_IPv6;
+				cvt_addr(
+				    event->adt_ilb_create_rule.proxy_src_max,
+				    ADT_IPv6, rlinfo->rl_nat_src_end);
+			}
 		}
 
 		/*
@@ -692,6 +728,24 @@
 	free(valstr2);
 	(void) adt_end_session(ah);
 }
+/*
+ * converts IP address from in6_addr format to uint32_t[4]
+ * This conversion is needed for recording IP address in
+ * audit records.
+ */
+void
+cvt_addr(uint32_t *audit, int32_t type, struct in6_addr address)
+{
+
+	if (type == ADT_IPv4)  {
+		/* address is IPv4 */
+		audit[0] = address._S6_un._S6_u32[3];
+	} else {
+		/* address is IPv6 */
+		(void) memcpy(audit, address._S6_un._S6_u32,
+		    (4 * sizeof (uint32_t)));
+	}
+}
 
 static ilb_status_t
 i_ilbd_action_switch(ilbd_rule_t *irl, ilbd_cmd_t cmd,
--- a/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd_sg.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/cmd-inet/usr.lib/ilbd/ilbd_sg.c	Thu Sep 09 11:46:43 2010 -0400
@@ -205,16 +205,22 @@
 		    NET_ILB_ENABLE_AUTH;
 		event->adt_ilb_enable_server.server_id =
 		    data->ed_serverid;
-		event->adt_ilb_enable_server.server_ipaddress =
-		    data->ed_server_address;
+		event->adt_ilb_enable_server.server_ipaddress_type =
+		    data->ed_ipaddr_type;
+		(void) memcpy(event->adt_ilb_enable_server.server_ipaddress,
+		    data->ed_server_address,
+		    (sizeof (data->ed_server_address)));
 		break;
 	case ILBD_DISABLE_SERVER:
 		event->adt_ilb_disable_server.auth_used =
 		    NET_ILB_ENABLE_AUTH;
 		event->adt_ilb_disable_server.server_id =
 		    data->ed_serverid;
-		event->adt_ilb_disable_server.server_ipaddress =
-		    data->ed_server_address;
+		event->adt_ilb_disable_server.server_ipaddress_type =
+		    data->ed_ipaddr_type;
+		(void) memcpy(event->adt_ilb_disable_server.server_ipaddress,
+		    data->ed_server_address,
+		    (sizeof (data->ed_server_address)));
 		break;
 	case ILBD_REM_SERVER_FROM_GROUP:
 		event->adt_ilb_remove_server.auth_used =
@@ -222,8 +228,11 @@
 		event->adt_ilb_remove_server.server_id =
 		    data->ed_serverid;
 		event->adt_ilb_remove_server.server_group = data->ed_sgroup;
-		event->adt_ilb_remove_server.server_ipaddress =
-		    data->ed_server_address;
+		event->adt_ilb_remove_server.server_ipaddress_type =
+		    data->ed_ipaddr_type;
+		(void) memcpy(event->adt_ilb_remove_server.server_ipaddress,
+		    data->ed_server_address,
+		    (sizeof (data->ed_server_address)));
 		break;
 	case ILBD_CREATE_SERVERGROUP:
 		event->adt_ilb_create_servergroup.auth_used =
@@ -234,8 +243,11 @@
 	case ILBD_ADD_SERVER_TO_GROUP:
 		event->adt_ilb_add_server.auth_used =
 		    NET_ILB_CONFIG_AUTH;
-		event->adt_ilb_add_server.server_ipaddress =
-		    data->ed_server_address;
+		event->adt_ilb_add_server.server_ipaddress_type =
+		    data->ed_ipaddr_type;
+		(void) memcpy(event->adt_ilb_add_server.server_ipaddress,
+		    data->ed_server_address,
+		    (sizeof (data->ed_server_address)));
 		event->adt_ilb_add_server.server_id =
 		    data->ed_serverid;
 		event->adt_ilb_add_server.server_group =
@@ -547,19 +559,24 @@
 	for (i = 0; i < sg->sg_srvcount; i++) {
 		tsrv = &sg->sg_servers[i];
 		if (cmd == ILBD_ADD_SERVER_TO_GROUP)  {
-			char	addrstr_buf[INET6_ADDRSTRLEN];
 
 			audit_sg_data->ed_serverid = NULL;
-			ilbd_addr2str(&tsrv->sgs_addr, addrstr_buf,
-			    sizeof (addrstr_buf));
-			audit_sg_data->ed_server_address = addrstr_buf;
+			if (IN6_IS_ADDR_V4MAPPED(&tsrv->sgs_addr)) {
+				audit_sg_data->ed_ipaddr_type = ADT_IPv4;
+				cvt_addr(audit_sg_data->ed_server_address,
+				    ADT_IPv4, tsrv->sgs_addr);
+			} else {
+				audit_sg_data->ed_ipaddr_type = ADT_IPv6;
+				cvt_addr(audit_sg_data->ed_server_address,
+				    ADT_IPv6, tsrv->sgs_addr);
+			}
 			audit_sg_data->ed_minport = tsrv->sgs_minport;
 			audit_sg_data->ed_maxport = tsrv->sgs_maxport;
 			audit_sg_data->ed_sgroup = sg->sg_name;
 		} else if (cmd == ILBD_REM_SERVER_FROM_GROUP) {
 			audit_sg_data->ed_serverid = tsrv->sgs_srvID;
 			audit_sg_data->ed_sgroup = sg->sg_name;
-			audit_sg_data->ed_server_address = NULL;
+
 			audit_sg_data->ed_minport = 0;
 			audit_sg_data->ed_maxport = 0;
 		}
@@ -582,7 +599,6 @@
 	ilbd_srv_t	*nsrv;
 	ilb_sg_srv_t	*srv;
 	audit_sg_event_data_t   audit_sg_data;
-	char    addrstr_buf[INET6_ADDRSTRLEN];
 
 	if (ps != NULL) {
 		rc = ilbd_check_client_config_auth(ps);
@@ -624,9 +640,15 @@
 		srv = &sg_info->sg_servers[i];
 
 		(void) memset(&audit_sg_data, 0, sizeof (audit_sg_data));
-		ilbd_addr2str(&srv->sgs_addr, addrstr_buf,
-		    sizeof (addrstr_buf));
-		audit_sg_data.ed_server_address = addrstr_buf;
+		if (IN6_IS_ADDR_V4MAPPED(&srv->sgs_addr)) {
+			audit_sg_data.ed_ipaddr_type = ADT_IPv4;
+			cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4,
+			    srv->sgs_addr);
+		} else {
+			audit_sg_data.ed_ipaddr_type = ADT_IPv6;
+			cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6,
+			    srv->sgs_addr);
+		}
 		audit_sg_data.ed_minport = srv->sgs_minport;
 		audit_sg_data.ed_maxport = srv->sgs_maxport;
 		audit_sg_data.ed_sgroup = sg_info->sg_name;
@@ -938,7 +960,6 @@
 	ilbd_srv_t	*srv, tmp_srv;
 	ilb_sg_srv_t    *tsrv;
 	audit_sg_event_data_t   audit_sg_data;
-	char    addrstr_buf[INET6_ADDRSTRLEN];
 
 	rc = ilbd_check_client_config_auth(ps);
 	if (rc != ILB_STATUS_OK) {
@@ -958,7 +979,6 @@
 	tsrv = &sg_info->sg_servers[0];
 	audit_sg_data.ed_serverid = tsrv->sgs_srvID;
 	audit_sg_data.ed_sgroup = sg_info->sg_name;
-	audit_sg_data.ed_server_address = NULL;
 
 	assert(sg_info->sg_srvcount == 1);
 	srv = i_find_srv(&tmp_sg->isg_srvlist, &sg_info->sg_servers[0],
@@ -971,9 +991,15 @@
 		return (ILB_STATUS_SRVUNAVAIL);
 	}
 	tsrv = &srv->isv_srv;
-	ilbd_addr2str(&tsrv->sgs_addr, addrstr_buf,
-	    sizeof (addrstr_buf));
-	audit_sg_data.ed_server_address = addrstr_buf;
+	if (IN6_IS_ADDR_V4MAPPED(&tsrv->sgs_addr)) {
+		audit_sg_data.ed_ipaddr_type = ADT_IPv4;
+		cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4,
+		    tsrv->sgs_addr);
+	} else {
+		audit_sg_data.ed_ipaddr_type = ADT_IPv6;
+		cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6,
+		    tsrv->sgs_addr);
+	}
 	/*
 	 * i_delete_srv frees srv, therefore we need to save
 	 * this information for ilbd_scf_del_srv
@@ -1184,7 +1210,6 @@
 	uint32_t	nflags;
 	ilbd_srv_status_ind_t u_cmd;
 	audit_sg_event_data_t   audit_sg_data;
-	char    addrstr_buf[INET6_ADDRSTRLEN];
 
 	(void) memset(&audit_sg_data, 0, sizeof (audit_sg_data));
 
@@ -1193,7 +1218,6 @@
 
 	srv = &sg->sg_servers[0];
 	audit_sg_data.ed_serverid = srv->sgs_srvID;
-	audit_sg_data.ed_server_address = NULL;
 
 	rc = ilbd_check_client_enable_auth(ps);
 	if (rc != ILB_STATUS_OK) {
@@ -1298,9 +1322,15 @@
 		return (ILB_STATUS_INVAL_ENBSRVR);
 	}
 	/* Fill in the server IP address for audit record */
-	ilbd_addr2str(&tmp_srv->isv_addr, addrstr_buf,
-	    sizeof (addrstr_buf));
-	audit_sg_data.ed_server_address = addrstr_buf;
+	if (IN6_IS_ADDR_V4MAPPED(&tmp_srv->isv_addr)) {
+		audit_sg_data.ed_ipaddr_type = ADT_IPv4;
+		cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4,
+		    tmp_srv->isv_addr);
+	} else {
+		audit_sg_data.ed_ipaddr_type = ADT_IPv6;
+		cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6,
+		    tmp_srv->isv_addr);
+	}
 
 	/*
 	 * We have found the server in memory, perform the following
@@ -1540,38 +1570,6 @@
 	return (ILB_STATUS_OK);
 }
 
-void
-ilbd_addr2str(struct in6_addr *ipaddr, char *addrstr_buf, size_t sz)
-{
-	ilb_ip_addr_t	ilb_ip;
-
-	IP_COPY_IMPL_2_CLI(ipaddr, &ilb_ip);
-	addr2str(ilb_ip, addrstr_buf, sz);
-}
-
-/* Convert ip address to a address string */
-void
-addr2str(ilb_ip_addr_t ip, char *buf, size_t sz)
-{
-
-	switch (ip.ia_af) {
-	case AF_INET:
-		if ((uint32_t *)&(ip).ia_v4 == 0)
-			buf[0] = '\0';
-		else
-			(void) inet_ntop(AF_INET, (void *)&(ip).ia_v4, buf, sz);
-		break;
-	case AF_INET6:
-		if (IN6_IS_ADDR_UNSPECIFIED(&(ip).ia_v6)) {
-			buf[0] = '\0';
-			break;
-		}
-		(void) inet_ntop(ip.ia_af, (void *)&(ip).ia_v6, buf, sz);
-		break;
-	default: buf[0] = '\0';
-	}
-}
-
 /*
  * Map ilb_status errors to similar errno values from errno.h or
  * adt_event.h to be used for audit record
--- a/usr/src/cmd/man/src/man.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/man/src/man.c	Thu Sep 09 11:46:43 2010 -0400
@@ -91,7 +91,7 @@
 
 #define	SOLIMIT		10	/* maximum allowed .so chain length */
 #define	MAXDIRS		128	/* max # of subdirs per manpath */
-#define	MAXPAGES	32	/* max # for multiple pages */
+#define	MAXPAGES	128	/* max # for multiple pages */
 #define	PLEN		3	/* prefix length {man, cat, fmt} */
 #define	TMPLEN		7	/* length of tmpfile prefix */
 #define	MAXTOKENS 	64
@@ -1755,7 +1755,7 @@
 			if (**secv == '\\') {
 				if (!eq(*secv + 1, *dv+plen))
 					continue;
-			} else if (!match(*secv, *dv+plen, len)) {
+			} else if (strncasecmp(*secv, *dv+plen, len) != 0) {
 				/* check to see if directory name changed */
 				if (!all &&
 				    (newsection = map_section(*secv, path))
@@ -1945,7 +1945,7 @@
 	FILE *fp;
 	struct stat sbuf;
 	struct suffix *sp;
-	struct suffix	psecs[MAXPAGES];
+	struct suffix	psecs[MAXPAGES+1];
 	char whatfile[MAXPATHLEN+1];
 	char page[MAXPATHLEN+1];
 	char *matches[MAXPAGES];
@@ -1982,8 +1982,20 @@
 	 * Save and split sections
 	 * section() allocates memory for sp->ds
 	 */
-	for (sp = psecs, vp = matches; *vp; vp++, sp++)
-		section(sp, *vp);
+	for (sp = psecs, vp = matches; *vp; vp++, sp++) {
+		if ((sp - psecs) < MAXPAGES) {
+			section(sp, *vp);
+		} else {
+			if (debug)
+				(void) fprintf(stderr, gettext(
+				    "too many sections in %s windex entry\n"),
+				    name);
+
+			/* Setting sp->ds to NULL signifies end-of-data. */
+			sp->ds = 0;
+			goto finish;
+		}
+	}
 
 	sp->ds = 0;
 
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c	Thu Sep 09 11:46:43 2010 -0400
@@ -584,16 +584,10 @@
 static const smb_exp_t smb_server_exp[] =
 {
 	{ SMB_OPT_ALL_OBJ,
-	    offsetof(smb_server_t, sv_nbt_daemon.ld_session_list.se_rdy.lst),
+	    offsetof(smb_server_t, sv_nbt_daemon.ld_session_list.ll_list),
 	    "smbsess", "smb_session"},
 	{ SMB_OPT_ALL_OBJ,
-	    offsetof(smb_server_t, sv_nbt_daemon.ld_session_list.se_act.lst),
-	    "smbsess", "smb_session"},
-	{ SMB_OPT_ALL_OBJ,
-	    offsetof(smb_server_t, sv_tcp_daemon.ld_session_list.se_rdy.lst),
-	    "smbsess", "smb_session"},
-	{ SMB_OPT_ALL_OBJ,
-	    offsetof(smb_server_t, sv_tcp_daemon.ld_session_list.se_act.lst),
+	    offsetof(smb_server_t, sv_tcp_daemon.ld_session_list.ll_list),
 	    "smbsess", "smb_session"},
 	{ 0, 0, NULL, NULL }
 };
--- a/usr/src/cmd/smbsrv/smbd/server.xml	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/smbsrv/smbd/server.xml	Thu Sep 09 11:46:43 2010 -0400
@@ -169,7 +169,7 @@
 		<propval name='max_workers' type='integer'
 			value='1024' override='true'/>
 		<propval name='max_connections' type='integer'
-			value='-1' override='true'/>
+			value='100000' override='true'/>
 		<propval name='keep_alive' type='integer'
 			value='5400' override='true'/>
 		<propval name='restrict_anonymous' type='boolean'
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Thu Sep 09 11:46:43 2010 -0400
@@ -63,11 +63,6 @@
 #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
 #define	SMB_DBDIR "/var/smb"
 
-static void *smbd_nbt_listener(void *);
-static void *smbd_tcp_listener(void *);
-static void *smbd_nbt_receiver(void *);
-static void *smbd_tcp_receiver(void *);
-
 static int smbd_daemonize_init(void);
 static void smbd_daemonize_fini(int, int);
 static int smb_init_daemon_priv(int, uid_t, gid_t);
@@ -96,18 +91,11 @@
 static void smbd_refresh_fini(void);
 static void *smbd_refresh_monitor(void *);
 
-static int smbd_start_listeners(void);
-static void smbd_stop_listeners(void);
 static int smbd_kernel_start(void);
 
-static void smbd_fatal_error(const char *);
-
 static pthread_cond_t refresh_cond;
 static pthread_mutex_t refresh_mutex;
 
-static cond_t listener_cv;
-static mutex_t listener_mutex;
-
 /*
  * Mutex to ensure that smbd_service_fini() and smbd_service_init()
  * are atomic w.r.t. one another.  Otherwise, if a shutdown begins
@@ -841,10 +829,7 @@
 
 	rc = smb_kmod_start(smbd.s_door_opipe, smbd.s_door_lmshr,
 	    smbd.s_door_srv);
-	if (rc != 0)
-		return (rc);
 
-	rc = smbd_start_listeners();
 	if (rc != 0)
 		return (rc);
 
@@ -859,7 +844,6 @@
 smbd_kernel_unbind(void)
 {
 	smbd_spool_fini();
-	smbd_stop_listeners();
 	smb_kmod_unbind();
 	smbd.s_kbound = B_FALSE;
 }
@@ -1078,181 +1062,6 @@
 	(void) fprintf(stderr, "smbd: %s\n", buf);
 }
 
-static int
-smbd_start_listeners(void)
-{
-	int		rc1;
-	int		rc2;
-	pthread_attr_t	tattr;
-
-	(void) pthread_attr_init(&tattr);
-
-	if (!smbd.s_nbt_listener_running) {
-		rc1 = pthread_create(&smbd.s_nbt_listener_id, &tattr,
-		    smbd_nbt_listener, NULL);
-		if (rc1 != 0)
-			smbd_report("unable to start NBT service");
-		else
-			smbd.s_nbt_listener_running = B_TRUE;
-	}
-
-	if (!smbd.s_tcp_listener_running) {
-		rc2 = pthread_create(&smbd.s_tcp_listener_id, &tattr,
-		    smbd_tcp_listener, NULL);
-		if (rc2 != 0)
-			smbd_report("unable to start TCP service");
-		else
-			smbd.s_tcp_listener_running = B_TRUE;
-	}
-
-	(void) pthread_attr_destroy(&tattr);
-
-	if (rc1 != 0)
-		return (rc1);
-	return (rc2);
-}
-
-/*
- * Stop the listener threads.  In an attempt to ensure that the listener
- * threads get the signal, we use the timed wait loop to harass the
- * threads into terminating.  Then, if they are still running, we make
- * one final attempt to deliver the signal before calling thread join
- * to wait for them.  Note: if these threads don't terminate, smbd will
- * hang here and SMF will probably end up killing the contract.
- */
-static void
-smbd_stop_listeners(void)
-{
-	void		*status;
-	timestruc_t	delay;
-	int		rc = 0;
-
-	(void) mutex_lock(&listener_mutex);
-
-	while ((smbd.s_nbt_listener_running || smbd.s_tcp_listener_running) &&
-	    (rc != ETIME)) {
-		if (smbd.s_nbt_listener_running)
-			(void) pthread_kill(smbd.s_nbt_listener_id, SIGTERM);
-
-		if (smbd.s_tcp_listener_running)
-			(void) pthread_kill(smbd.s_tcp_listener_id, SIGTERM);
-
-		delay.tv_sec = 3;
-		delay.tv_nsec = 0;
-		rc = cond_reltimedwait(&listener_cv, &listener_mutex, &delay);
-	}
-
-	(void) mutex_unlock(&listener_mutex);
-
-	if (smbd.s_nbt_listener_running) {
-		syslog(LOG_WARNING, "NBT listener still running");
-		(void) pthread_kill(smbd.s_nbt_listener_id, SIGTERM);
-		(void) pthread_join(smbd.s_nbt_listener_id, &status);
-		smbd.s_nbt_listener_running = B_FALSE;
-	}
-
-	if (smbd.s_tcp_listener_running) {
-		syslog(LOG_WARNING, "TCP listener still running");
-		(void) pthread_kill(smbd.s_tcp_listener_id, SIGTERM);
-		(void) pthread_join(smbd.s_tcp_listener_id, &status);
-		smbd.s_tcp_listener_running = B_FALSE;
-	}
-}
-
-/*
- * Perform fatal error exit.
- */
-static void
-smbd_fatal_error(const char *msg)
-{
-	if (msg == NULL)
-		msg = "Fatal error";
-
-	smbd_report("%s", msg);
-	smbd.s_fatal_error = B_TRUE;
-	(void) kill(smbd.s_pid, SIGTERM);
-}
-
-/*ARGSUSED*/
-static void *
-smbd_nbt_receiver(void *arg)
-{
-	(void) smb_kmod_nbtreceive();
-	return (NULL);
-}
-
-/*ARGSUSED*/
-static void *
-smbd_nbt_listener(void *arg)
-{
-	pthread_attr_t	tattr;
-	sigset_t	set;
-	sigset_t	oset;
-	pthread_t	tid;
-	int		error = 0;
-
-	(void) sigfillset(&set);
-	(void) sigdelset(&set, SIGTERM);
-	(void) sigdelset(&set, SIGINT);
-	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-
-	while (smb_kmod_nbtlisten(error) == 0)
-		error = pthread_create(&tid, &tattr, smbd_nbt_receiver, NULL);
-
-	(void) pthread_attr_destroy(&tattr);
-
-	if (!smbd.s_shutting_down)
-		smbd_fatal_error("NBT listener thread terminated unexpectedly");
-
-	(void) mutex_lock(&listener_mutex);
-	smbd.s_nbt_listener_running = B_FALSE;
-	(void) cond_broadcast(&listener_cv);
-	(void) mutex_unlock(&listener_mutex);
-	return (NULL);
-}
-
-/*ARGSUSED*/
-static void *
-smbd_tcp_receiver(void *arg)
-{
-	(void) smb_kmod_tcpreceive();
-	return (NULL);
-}
-
-/*ARGSUSED*/
-static void *
-smbd_tcp_listener(void *arg)
-{
-	pthread_attr_t	tattr;
-	sigset_t	set;
-	sigset_t	oset;
-	pthread_t	tid;
-	int		error = 0;
-
-	(void) sigfillset(&set);
-	(void) sigdelset(&set, SIGTERM);
-	(void) sigdelset(&set, SIGINT);
-	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-
-	while (smb_kmod_tcplisten(error) == 0)
-		error = pthread_create(&tid, &tattr, smbd_tcp_receiver, NULL);
-
-	(void) pthread_attr_destroy(&tattr);
-
-	if (!smbd.s_shutting_down)
-		smbd_fatal_error("TCP listener thread terminated unexpectedly");
-
-	(void) mutex_lock(&listener_mutex);
-	smbd.s_tcp_listener_running = B_FALSE;
-	(void) cond_broadcast(&listener_cv);
-	(void) mutex_unlock(&listener_mutex);
-	return (NULL);
-}
-
 /*
  * Enable libumem debugging by default on DEBUG builds.
  */
--- a/usr/src/cmd/zonecfg/zonecfg.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/zonecfg/zonecfg.h	Thu Sep 09 11:46:43 2010 -0400
@@ -228,6 +228,12 @@
 extern char *res_types[];
 extern char *prop_types[];
 
+/*
+ * NOTE: Only Lex and YACC should use the following functions.
+ */
+extern void assert_no_unclaimed_tokens(void);
+extern char *claim_token(char *);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y	Thu Sep 09 11:46:43 2010 -0400
@@ -24,6 +24,14 @@
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+/*
+ * This file defines zonecfg(1M)'s grammar.
+ *
+ * Reduction rules that consume TOKENs must invoke claim_token() immediately
+ * before freeing the TOKENs or adding them to data structures (e.g., cmd) that
+ * will be cleaned up when the parser finishes or encounters errors.
+ */
+
 #include <stdio.h>
 #include <strings.h>
 
@@ -159,6 +167,11 @@
 
 %%
 
+/*
+ * NOTE: Each commands reduction rule must invoke assert_no_unclaimed_tokens()
+ * before it completes if it isn't processing an error.  This ensures that
+ * reduction rules properly consume TOKENs.
+ */
 commands: command terminator
 	{
 		if ($1 != NULL) {
@@ -168,6 +181,7 @@
 			bzero(list, sizeof (list_property_t));
 			num_prop_vals = 0;
 		}
+		assert_no_unclaimed_tokens();
 		return (0);
 	}
 	| command error terminator
@@ -191,6 +205,7 @@
 	}
 	| terminator
 	{
+		assert_no_unclaimed_tokens();
 		return (0);
 	}
 
@@ -228,7 +243,7 @@
 		cmd = $$;
 		$$->cmd_handler = &add_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 	| ADD resource_type
@@ -269,7 +284,7 @@
 		cmd = $$;
 		$$->cmd_handler = &cancel_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -289,7 +304,7 @@
 		cmd = $$;
 		$$->cmd_handler = &create_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 	| CREATE TOKEN TOKEN
@@ -299,8 +314,8 @@
 		cmd = $$;
 		$$->cmd_handler = &create_func;
 		$$->cmd_argc = 2;
-		$$->cmd_argv[0] = $2;
-		$$->cmd_argv[1] = $3;
+		$$->cmd_argv[0] = claim_token($2);
+		$$->cmd_argv[1] = claim_token($3);
 		$$->cmd_argv[2] = NULL;
 	}
 	| CREATE TOKEN TOKEN TOKEN
@@ -310,9 +325,9 @@
 		cmd = $$;
 		$$->cmd_handler = &create_func;
 		$$->cmd_argc = 3;
-		$$->cmd_argv[0] = $2;
-		$$->cmd_argv[1] = $3;
-		$$->cmd_argv[2] = $4;
+		$$->cmd_argv[0] = claim_token($2);
+		$$->cmd_argv[1] = claim_token($3);
+		$$->cmd_argv[2] = claim_token($4);
 		$$->cmd_argv[3] = NULL;
 	}
 
@@ -332,7 +347,7 @@
 		cmd = $$;
 		$$->cmd_handler = &commit_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -352,7 +367,7 @@
 		cmd = $$;
 		$$->cmd_handler = &delete_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -372,7 +387,7 @@
 		cmd = $$;
 		$$->cmd_handler = &end_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -392,7 +407,7 @@
 		cmd = $$;
 		$$->cmd_handler = &exit_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -412,7 +427,7 @@
 		cmd = $$;
 		$$->cmd_handler = &export_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 	| EXPORT TOKEN TOKEN
@@ -422,8 +437,8 @@
 		cmd = $$;
 		$$->cmd_handler = &export_func;
 		$$->cmd_argc = 2;
-		$$->cmd_argv[0] = $2;
-		$$->cmd_argv[1] = $3;
+		$$->cmd_argv[0] = claim_token($2);
+		$$->cmd_argv[1] = claim_token($3);
 		$$->cmd_argv[2] = NULL;
 	}
 
@@ -443,7 +458,7 @@
 		cmd = $$;
 		$$->cmd_handler = &help_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -461,7 +476,7 @@
 		short_usage(CMD_INFO);
 		(void) fputs("\n", stderr);
 		usage(B_FALSE, HELP_RES_PROPS);
-		free($2);
+		free(claim_token($2));
 		YYERROR;
 	}
 	|	INFO resource_type
@@ -687,6 +702,7 @@
 		short_usage(CMD_REMOVE);
 		(void) fputs("\n", stderr);
 		usage(B_FALSE, HELP_RES_PROPS);
+		free(claim_token($2));
 		YYERROR;
 	}
 	| REMOVE resource_type
@@ -705,7 +721,7 @@
 		$$->cmd_handler = &remove_func;
 		$$->cmd_res_type = $3;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 	| REMOVE property_name property_value
@@ -774,7 +790,7 @@
 		cmd = $$;
 		$$->cmd_handler = &revert_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -889,7 +905,7 @@
 			YYERROR;
 		cmd = $$;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 		$$->cmd_handler = &set_func;
 		$$->cmd_prop_nv_pairs = 1;
@@ -929,7 +945,7 @@
 		cmd = $$;
 		$$->cmd_handler = &verify_func;
 		$$->cmd_argc = 1;
-		$$->cmd_argv[0] = $2;
+		$$->cmd_argv[0] = claim_token($2);
 		$$->cmd_argv[1] = NULL;
 	}
 
@@ -1046,7 +1062,7 @@
 simple_prop_val: TOKEN
 	{
 		$$ = simple_prop_val_func($1);
-		free($1);
+		free(claim_token($1));
 		if ($$ == NULL)
 			YYERROR;
 	}
@@ -1081,7 +1097,7 @@
 complex_piece: property_name EQUAL TOKEN
 	{
 		$$ = complex_piece_func($1, $3, NULL);
-		free($3);
+		free(claim_token($3));
 		if ($$ == NULL)
 			YYERROR;
 	}
@@ -1098,7 +1114,7 @@
 	| property_name EQUAL TOKEN COMMA complex_piece 
 	{
 		$$ = complex_piece_func($1, $3, complex);
-		free($3);
+		free(claim_token($3));
 		if ($$ == NULL)
 			YYERROR;
 	}
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l	Thu Sep 09 11:46:43 2010 -0400
@@ -24,17 +24,37 @@
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+#include <assert.h>
 #include <string.h>
 #include <libintl.h>
 #include "zonecfg.h"
 #include "zonecfg_grammar.tab.h"
 
+/*
+ * This constant defines the number of entries added to unclaimed_tokens[]
+ * when it runs out of space.
+ */
+#define	UNCLAIMED_TOKENS_BUFFER_GROWTH	4
+
+/*
+ * Invariants:
+ *
+ *	unclaimed_tokens == NULL IFF unclaimed_tokens_size == 0
+ *	unclaimed_tokens_size == 0 IFF num_unclaimed_tokens == 0
+ */
+static char **unclaimed_tokens;		/* TOKENs produced by Lex (see below) */
+					/* but not claimed by YACC reduction */
+					/* rules */
+static unsigned int unclaimed_tokens_size;	/* size of unclaimed_tokens */
+static unsigned int num_unclaimed_tokens;	/* number of unclaimed TOKENs */
+
 int lex_lineno = 1;	/* line number for error reporting */
 static int state = INITIAL;
 extern boolean_t cmd_file_mode;
 extern boolean_t saw_error;
 extern void yyerror(char *s);
-char *safe_strdup(char *s);
+
+static char *create_token(char *s);
 %}
 
 %a 7000
@@ -323,29 +343,29 @@
 <CSTATE>","	{ return COMMA; }
 
 <TSTATE>[^ \t\n\";=\[\]\(\)]+	{
-			yylval.strval = safe_strdup(yytext);
+			yylval.strval = create_token(yytext);
 			return TOKEN;
 		}
 
 <LSTATE>[^ \t\n\",;=\[\]\(\)]+	{
-			yylval.strval = safe_strdup(yytext);
+			yylval.strval = create_token(yytext);
 			return TOKEN;
 		}
 
 <CSTATE>[^ \t\n\",;=\(\)]+	{
-			yylval.strval = safe_strdup(yytext);
+			yylval.strval = create_token(yytext);
 			return TOKEN;
 		}
 
 <TSTATE>\"[^\"\n]*[\"\n] {
-			yylval.strval = safe_strdup(yytext + 1);
+			yylval.strval = create_token(yytext + 1);
 			if (yylval.strval[yyleng - 2] == '"')
 				yylval.strval[yyleng - 2] = 0;
 			return TOKEN;
 		}
 
 <LSTATE>\"[^\"\n]*[\"\n] {
-			yylval.strval = safe_strdup(yytext + 1);
+			yylval.strval = create_token(yytext + 1);
 			if (yylval.strval[yyleng - 2] == '"')
 				yylval.strval[yyleng - 2] = 0;
 			return TOKEN;
@@ -370,8 +390,88 @@
 
 %%
 
+/*
+ * Assert that there are no unclaimed tokens.  This function enforces the
+ * invariants mentioned at the top of this file.
+ */
+void
+assert_no_unclaimed_tokens(void)
+{
+	assert(num_unclaimed_tokens == 0);
+	assert(unclaimed_tokens == NULL);
+	assert(unclaimed_tokens_size == 0);
+}
+
+/*
+ * Claim the specified unclaimed TOKEN.  YACC reduction rules that
+ * use TOKENs should invoke this function immediately before freeing the TOKENs
+ * or adding them to data structures that will be cleaned up when the YACC
+ * parser finishes or encounters errors.  Reduction rules should only claim the
+ * TOKENs that they use.
+ *
+ * This function returns its argument but does not free its memory.
+ */
 char *
-safe_strdup(char *s)
+claim_token(char *token)
+{
+	unsigned int index;
+
+	/*
+	 * Find the token in the list of unclaimed tokens.
+	 */
+	assert(num_unclaimed_tokens > 0);
+	for (index = 0; index < num_unclaimed_tokens; index++) {
+		if (unclaimed_tokens[index] == token)
+			break;
+	}
+
+	/*
+	 * Abort if we didn't find the token.
+	 */
+	assert(index != num_unclaimed_tokens);
+
+	/*
+	 * Replace the token with the last unclaimed token.
+	 */
+	num_unclaimed_tokens--;
+	unclaimed_tokens[index] = unclaimed_tokens[num_unclaimed_tokens];
+
+	/*
+	 * Delete the list of unclaimed tokens if it's empty.
+	 */
+	if (num_unclaimed_tokens == 0) {
+		free(unclaimed_tokens);
+		unclaimed_tokens = NULL;
+		unclaimed_tokens_size = 0;
+	}
+
+	return (token);
+}
+
+/*
+ * Free all unclaimed TOKENs.  This should only be invoked when the YACC
+ * parser encounters errors.
+ */
+static void
+free_tokens(void)
+{
+	if (unclaimed_tokens != NULL) {
+		while (num_unclaimed_tokens > 0)
+			free(unclaimed_tokens[--num_unclaimed_tokens]);
+		free(unclaimed_tokens);
+		unclaimed_tokens = NULL;
+		unclaimed_tokens_size = 0;
+	}
+	assert_no_unclaimed_tokens();
+}
+
+/*
+ * Create a TOKEN from the specified string.  The TOKEN is merely a duplicate
+ * of the specified string.  TOKENs must be claimed by the YACC reduction rules
+ * that use them; see claim_token() above.
+ */
+char *
+create_token(char *s)
 {
 	char *result;
 
@@ -379,12 +479,39 @@
 		yyerror("Out of memory");
 		exit(Z_ERR);
 	}
+
+	/*
+	 * Add the new TOKEN to the list of unclaimed TOKENs.  The list might
+	 * have to be resized.
+	 *
+	 * Reduction rules should claim TOKENs via claim_token() (see above).
+	 */
+	if (num_unclaimed_tokens == unclaimed_tokens_size) {
+		char **new_unclaimed_tokens;
+
+		unclaimed_tokens_size += UNCLAIMED_TOKENS_BUFFER_GROWTH;
+		new_unclaimed_tokens = (char **)realloc(unclaimed_tokens,
+		    unclaimed_tokens_size * sizeof (char *));
+		if (new_unclaimed_tokens == NULL) {
+			yyerror("Out of memory");
+			free(result);
+			exit(Z_ERR);
+		}
+		unclaimed_tokens = new_unclaimed_tokens;
+	}
+	unclaimed_tokens[num_unclaimed_tokens] = result;
+	num_unclaimed_tokens++;
 	return (result);
 }
 
 void
 yyerror(char *s)
 {
+	/*
+	 * Ensure that we won't leak unclaimed tokens.
+	 */
+	free_tokens();
+
 	/* feof(yyin) is not an error; anything else is, so we set saw_error */
 	if (yytext[0] == '\0') {
 		if (!feof(yyin)) {
--- a/usr/src/lib/libbsm/common/adt.xml	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/libbsm/common/adt.xml	Thu Sep 09 11:46:43 2010 -0400
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
-Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-Use is subject to license terms.
+Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 
 -->
 
@@ -2064,7 +2063,7 @@
     </event>
 
     <event id="AUE_ilb_create_healthcheck" header="0" idNo="120" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Create Integrated Loadbalancer healthcheck object</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2115,7 +2114,7 @@
     </event> 
 
     <event id="AUE_ilb_delete_healthcheck" header="0" idNo="121" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Delete Integrated Loadbalancer healthcheck object</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2138,12 +2137,8 @@
         </entry>
     </event>
 
-    <!--
-	virtual_address and proxy-src token are set to be char *.
-	But they should be in6_addr See audit bug 6864075 	.
-     -->
     <event id="AUE_ilb_create_rule" header="0" idNo="122" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Create Integrated Loadbalancer rule</title>
 	<program>/usr/sbin/ilbadm</program>
 	<see>ilbadm(1m)</see>
 	<entry id="subject">
@@ -2155,19 +2150,19 @@
 	    <external opt="required" type="char *"/>
 	    <comment>authorization used</comment>
 	</entry>
-	<entry id="virtual_ipaddress">
-	    <internal token="text"/>
-	    <external opt="required" type="char *"/>
+	<entry id="virtual_ipaddress_type,virtual_ipaddress">
+	    <internal token="in_remote"/>
+	    <external opt="required" type="int32_t,uint32_t[4]"/>
 	    <comment>LB virtual IP address</comment>
 	</entry>
 	<entry id="min_port">
-	    <internal token="text"/>
-	    <external opt="required" type="uint32_t"/>
+	    <internal token="iport"/>
+	    <external opt="required" type="uint16_t"/>
 	    <comment>minimum value in port range</comment>
 	</entry>
 	<entry id="max_port">
-	    <internal token="text"/>
-	    <external opt="required" type="uint32_t"/>
+	    <internal token="iport"/>
+	    <external opt="required" type="uint16_t"/>
 	    <comment>maximum value in port range - max=min means single
 		port is specified
 	    </comment>
@@ -2182,11 +2177,16 @@
             <external opt="required" type="char *"/>
             <comment>[rr,hip,hipp,hipv],[dsr,nat,half-nat]</comment>
         </entry>
-        <entry id="proxy_src">
-            <internal token="text"/>
-            <external opt="optional" type="char *"/>
-            <comment>proxy source address for NAT - may be single
-		address or a address range
+        <entry id="proxy_src_min_type,proxy_src_min">
+            <internal token="in_remote"/>
+            <external opt="optional" type="int32_t,uint32_t[4]"/>
+            <comment>min value for proxy source address for NAT</comment>
+        </entry>
+        <entry id="proxy_src_max_type,proxy_src_max">
+            <internal token="in_remote"/>
+            <external opt="optional" type="int32_t,uint32_t[4]"/>
+            <comment>max value in proxy source address range for NAT
+	          - max=min means single address is specified
 	    </comment>
         </entry>
         <entry id="persist_mask">
@@ -2269,31 +2269,27 @@
 <!--  instances of the ILB generic rule  event. -->
     <event id="AUE_ilb_delete_rule" instance_of="AUE_generic_ILB_rule"
         header="0" idNo="123">
-        <title>Integrated Loadbalancer</title>
+        <title>Delete Integrated Loadbalancer rule</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
     </event>
 
     <event id="AUE_ilb_disable_rule" instance_of="AUE_generic_ILB_rule"
         header="0" idNo="124">
-        <title>Integrated Loadbalancer</title>
+        <title>Disable Integrated Loadbalancer rule</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
     </event>
 
     <event id="AUE_ilb_enable_rule" instance_of="AUE_generic_ILB_rule"
         header="0" idNo="125">
-        <title>Integrated Loadbalancer</title>
+        <title>Enable Integrated Loadbalancer rule</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
     </event>
 
-    <!--
-	server_ipaddress token is set to be char *. But it should be
-	in6_addr See audit bug 6864075.
-     -->
     <event id="AUE_ilb_add_server" header="0" idNo="126" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Add server to Integrated Loadbalancer</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2305,9 +2301,9 @@
 	    <external opt="required" type="char *"/>
 	    <comment>authorization used</comment>
 	</entry>
-        <entry id="server_ipaddress">
-            <internal token="text"/>
-            <external opt="required" type="char *"/>
+        <entry id="server_ipaddress_type,server_ipaddress">
+            <internal token="in_remote"/>
+            <external opt="required" type="int32_t,uint32_t[4]"/>
             <comment>IP address</comment>
         </entry>
         <entry id="server_id">
@@ -2325,15 +2321,15 @@
             <comment>server group name</comment>
         </entry>
 	<entry id="server_minport">
-	    <internal token="text"/>
-	    <external opt="optional" type="uint32_t" />
+	    <internal token="iport"/>
+	    <external opt="optional" type="uint16_t" />
 	    <comment>server's minimum value in port range - empty
 		means default value (see man page)
 	    </comment>
 	</entry>
 	<entry id="server_maxport">
-	    <internal token="text"/>
-	    <external opt="optional" type="uint32_t" />
+	    <internal token="iport"/>
+	    <external opt="optional" type="uint16_t" />
 	    <comment>server's maximum value in port range - empty 
 		means default value(see man page)
 	    </comment>
@@ -2344,12 +2340,8 @@
         </entry>
     </event> 
 
-    <!--
-	server_ipaddress token is set to be char *. But it should be
-	in6_addr See audit bug 6864075.
-     -->
     <event id="AUE_ilb_disable_server" header="0" idNo="127" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Disable server to Integrated Loadbalancer</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2366,10 +2358,10 @@
             <external opt="required" type="char *"/>
             <comment>serverid</comment>
         </entry>
-        <entry id="server_ipaddress">
-            <internal token="text"/>
-            <external opt="optional" type="char *"/>
-            <comment>IPaddr corresponding to the serverid - empty
+        <entry id="server_ipaddress_type,server_ipaddress">
+            <internal token="in_remote"/>
+            <external opt="optional" type="int32_t,uint32_t[4]"/>
+            <comment>IPaddr corresponding to the serverid - empty 
 		if authorization fails, or user specified serverid
 		is nonexistent
 	    </comment>
@@ -2380,12 +2372,8 @@
         </entry>
     </event> 
 
-    <!--
-	server_ipaddress token is set to be char *. But it should be
-	in6_addr See audit bug 6864075.
-     -->
     <event id="AUE_ilb_enable_server" header="0" idNo="128" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Enable server to Integrated Loadbalancer</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2402,10 +2390,10 @@
             <external opt="required" type="char *"/>
             <comment>serverid</comment>
         </entry>
-        <entry id="server_ipaddress">
-            <internal token="text"/>
-            <external opt="optional" type="char *"/>
-            <comment>IPaddr corresponding to the serverid - empty
+        <entry id="server_ipaddress_type,server_ipaddress">
+            <internal token="in_remote"/>
+            <external opt="optional" type="int32_t,uint32_t[4]"/>
+            <comment>IPaddr corresponding to the serverid - empty 
 		if authorization fails, or user specified serverid
 		is nonexistent
 	    </comment>
@@ -2416,12 +2404,8 @@
         </entry>
     </event> 
 
-    <!--
-	server_ipaddress token is set to be char *. But it should be
-	in6_addr See audit bug 6864075 	.
-     -->
     <event id="AUE_ilb_remove_server" header="0" idNo="129" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Remove server from Integrated Loadbalancer</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2443,10 +2427,10 @@
             <external opt="required" type="char *"/>
             <comment>server group name</comment>
         </entry>
-        <entry id="server_ipaddress">
-            <internal token="text"/>
-            <external opt="optional" type="char *"/>
-            <comment>IPaddr corresponding to serverid - empty
+        <entry id="server_ipaddress_type,server_ipaddress">
+            <internal token="in_remote"/>
+            <external opt="optional" type="int32_t,uint32_t[4]"/>
+            <comment>IPaddr corresponding to serverid - empty 
 		if authorization fails or user specified serverid
 		serverid is nonexistent
 	    </comment>
@@ -2458,7 +2442,7 @@
     </event> 
 
     <event id="AUE_ilb_create_servergroup" header="0" idNo="130" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Create server group for Integrated Loadbalancer</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
@@ -2482,7 +2466,7 @@
     </event> 
 
     <event id="AUE_ilb_delete_servergroup" header="0" idNo="131" omit="JNI">
-        <title>Integrated Loadbalancer</title>
+        <title>Delete server group from Integrated Loadbalancer</title>
         <program>/usr/sbin/ilbadm</program>
         <see>ilbadm(1m)</see>
         <entry id="subject">
--- a/usr/src/lib/libnisdb/yptol/dit_access.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/libnisdb/yptol/dit_access.c	Thu Sep 09 11:46:43 2010 -0400
@@ -19,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * DESCRIPTION: Contains top level functions to read/write to the DIT. These
  *		are the API between the shim and the mapping system.
@@ -615,6 +612,16 @@
 	int			next_print = PRINT_FREQ;
 	int			search_flag = SUCCESS;
 
+	int			m;
+
+	/* list of maps whose keys will be transliterated to lowercase */
+	char			*xlate_to_lcase_maps[] = {
+		"hosts.byname",
+		"ipnodes.byname",
+		NULL
+	};
+	bool_t			xlate_to_lcase = FALSE;
+
 	if (!map || !map->map_name || !map->domain) {
 		return (FAILURE);
 	}
@@ -692,6 +699,20 @@
 		return (FAILURE);
 	}
 
+	/*
+	 * set xlate_to_lcase to TRUE if map_name is found in
+	 * xlate_to_lcase_maps[]
+	 */
+	m = 0;
+	while (xlate_to_lcase_maps[m] != NULL) {
+		if (strncmp(map->map_name, xlate_to_lcase_maps[m],
+			strlen(xlate_to_lcase_maps[m])) == 0) {
+			xlate_to_lcase = TRUE;
+			break;
+		}
+		++m;
+	}
+
 	/* Try each mapping for the map */
 	for (flag = 0; t != 0 && search_flag != FAILURE; t = t->next) {
 
@@ -802,7 +823,7 @@
 
 				/* Obtain the datum for key */
 				datkey = getKeyFromRuleValue(t, &rv[i],
-						&nv, &statP);
+				    &nv, &statP, xlate_to_lcase);
 				if (datkey == 0) {
 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
 						"%s: Unable to obtain NIS "
--- a/usr/src/lib/libnisdb/yptol/dit_access_utils.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/libnisdb/yptol/dit_access_utils.c	Thu Sep 09 11:46:43 2010 -0400
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * DESCRIPTION:	Contains dit_access interface support functions.
  */
@@ -55,6 +51,9 @@
 #include "yptol.h"
 #include "dit_access_utils.h"
 
+#define	YPMULTI		"YP_MULTI_"
+#define	YPMULTISZ	9		/* == strlen(YPMULTI) */
+
 /*
  * Returns 'map,domain.'
  */
@@ -852,8 +851,9 @@
 
 datum *
 getKeyFromRuleValue(__nis_table_mapping_t *t, __nis_rule_value_t *rv, int *nv,
-					int *statP) {
-	int	i, j;
+    int *statP, bool_t xlate_to_lcase)
+{
+	int	i, j, k;
 	datum	*key = 0;
 	char	*str;
 	char	*myself = "getKeyFromRuleValue";
@@ -868,7 +868,7 @@
 		if (rv->colName[i] == 0)
 			continue;
 		if (strcasecmp(N2LKEY, rv->colName[i]) == 0 ||
-				strcasecmp(N2LIPKEY, rv->colName[i]) == 0) {
+		    strcasecmp(N2LIPKEY, rv->colName[i]) == 0) {
 			if ((*nv = rv->colVal[i].numVals) == 0)
 				return (0);
 			if ((key = am(myself, sizeof (key[0]) * *nv)) == 0) {
@@ -881,15 +881,15 @@
 					key[j].dptr = 0;
 				} else {
 					if (verifyIndexMatch(t, 0, 0,
-							rv->colName[i],
-								str) == 0) {
+					    rv->colName[i], str) == 0) {
 						key[j].dsize = 0;
 						key[j].dptr = 0;
 						continue;
 					}
+
 					key[j].dsize = strlen(str);
 					key[j].dptr = am(myself,
-							key[j].dsize + 1);
+					    key[j].dsize + 1);
 					if (key[j].dptr == 0) {
 						*statP = MAP_NO_MEMORY;
 						for (--j; j >= 0; j--)
@@ -897,7 +897,33 @@
 						sfree(key);
 						return (0);
 					}
-					bcopy(str, key[j].dptr, key[j].dsize);
+
+					/* transliterate key to lowercase */
+					if (xlate_to_lcase == TRUE) {
+
+						/*
+						 * For multi-homed
+						 * entries, skip over
+						 * "YP_MULTI_" prefix.
+						 */
+						k = 0;
+						if (strncmp(YPMULTI, str,
+						    YPMULTISZ) == 0) {
+							k = YPMULTISZ;
+							bcopy(str, key[j].dptr,
+							    YPMULTISZ);
+						}
+						while (k < key[j].dsize) {
+							key[j].dptr[k] =
+							    (char)tolower(
+							    (int)(uchar_t)
+							    str[k]);
+							k++;
+						}
+					} else {
+						bcopy(str, key[j].dptr,
+						    key[j].dsize);
+					}
 				}
 			}
 			return (key);
--- a/usr/src/lib/libnisdb/yptol/dit_access_utils.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/libnisdb/yptol/dit_access_utils.h	Thu Sep 09 11:46:43 2010 -0400
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,15 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _DIT_ACCESS_UTILS_H
 #define	_DIT_ACCESS_UTILS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -73,7 +69,8 @@
 extern datum			*ruleValueToDatum(__nis_table_mapping_t *t,
 				__nis_rule_value_t *rv, int *statP);
 extern datum 			*getKeyFromRuleValue(__nis_table_mapping_t *t,
-				__nis_rule_value_t *rv, int *nv, int *statP);
+				__nis_rule_value_t *rv, int *nv, int *statP,
+				bool_t xlate_to_lcase);
 extern const char		*getObjectClass(char *rdn);
 extern suc_code			makeNISObject(char *domain, char *dn);
 extern suc_code			addNISObject(char *domain, char *dn,
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h	Thu Sep 09 11:46:43 2010 -0400
@@ -315,6 +315,7 @@
 #define	KM_PUSHPAGE		KM_SLEEP
 #define	KM_NOSLEEP		UMEM_DEFAULT
 #define	KMC_NODEBUG		UMC_NODEBUG
+#define	KMC_NOTOUCH		0	/* not needed for userland caches */
 #define	kmem_alloc(_s, _f)	umem_alloc(_s, _f)
 #define	kmem_zalloc(_s, _f)	umem_zalloc(_s, _f)
 #define	kmem_free(_b, _s)	umem_free(_b, _s)
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Thu Sep 09 11:46:43 2010 -0400
@@ -884,10 +884,6 @@
 int smb_kmod_start(int, int, int);
 void smb_kmod_stop(void);
 int smb_kmod_event_notify(uint32_t);
-int smb_kmod_tcplisten(int);
-int smb_kmod_nbtlisten(int);
-int smb_kmod_tcpreceive(void);
-int smb_kmod_nbtreceive(void);
 void smb_kmod_unbind(void);
 int smb_kmod_share(nvlist_t *);
 int smb_kmod_unshare(nvlist_t *);
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Thu Sep 09 11:46:43 2010 -0400
@@ -222,8 +222,6 @@
         smb_kmod_get_open_num;
 	smb_kmod_get_spool_doc;
 	smb_kmod_isbound;
-	smb_kmod_nbtlisten;
-	smb_kmod_nbtreceive;
 	smb_kmod_session_close;
 	smb_kmod_setcfg;
 	smb_kmod_setgmtoff;
@@ -231,8 +229,6 @@
 	smb_kmod_shareinfo;
 	smb_kmod_start;
 	smb_kmod_stop;
-	smb_kmod_tcplisten;
-	smb_kmod_tcpreceive;
 	smb_kmod_unbind;
 	smb_kmod_unshare;
 	smb_join;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Thu Sep 09 11:46:43 2010 -0400
@@ -136,40 +136,6 @@
 }
 
 int
-smb_kmod_tcplisten(int error)
-{
-	smb_ioc_listen_t ioc;
-
-	ioc.error = error;
-	return (smb_kmod_ioctl(SMB_IOC_TCP_LISTEN, &ioc.hdr, sizeof (ioc)));
-}
-
-int
-smb_kmod_nbtlisten(int error)
-{
-	smb_ioc_listen_t ioc;
-
-	ioc.error = error;
-	return (smb_kmod_ioctl(SMB_IOC_NBT_LISTEN, &ioc.hdr, sizeof (ioc)));
-}
-
-int
-smb_kmod_tcpreceive(void)
-{
-	smb_ioc_header_t ioc;
-
-	return (smb_kmod_ioctl(SMB_IOC_TCP_RECEIVE, &ioc, sizeof (ioc)));
-}
-
-int
-smb_kmod_nbtreceive(void)
-{
-	smb_ioc_header_t ioc;
-
-	return (smb_kmod_ioctl(SMB_IOC_NBT_RECEIVE, &ioc, sizeof (ioc)));
-}
-
-int
 smb_kmod_share(nvlist_t *shrlist)
 {
 	smb_ioc_share_t *ioc;
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c	Thu Sep 09 11:46:43 2010 -0400
@@ -261,18 +261,6 @@
 	case SMB_IOC_EVENT:
 		rc = smb_server_notify_event(&ioc->ioc_event);
 		break;
-	case SMB_IOC_NBT_LISTEN:
-		rc = smb_server_nbt_listen(&ioc->ioc_listen);
-		break;
-	case SMB_IOC_TCP_LISTEN:
-		rc = smb_server_tcp_listen(&ioc->ioc_listen);
-		break;
-	case SMB_IOC_NBT_RECEIVE:
-		rc = smb_server_nbt_receive();
-		break;
-	case SMB_IOC_TCP_RECEIVE:
-		rc = smb_server_tcp_receive();
-		break;
 	case SMB_IOC_GMTOFF:
 		rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
 		break;
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Thu Sep 09 11:46:43 2010 -0400
@@ -307,7 +307,7 @@
 	    sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
 
 	smb_thread_init(&smb_export.e_unexport_thread, "smb_thread_unexport",
-	    smb_kshare_unexport_thread, NULL, NULL, NULL);
+	    smb_kshare_unexport_thread, NULL);
 
 	if ((rc = smb_thread_start(&smb_export.e_unexport_thread)) != 0)
 		return (rc);
--- a/usr/src/uts/common/fs/smbsrv/smb_kutil.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_kutil.c	Thu Sep 09 11:46:43 2010 -0400
@@ -889,9 +889,7 @@
     smb_thread_t	*thread,
     char		*name,
     smb_thread_ep_t	ep,
-    void		*ep_arg,
-    smb_thread_aw_t	aw,
-    void		*aw_arg)
+    void		*ep_arg)
 {
 	ASSERT(thread->sth_magic != SMB_THREAD_MAGIC);
 
@@ -900,8 +898,6 @@
 	(void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name));
 	thread->sth_ep = ep;
 	thread->sth_ep_arg = ep_arg;
-	thread->sth_aw = aw;
-	thread->sth_aw_arg = aw_arg;
 	thread->sth_state = SMB_THREAD_STATE_EXITED;
 	mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL);
 	cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL);
@@ -968,8 +964,7 @@
  * state has been reached.
  */
 void
-smb_thread_stop(
-    smb_thread_t	*thread)
+smb_thread_stop(smb_thread_t *thread)
 {
 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
 
@@ -979,8 +974,6 @@
 	case SMB_THREAD_STATE_STARTING:
 		if (!thread->sth_kill) {
 			thread->sth_kill = B_TRUE;
-			if (thread->sth_aw)
-				thread->sth_aw(thread, thread->sth_aw_arg);
 			cv_broadcast(&thread->sth_cv);
 			while (thread->sth_state != SMB_THREAD_STATE_EXITING)
 				cv_wait(&thread->sth_cv, &thread->sth_mtx);
@@ -1021,16 +1014,13 @@
  * This function signals a thread.
  */
 void
-smb_thread_signal(
-    smb_thread_t	*thread)
+smb_thread_signal(smb_thread_t *thread)
 {
 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
 
 	mutex_enter(&thread->sth_mtx);
 	switch (thread->sth_state) {
 	case SMB_THREAD_STATE_RUNNING:
-		if (thread->sth_aw)
-			thread->sth_aw(thread, thread->sth_aw_arg);
 		cv_signal(&thread->sth_cv);
 		break;
 
@@ -1112,18 +1102,6 @@
 	return (result);
 }
 
-void
-smb_thread_set_awaken(smb_thread_t *thread, smb_thread_aw_t new_aw_fn,
-    void *new_aw_arg)
-{
-	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
-
-	mutex_enter(&thread->sth_mtx);
-	thread->sth_aw = new_aw_fn;
-	thread->sth_aw_arg = new_aw_arg;
-	mutex_exit(&thread->sth_mtx);
-}
-
 /*
  * smb_rwx_init
  */
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c	Thu Sep 09 11:46:43 2010 -0400
@@ -140,8 +140,7 @@
 	    offsetof(smb_request_t, sr_ncr.nc_lnd));
 
 	smb_thread_init(&smb_thread_notify_daemon,
-	    "smb_notify_change_daemon", smb_notify_change_daemon, NULL,
-	    NULL, NULL);
+	    "smb_notify_change_daemon", smb_notify_change_daemon, NULL);
 
 	rc = smb_thread_start(&smb_thread_notify_daemon);
 	if (rc) {
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Thu Sep 09 11:46:43 2010 -0400
@@ -98,7 +98,7 @@
 	    offsetof(smb_oplock_break_t, ob_lnd));
 
 	smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break",
-	    smb_oplock_break_thread, NULL, NULL, NULL);
+	    smb_oplock_break_thread, NULL);
 
 	rc = smb_thread_start(&smb_oplock_thread);
 	if (rc != 0) {
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Thu Sep 09 11:46:43 2010 -0400
@@ -148,21 +148,11 @@
  * SMB_SERVER_STATE_RUNNING
  *
  *    The server has been started. While in this state the threads listening on
- *    the sockets car be started. The smbd daemon does so through an Ioctl:
- *
- *	smb_drv_ioctl(SMB_IOC_NBT_LISTEN) --> smb_server_nbt_listen()
- *	smb_drv_ioctl(SMB_IOC_TCP_LISTEN) --> smb_server_nbt_listen()
+ *    the sockets are started.
  *
- *    When a client establishes a connection the thread listening leaves
- *    temporarily the kernel. While in user space it creates a thread for the
- *    new session. It then returns to kernel with the result of the thread
- *    creation. If the creation failed the new session context is destroyed
- *    before returning listening.
- *
- *    The new created thread enters the kernel though an Ioctl:
- *
- *	smb_drv_ioctl(SMB_IOC_NBT_RECEIVE) --> smb_server_nbt_receive()
- *	smb_drv_ioctl(SMB_IOC_TCP_RECEIVE) --> smb_server_tcp_receive()
+ *    When a client establishes a connection the thread listening dispatches
+ *    a task with the new session as an argument. If the dispatch fails the new
+ *    session context is destroyed.
  *
  * SMB_SERVER_STATE_STOPPING
  *
@@ -231,30 +221,40 @@
 
 extern void smb_reply_notify_change_request(smb_request_t *);
 
+typedef struct {
+	smb_listener_daemon_t	*ra_listener;
+	smb_session_t		*ra_session;
+} smb_receiver_arg_t;
+
 static void smb_server_kstat_init(smb_server_t *);
 static void smb_server_kstat_fini(smb_server_t *);
 static void smb_server_timers(smb_thread_t *, void *);
-static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *,
-    in_port_t, int, int);
-static void smb_server_listen_fini(smb_listener_daemon_t *);
-static kt_did_t smb_server_listener_tid(smb_listener_daemon_t *);
 static int smb_server_lookup(smb_server_t **);
 static void smb_server_release(smb_server_t *);
 static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
 static void smb_server_shutdown(smb_server_t *);
 static int smb_server_fsop_start(smb_server_t *);
 static void smb_server_fsop_stop(smb_server_t *);
-static void smb_server_signal_listeners(smb_server_t *);
 static void smb_event_cancel(smb_server_t *, uint32_t);
 static uint32_t smb_event_alloc_txid(void);
 
-static void smb_server_disconnect_share(smb_session_list_t *, const char *);
-static void smb_server_enum_private(smb_session_list_t *, smb_svcenum_t *);
-static int smb_server_sesion_disconnect(smb_session_list_t *, const char *,
+static void smb_server_disconnect_share(smb_llist_t *, const char *);
+static void smb_server_enum_private(smb_llist_t *, smb_svcenum_t *);
+static int smb_server_session_disconnect(smb_llist_t *, const char *,
     const char *);
-static int smb_server_fclose(smb_session_list_t *, uint32_t);
+static int smb_server_fclose(smb_llist_t *, uint32_t);
 static int smb_server_kstat_update(kstat_t *, int);
 static int smb_server_legacy_kstat_update(kstat_t *, int);
+static void smb_server_listener_init(smb_server_t *, smb_listener_daemon_t *,
+    char *, in_port_t, int);
+static void smb_server_listener_destroy(smb_listener_daemon_t *);
+static int smb_server_listener_start(smb_listener_daemon_t *);
+static void smb_server_listener_stop(smb_listener_daemon_t *);
+static void smb_server_listener(smb_thread_t *, void *);
+static void smb_server_receiver(void *);
+static void smb_server_create_session(smb_listener_daemon_t *, ksocket_t);
+static void smb_server_destroy_session(smb_listener_daemon_t *,
+    smb_session_t *);
 
 int smb_event_debug = 0;
 
@@ -379,9 +379,6 @@
 	smb_llist_constructor(&sv->sp_info.sp_fidlist,
 	    sizeof (smb_spoolfid_t), offsetof(smb_spoolfid_t, sf_lnd));
 
-	smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list);
-	smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list);
-
 	sv->si_cache_request = kmem_cache_create("smb_request_cache",
 	    sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
 	sv->si_cache_session = kmem_cache_create("smb_session_cache",
@@ -400,8 +397,7 @@
 	    sizeof (smb_event_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
 
 	smb_thread_init(&sv->si_thread_timers,
-	    "smb_timers", smb_server_timers, sv,
-	    NULL, NULL);
+	    "smb_timers", smb_server_timers, sv);
 
 	sv->sv_pid = curproc->p_pid;
 	smb_srqueue_init(&sv->sv_srqueue);
@@ -442,8 +438,6 @@
 smb_server_delete(void)
 {
 	smb_server_t	*sv;
-	kt_did_t	nbt_tid;
-	kt_did_t	tcp_tid;
 	int		rc;
 
 	rc = smb_server_lookup(&sv);
@@ -457,24 +451,15 @@
 	mutex_enter(&sv->sv_mutex);
 	switch (sv->sv_state) {
 	case SMB_SERVER_STATE_RUNNING:
-	case SMB_SERVER_STATE_STOPPING:
 		sv->sv_state = SMB_SERVER_STATE_STOPPING;
-		smb_server_signal_listeners(sv);
-		nbt_tid = smb_server_listener_tid(&sv->sv_nbt_daemon);
-		tcp_tid = smb_server_listener_tid(&sv->sv_tcp_daemon);
-		cv_broadcast(&sv->sp_info.sp_cv);
-
-		sv->sv_state = SMB_SERVER_STATE_DELETING;
 		mutex_exit(&sv->sv_mutex);
-
-		if (nbt_tid != 0)
-			thread_join(nbt_tid);
-		if (tcp_tid != 0)
-			thread_join(tcp_tid);
-
-		smb_server_listen_fini(&sv->sv_nbt_daemon);
-		smb_server_listen_fini(&sv->sv_tcp_daemon);
+		smb_server_shutdown(sv);
 		mutex_enter(&sv->sv_mutex);
+		cv_broadcast(&sv->sp_info.sp_cv);
+		sv->sv_state = SMB_SERVER_STATE_DELETING;
+		break;
+	case SMB_SERVER_STATE_STOPPING:
+		sv->sv_state = SMB_SERVER_STATE_DELETING;
 		break;
 	case SMB_SERVER_STATE_CONFIGURED:
 	case SMB_SERVER_STATE_CREATED:
@@ -499,7 +484,8 @@
 	smb_llist_remove(&smb_servers, sv);
 	smb_llist_exit(&smb_servers);
 
-	smb_server_shutdown(sv);
+	smb_server_listener_destroy(&sv->sv_nbt_daemon);
+	smb_server_listener_destroy(&sv->sv_tcp_daemon);
 	rw_destroy(&sv->sv_cfg_lock);
 	smb_opipe_door_fini();
 	smb_kdoor_fini();
@@ -577,6 +563,7 @@
 smb_server_start(smb_ioc_start_t *ioc)
 {
 	int		rc = 0;
+	int		family;
 	smb_server_t	*sv;
 
 	rc = smb_server_lookup(&sv);
@@ -588,14 +575,19 @@
 	case SMB_SERVER_STATE_CONFIGURED:
 		smb_codepage_init();
 
-		sv->sv_thread_pool = taskq_create("smb_workers",
+		sv->sv_worker_pool = taskq_create("smb_workers",
 		    sv->sv_cfg.skc_maxworkers, SMB_WORKER_PRIORITY,
 		    sv->sv_cfg.skc_maxworkers, INT_MAX,
 		    TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
 
+		sv->sv_receiver_pool = taskq_create("smb_receivers",
+		    sv->sv_cfg.skc_maxconnections, SMB_WORKER_PRIORITY,
+		    sv->sv_cfg.skc_maxconnections, INT_MAX,
+		    TASKQ_DYNAMIC);
+
 		sv->sv_session = smb_session_create(NULL, 0, sv, 0);
 
-		if (sv->sv_thread_pool == NULL || sv->sv_session == NULL) {
+		if (sv->sv_worker_pool == NULL || sv->sv_session == NULL) {
 			rc = ENOMEM;
 			break;
 		}
@@ -616,11 +608,25 @@
 		}
 		if (rc = smb_thread_start(&sv->si_thread_timers))
 			break;
+
+		family = AF_INET;
+		smb_server_listener_init(sv, &sv->sv_nbt_daemon,
+		    "smb_nbt_listener", IPPORT_NETBIOS_SSN, family);
+		if (sv->sv_cfg.skc_ipv6_enable)
+			family = AF_INET6;
+		smb_server_listener_init(sv, &sv->sv_tcp_daemon,
+		    "smb_tcp_listener", IPPORT_SMB, family);
+		rc = smb_server_listener_start(&sv->sv_nbt_daemon);
+		if (rc != 0)
+			break;
+		rc = smb_server_listener_start(&sv->sv_tcp_daemon);
+		if (rc != 0)
+			break;
+
 		sv->sv_state = SMB_SERVER_STATE_RUNNING;
 		sv->sv_start_time = gethrtime();
 		mutex_exit(&sv->sv_mutex);
 		smb_server_release(sv);
-
 		smb_export_start();
 		return (0);
 	default:
@@ -630,8 +636,8 @@
 		return (ENOTTY);
 	}
 
+	mutex_exit(&sv->sv_mutex);
 	smb_server_shutdown(sv);
-	mutex_exit(&sv->sv_mutex);
 	smb_server_release(sv);
 	return (rc);
 }
@@ -652,7 +658,9 @@
 	switch (sv->sv_state) {
 	case SMB_SERVER_STATE_RUNNING:
 		sv->sv_state = SMB_SERVER_STATE_STOPPING;
-		smb_server_signal_listeners(sv);
+		mutex_exit(&sv->sv_mutex);
+		smb_server_shutdown(sv);
+		mutex_enter(&sv->sv_mutex);
 		cv_broadcast(&sv->sp_info.sp_cv);
 		break;
 	default:
@@ -722,148 +730,6 @@
 }
 
 /*
- * SMB-over-NetBIOS (port 139)
- *
- * Traditional SMB service over NetBIOS, which requires that a NetBIOS
- * session be established.
- */
-int
-smb_server_nbt_listen(smb_ioc_listen_t *ioc)
-{
-	smb_server_t	*sv;
-	int		rc;
-
-	rc = smb_server_lookup(&sv);
-	if (rc)
-		return (rc);
-
-	mutex_enter(&sv->sv_mutex);
-	switch (sv->sv_state) {
-	case SMB_SERVER_STATE_RUNNING:
-		if ((sv->sv_nbt_daemon.ld_kth != NULL) &&
-		    (sv->sv_nbt_daemon.ld_kth != curthread)) {
-			mutex_exit(&sv->sv_mutex);
-			smb_server_release(sv);
-			return (EACCES);
-		} else {
-			sv->sv_nbt_daemon.ld_kth = curthread;
-			sv->sv_nbt_daemon.ld_ktdid = curthread->t_did;
-		}
-		break;
-	case SMB_SERVER_STATE_STOPPING:
-		mutex_exit(&sv->sv_mutex);
-		smb_server_release(sv);
-		return (ECANCELED);
-	default:
-		SMB_SERVER_STATE_VALID(sv->sv_state);
-		mutex_exit(&sv->sv_mutex);
-		smb_server_release(sv);
-		return (EFAULT);
-	}
-	mutex_exit(&sv->sv_mutex);
-
-	/*
-	 * netbios must be ipv4
-	 */
-	rc = smb_server_listen(sv, &sv->sv_nbt_daemon, IPPORT_NETBIOS_SSN,
-	    AF_INET, ioc->error);
-
-	mutex_enter(&sv->sv_mutex);
-	sv->sv_nbt_daemon.ld_kth = NULL;
-	mutex_exit(&sv->sv_mutex);
-
-	smb_server_release(sv);
-	return (rc);
-}
-
-/*
- *  SMB-over-TCP (port 445)
- */
-int
-smb_server_tcp_listen(smb_ioc_listen_t *ioc)
-{
-	smb_server_t	*sv;
-	int		rc;
-
-	rc = smb_server_lookup(&sv);
-	if (rc)
-		return (rc);
-
-	mutex_enter(&sv->sv_mutex);
-	switch (sv->sv_state) {
-	case SMB_SERVER_STATE_RUNNING:
-		if ((sv->sv_tcp_daemon.ld_kth != NULL) &&
-		    (sv->sv_tcp_daemon.ld_kth != curthread)) {
-			mutex_exit(&sv->sv_mutex);
-			smb_server_release(sv);
-			return (EACCES);
-		} else {
-			sv->sv_tcp_daemon.ld_kth = curthread;
-			sv->sv_tcp_daemon.ld_ktdid = curthread->t_did;
-		}
-		break;
-	case SMB_SERVER_STATE_STOPPING:
-		mutex_exit(&sv->sv_mutex);
-		smb_server_release(sv);
-		return (ECANCELED);
-	default:
-		SMB_SERVER_STATE_VALID(sv->sv_state);
-		mutex_exit(&sv->sv_mutex);
-		smb_server_release(sv);
-		return (EFAULT);
-	}
-	mutex_exit(&sv->sv_mutex);
-
-	if (sv->sv_cfg.skc_ipv6_enable)
-		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
-		    IPPORT_SMB, AF_INET6, ioc->error);
-	else
-		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
-		    IPPORT_SMB, AF_INET, ioc->error);
-
-	mutex_enter(&sv->sv_mutex);
-	sv->sv_tcp_daemon.ld_kth = NULL;
-	mutex_exit(&sv->sv_mutex);
-
-	smb_server_release(sv);
-	return (rc);
-}
-
-/*
- * smb_server_nbt_receive
- */
-int
-smb_server_nbt_receive(void)
-{
-	int		rc;
-	smb_server_t	*sv;
-
-	if ((rc = smb_server_lookup(&sv)) == 0) {
-		rc = smb_session_daemon(&sv->sv_nbt_daemon.ld_session_list);
-		smb_server_release(sv);
-	}
-
-	return (rc);
-}
-
-/*
- * smb_server_tcp_receive
- */
-int
-smb_server_tcp_receive(void)
-{
-	int		rc;
-	smb_server_t	*sv;
-
-	if ((rc = smb_server_lookup(&sv)) == 0) {
-		rc = smb_session_daemon(&sv->sv_tcp_daemon.ld_session_list);
-		smb_server_release(sv);
-	}
-
-	return (rc);
-}
-
-/*
  * smb_server_spooldoc
  *
  * Waits for print file close broadcast.
@@ -947,10 +813,9 @@
 int
 smb_server_enum(smb_ioc_svcenum_t *ioc)
 {
-	smb_svcenum_t		*svcenum = &ioc->svcenum;
-	smb_server_t		*sv;
-	smb_session_list_t	*se;
-	int			rc;
+	smb_svcenum_t	*svcenum = &ioc->svcenum;
+	smb_server_t	*sv;
+	int		rc;
 
 	switch (svcenum->se_type) {
 	case SMB_SVCENUM_TYPE_USER:
@@ -968,11 +833,8 @@
 	svcenum->se_bused = 0;
 	svcenum->se_nitems = 0;
 
-	se = &sv->sv_nbt_daemon.ld_session_list;
-	smb_server_enum_private(se, svcenum);
-
-	se = &sv->sv_tcp_daemon.ld_session_list;
-	smb_server_enum_private(se, svcenum);
+	smb_server_enum_private(&sv->sv_nbt_daemon.ld_session_list, svcenum);
+	smb_server_enum_private(&sv->sv_tcp_daemon.ld_session_list, svcenum);
 
 	smb_server_release(sv);
 	return (0);
@@ -984,20 +846,20 @@
 int
 smb_server_session_close(smb_ioc_session_t *ioc)
 {
-	smb_session_list_t	*se;
-	smb_server_t		*sv;
-	int			nbt_cnt;
-	int			tcp_cnt;
-	int			rc;
+	smb_llist_t	*ll;
+	smb_server_t	*sv;
+	int		nbt_cnt;
+	int		tcp_cnt;
+	int		rc;
 
 	if ((rc = smb_server_lookup(&sv)) != 0)
 		return (rc);
 
-	se = &sv->sv_nbt_daemon.ld_session_list;
-	nbt_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
+	ll = &sv->sv_nbt_daemon.ld_session_list;
+	nbt_cnt = smb_server_session_disconnect(ll, ioc->client, ioc->username);
 
-	se = &sv->sv_tcp_daemon.ld_session_list;
-	tcp_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
+	ll = &sv->sv_tcp_daemon.ld_session_list;
+	tcp_cnt = smb_server_session_disconnect(ll, ioc->client, ioc->username);
 
 	smb_server_release(sv);
 
@@ -1012,20 +874,20 @@
 int
 smb_server_file_close(smb_ioc_fileid_t *ioc)
 {
-	uint32_t		uniqid = ioc->uniqid;
-	smb_session_list_t	*se;
-	smb_server_t		*sv;
-	int			rc;
+	uint32_t	uniqid = ioc->uniqid;
+	smb_llist_t	*ll;
+	smb_server_t	*sv;
+	int		rc;
 
 	if ((rc = smb_server_lookup(&sv)) != 0)
 		return (rc);
 
-	se = &sv->sv_nbt_daemon.ld_session_list;
-	rc = smb_server_fclose(se, uniqid);
+	ll = &sv->sv_nbt_daemon.ld_session_list;
+	rc = smb_server_fclose(ll, uniqid);
 
 	if (rc == ENOENT) {
-		se = &sv->sv_tcp_daemon.ld_session_list;
-		rc = smb_server_fclose(se, uniqid);
+		ll = &sv->sv_tcp_daemon.ld_session_list;
+		rc = smb_server_fclose(ll, uniqid);
 	}
 
 	smb_server_release(sv);
@@ -1045,12 +907,8 @@
 	if (smb_server_lookup(&sv))
 		return (0);
 
-	rw_enter(&sv->sv_nbt_daemon.ld_session_list.se_lock, RW_READER);
-	counter = sv->sv_nbt_daemon.ld_session_list.se_act.count;
-	rw_exit(&sv->sv_nbt_daemon.ld_session_list.se_lock);
-	rw_enter(&sv->sv_tcp_daemon.ld_session_list.se_lock, RW_READER);
-	counter += sv->sv_tcp_daemon.ld_session_list.se_act.count;
-	rw_exit(&sv->sv_tcp_daemon.ld_session_list.se_lock);
+	counter = smb_llist_get_count(&sv->sv_nbt_daemon.ld_session_list);
+	counter += smb_llist_get_count(&sv->sv_tcp_daemon.ld_session_list);
 
 	smb_server_release(sv);
 
@@ -1155,9 +1013,9 @@
 int
 smb_server_unshare(const char *sharename)
 {
-	smb_server_t		*sv;
-	smb_session_list_t	*slist;
-	int			rc;
+	smb_server_t	*sv;
+	smb_llist_t	*ll;
+	int		rc;
 
 	if ((rc = smb_server_lookup(&sv)))
 		return (rc);
@@ -1174,11 +1032,11 @@
 	}
 	mutex_exit(&sv->sv_mutex);
 
-	slist = &sv->sv_nbt_daemon.ld_session_list;
-	smb_server_disconnect_share(slist, sharename);
+	ll = &sv->sv_nbt_daemon.ld_session_list;
+	smb_server_disconnect_share(ll, sharename);
 
-	slist = &sv->sv_tcp_daemon.ld_session_list;
-	smb_server_disconnect_share(slist, sharename);
+	ll = &sv->sv_tcp_daemon.ld_session_list;
+	smb_server_disconnect_share(ll, sharename);
 
 	smb_server_release(sv);
 	return (0);
@@ -1189,15 +1047,15 @@
  * Typically called when a share has been removed.
  */
 static void
-smb_server_disconnect_share(smb_session_list_t *slist, const char *sharename)
+smb_server_disconnect_share(smb_llist_t *ll, const char *sharename)
 {
-	smb_session_t		*session;
+	smb_session_t	*session;
 
-	rw_enter(&slist->se_lock, RW_READER);
+	smb_llist_enter(ll, RW_READER);
 
-	session = list_head(&slist->se_act.lst);
+	session = smb_llist_head(ll);
 	while (session) {
-		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+		SMB_SESSION_VALID(session);
 		smb_rwx_rwenter(&session->s_lock, RW_READER);
 		switch (session->s_state) {
 		case SMB_SESSION_STATE_NEGOTIATED:
@@ -1209,10 +1067,10 @@
 			break;
 		}
 		smb_rwx_rwexit(&session->s_lock);
-		session = list_next(&slist->se_act.lst, session);
+		session = smb_llist_next(ll, session);
 	}
 
-	rw_exit(&slist->se_lock);
+	smb_llist_exit(ll);
 }
 
 /*
@@ -1522,7 +1380,7 @@
 }
 
 /*
- * The mutex of the server must have been entered before calling this function.
+ * smb_server_shutdown
  */
 static void
 smb_server_shutdown(smb_server_t *sv)
@@ -1537,110 +1395,185 @@
 	smb_export_stop();
 	smb_server_fsop_stop(sv);
 
-	if (sv->sv_session) {
+	smb_server_listener_stop(&sv->sv_nbt_daemon);
+	smb_server_listener_stop(&sv->sv_tcp_daemon);
+
+	if (sv->sv_session != NULL) {
 		smb_session_delete(sv->sv_session);
 		sv->sv_session = NULL;
 	}
 
-	if (sv->sv_thread_pool) {
-		taskq_destroy(sv->sv_thread_pool);
-		sv->sv_thread_pool = NULL;
+	if (sv->sv_receiver_pool != NULL) {
+		taskq_destroy(sv->sv_receiver_pool);
+		sv->sv_receiver_pool = NULL;
+	}
+
+	if (sv->sv_worker_pool != NULL) {
+		taskq_destroy(sv->sv_worker_pool);
+		sv->sv_worker_pool = NULL;
 	}
 }
 
-static int
-smb_server_listen(
+/*
+ * smb_server_listener_init
+ *
+ * Initializes listener contexts.
+ */
+static void
+smb_server_listener_init(
     smb_server_t		*sv,
     smb_listener_daemon_t	*ld,
+    char			*name,
     in_port_t			port,
-    int				family,
-    int				pthread_create_error)
+    int				family)
 {
-	int			rc = 0;
-	ksocket_t		s_so;
-	uint32_t		on;
-	uint32_t		off;
-	uint32_t		txbuf_size;
-	smb_session_t		*session;
+	ASSERT(ld->ld_magic != SMB_LISTENER_MAGIC);
+
+	bzero(ld, sizeof (*ld));
+
+	ld->ld_sv = sv;
+	ld->ld_family = family;
+	ld->ld_port = port;
 
-	if (pthread_create_error) {
-		/*
-		 * Delete the last session created. The user space thread
-		 * creation failed.
-		 */
-		smb_session_list_delete_tail(&ld->ld_session_list);
+	if (family == AF_INET) {
+		ld->ld_sin.sin_family = (uint32_t)family;
+		ld->ld_sin.sin_port = htons(port);
+		ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
+	} else {
+		ld->ld_sin6.sin6_family = (uint32_t)family;
+		ld->ld_sin6.sin6_port = htons(port);
+		(void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0,
+		    sizeof (ld->ld_sin6.sin6_addr.s6_addr));
 	}
 
+	smb_llist_constructor(&ld->ld_session_list, sizeof (smb_session_t),
+	    offsetof(smb_session_t, s_lnd));
+	smb_thread_init(&ld->ld_thread, name, smb_server_listener, ld);
+	ld->ld_magic = SMB_LISTENER_MAGIC;
+}
+
+/*
+ * smb_server_listener_destroy
+ *
+ * Destroyes listener contexts.
+ */
+static void
+smb_server_listener_destroy(smb_listener_daemon_t *ld)
+{
+	SMB_LISTENER_VALID(ld);
+	ASSERT(ld->ld_so == NULL);
+	smb_thread_destroy(&ld->ld_thread);
+	smb_llist_destructor(&ld->ld_session_list);
+	ld->ld_magic = 0;
+}
+
+/*
+ * smb_server_listener_start
+ *
+ * Starts the listener associated with the context passed in.
+ *
+ * Return:	0	Success
+ *		not 0	Failure
+ */
+static int
+smb_server_listener_start(smb_listener_daemon_t *ld)
+{
+	int		rc;
+	uint32_t	on;
+	uint32_t	off;
+
+	SMB_LISTENER_VALID(ld);
+
+	if (ld->ld_so != NULL)
+		return (EINVAL);
+
+	ld->ld_so = smb_socreate(ld->ld_family, SOCK_STREAM, 0);
 	if (ld->ld_so == NULL) {
-		/* First time listener */
-		if (family == AF_INET) {
-			ld->ld_sin.sin_family = (uint32_t)family;
-			ld->ld_sin.sin_port = htons(port);
-			ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
-		} else {
-			ld->ld_sin6.sin6_family = (uint32_t)family;
-			ld->ld_sin6.sin6_port = htons(port);
-			(void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0,
-			    sizeof (ld->ld_sin6.sin6_addr.s6_addr));
-		}
+		cmn_err(CE_WARN, "port %d: socket create failed", ld->ld_port);
+		return (ENOMEM);
+	}
 
-		ld->ld_so = smb_socreate(family, SOCK_STREAM, 0);
-		if (ld->ld_so == NULL) {
-			cmn_err(CE_WARN, "port %d: socket create failed", port);
-			return (ENOMEM);
-		}
+	off = 0;
+	(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
+	    SO_MAC_EXEMPT, &off, sizeof (off), CRED());
 
-		off = 0;
-		(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
-		    SO_MAC_EXEMPT, &off, sizeof (off), CRED());
+	on = 1;
+	(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
+	    SO_REUSEADDR, &on, sizeof (on), CRED());
 
-		on = 1;
-		(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
-		    SO_REUSEADDR, &on, sizeof (on), CRED());
+	if (ld->ld_family == AF_INET) {
+		rc = ksocket_bind(ld->ld_so,
+		    (struct sockaddr *)&ld->ld_sin,
+		    sizeof (ld->ld_sin), CRED());
+	} else {
+		rc = ksocket_bind(ld->ld_so,
+		    (struct sockaddr *)&ld->ld_sin6,
+		    sizeof (ld->ld_sin6), CRED());
+	}
+
+	if (rc != 0) {
+		cmn_err(CE_WARN, "port %d: bind failed", ld->ld_port);
+		return (rc);
+	}
 
-		if (family == AF_INET) {
-			rc = ksocket_bind(ld->ld_so,
-			    (struct sockaddr *)&ld->ld_sin,
-			    sizeof (ld->ld_sin), CRED());
-		} else {
-			rc = ksocket_bind(ld->ld_so,
-			    (struct sockaddr *)&ld->ld_sin6,
-			    sizeof (ld->ld_sin6), CRED());
-		}
+	rc =  ksocket_listen(ld->ld_so, 20, CRED());
+	if (rc < 0) {
+		cmn_err(CE_WARN, "port %d: listen failed", ld->ld_port);
+		return (rc);
+	}
+
+	ksocket_hold(ld->ld_so);
+	rc = smb_thread_start(&ld->ld_thread);
+	if (rc != 0) {
+		ksocket_rele(ld->ld_so);
+		cmn_err(CE_WARN, "port %d: listener failed to start",
+		    ld->ld_port);
+		return (rc);
+	}
+	return (0);
+}
 
-		if (rc != 0) {
-			cmn_err(CE_WARN, "port %d: bind failed (%d)", port, rc);
-			smb_server_listen_fini(ld);
-			return (rc);
-		}
+/*
+ * smb_server_listener_stop
+ *
+ * Stops the listener associated with the context passed in.
+ */
+static void
+smb_server_listener_stop(smb_listener_daemon_t *ld)
+{
+	SMB_LISTENER_VALID(ld);
+
+	if (ld->ld_so != NULL) {
+		smb_soshutdown(ld->ld_so);
+		smb_sodestroy(ld->ld_so);
+		smb_thread_stop(&ld->ld_thread);
+		ld->ld_so = NULL;
+	}
+}
 
-		rc =  ksocket_listen(ld->ld_so, 20, CRED());
-		if (rc < 0) {
-			cmn_err(CE_WARN, "port %d: listen failed", port);
-			smb_server_listen_fini(ld);
-			return (rc);
-		}
-	}
+/*
+ * smb_server_listener
+ *
+ * Entry point of the listeners.
+ */
+static void
+smb_server_listener(smb_thread_t *thread, void *arg)
+{
+	_NOTE(ARGUNUSED(thread))
+	smb_listener_daemon_t	*ld;
+	smb_session_t		*session;
+	ksocket_t		s_so;
+	int			on;
+	int			txbuf_size;
+
+	ld = (smb_listener_daemon_t *)arg;
+
+	SMB_LISTENER_VALID(ld);
 
 	DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so);
 
-	for (;;) {
-		if (smb_server_is_stopping()) {
-			rc = ECANCELED;
-			break;
-		}
-
-		rc = ksocket_accept(ld->ld_so, NULL, NULL, &s_so, CRED());
-		if (rc != 0)
-			break;
-
-		if (smb_server_is_stopping()) {
-			smb_soshutdown(s_so);
-			smb_sodestroy(s_so);
-			rc = ECANCELED;
-			break;
-		}
-
+	while (ksocket_accept(ld->ld_so, NULL, NULL, &s_so, CRED())
+	    == 0) {
 		DTRACE_PROBE1(so__accept, struct sonode *, s_so);
 
 		on = 1;
@@ -1658,45 +1591,35 @@
 		/*
 		 * Create a session for this connection.
 		 */
-		session = smb_session_create(s_so, port, sv, family);
-		if (session) {
-			smb_session_list_append(&ld->ld_session_list, session);
-			rc = 0;
-			break;
-		} else {
-			smb_soshutdown(s_so);
-			smb_sodestroy(s_so);
-		}
+		smb_server_create_session(ld, s_so);
 	}
-
-	if (rc != 0)
-		smb_server_listen_fini(ld);
-
-	return (rc);
+	/* Disconnect all the sessions this listener created. */
+	smb_llist_enter(&ld->ld_session_list, RW_READER);
+	session = smb_llist_head(&ld->ld_session_list);
+	while (session != NULL) {
+		smb_session_disconnect(session);
+		session = smb_llist_next(&ld->ld_session_list, session);
+	}
+	smb_llist_exit(&ld->ld_session_list);
+	ksocket_rele(ld->ld_so);
 }
 
+/*
+ * smb_server_receiver
+ *
+ * Entry point of the receiver threads.
+ */
 static void
-smb_server_listen_fini(smb_listener_daemon_t *ld)
+smb_server_receiver(void *arg)
 {
-	if (ld->ld_so != NULL) {
-		smb_session_list_signal(&ld->ld_session_list);
-		smb_soshutdown(ld->ld_so);
-		smb_sodestroy(ld->ld_so);
-		ld->ld_so = NULL;
-	}
-}
+	smb_listener_daemon_t	*ld;
+	smb_session_t		*session;
 
-static kt_did_t
-smb_server_listener_tid(smb_listener_daemon_t *ld)
-{
-	kt_did_t	tid = 0;
-
-	if (ld->ld_ktdid != 0) {
-		tid = ld->ld_ktdid;
-		ld->ld_ktdid = 0;
-	}
-
-	return (tid);
+	ld = ((smb_receiver_arg_t *)arg)->ra_listener;
+	session = ((smb_receiver_arg_t *)arg)->ra_session;
+	smb_mem_free(arg);
+	smb_session_receiver(session);
+	smb_server_destroy_session(ld, session);
 }
 
 /*
@@ -1758,18 +1681,18 @@
  * Enumerate the users associated with a session list.
  */
 static void
-smb_server_enum_private(smb_session_list_t *se, smb_svcenum_t *svcenum)
+smb_server_enum_private(smb_llist_t *ll, smb_svcenum_t *svcenum)
 {
 	smb_session_t	*sn;
 	smb_llist_t	*ulist;
 	smb_user_t	*user;
 	int		rc = 0;
 
-	rw_enter(&se->se_lock, RW_READER);
-	sn = list_head(&se->se_act.lst);
+	smb_llist_enter(ll, RW_READER);
+	sn = smb_llist_head(ll);
 
 	while (sn != NULL) {
-		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+		SMB_SESSION_VALID(sn);
 		ulist = &sn->s_user_list;
 		smb_llist_enter(ulist, RW_READER);
 		user = smb_llist_head(ulist);
@@ -1788,10 +1711,10 @@
 		if (rc != 0)
 			break;
 
-		sn = list_next(&se->se_act.lst, sn);
+		sn = smb_llist_next(ll, sn);
 	}
 
-	rw_exit(&se->se_lock);
+	smb_llist_exit(ll);
 }
 
 /*
@@ -1799,7 +1722,7 @@
  * Empty strings are treated as wildcards.
  */
 static int
-smb_server_sesion_disconnect(smb_session_list_t *se,
+smb_server_session_disconnect(smb_llist_t *ll,
     const char *client, const char *name)
 {
 	smb_session_t	*sn;
@@ -1808,14 +1731,14 @@
 	boolean_t	match;
 	int		count = 0;
 
-	rw_enter(&se->se_lock, RW_READER);
-	sn = list_head(&se->se_act.lst);
+	smb_llist_enter(ll, RW_READER);
+	sn = smb_llist_head(ll);
 
 	while (sn != NULL) {
-		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+		SMB_SESSION_VALID(sn);
 
 		if ((*client != '\0') && (!smb_session_isclient(sn, client))) {
-			sn = list_next(&se->se_act.lst, sn);
+			sn = smb_llist_next(ll, sn);
 			continue;
 		}
 
@@ -1846,10 +1769,10 @@
 		}
 
 		smb_llist_exit(ulist);
-		sn = list_next(&se->se_act.lst, sn);
+		sn = smb_llist_next(ll, sn);
 	}
 
-	rw_exit(&se->se_lock);
+	smb_llist_exit(ll);
 	return (count);
 }
 
@@ -1857,18 +1780,18 @@
  * Close a file by its unique id.
  */
 static int
-smb_server_fclose(smb_session_list_t *se, uint32_t uniqid)
+smb_server_fclose(smb_llist_t *ll, uint32_t uniqid)
 {
 	smb_session_t	*sn;
 	smb_llist_t	*ulist;
 	smb_user_t	*user;
 	int		rc = ENOENT;
 
-	rw_enter(&se->se_lock, RW_READER);
-	sn = list_head(&se->se_act.lst);
+	smb_llist_enter(ll, RW_READER);
+	sn = smb_llist_head(ll);
 
 	while ((sn != NULL) && (rc == ENOENT)) {
-		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+		SMB_SESSION_VALID(sn);
 		ulist = &sn->s_user_list;
 		smb_llist_enter(ulist, RW_READER);
 		user = smb_llist_head(ulist);
@@ -1883,10 +1806,10 @@
 		}
 
 		smb_llist_exit(ulist);
-		sn = list_next(&se->se_act.lst, sn);
+		sn = smb_llist_next(ll, sn);
 	}
 
-	rw_exit(&se->se_lock);
+	smb_llist_exit(ll);
 	return (rc);
 }
 
@@ -1945,26 +1868,6 @@
 	}
 }
 
-static void
-smb_server_signal_listeners(smb_server_t *sv)
-{
-	SMB_SERVER_VALID(sv);
-	ASSERT(sv->sv_state == SMB_SERVER_STATE_STOPPING);
-	ASSERT(MUTEX_HELD(&sv->sv_mutex));
-
-	smb_event_cancel(sv, 0);
-
-	if (sv->sv_nbt_daemon.ld_kth != NULL) {
-		tsignal(sv->sv_nbt_daemon.ld_kth, SIGINT);
-		sv->sv_nbt_daemon.ld_kth = NULL;
-	}
-
-	if (sv->sv_tcp_daemon.ld_kth != NULL) {
-		tsignal(sv->sv_tcp_daemon.ld_kth, SIGINT);
-		sv->sv_tcp_daemon.ld_kth = NULL;
-	}
-}
-
 smb_event_t *
 smb_event_create(int timeout)
 {
@@ -2323,3 +2226,48 @@
 	smb_server_release(sv);
 	return (rc);
 }
+
+/*
+ * smb_server_create_session
+ */
+static void
+smb_server_create_session(smb_listener_daemon_t *ld, ksocket_t s_so)
+{
+	smb_session_t		*session;
+	smb_receiver_arg_t	*rarg;
+
+	session = smb_session_create(s_so, ld->ld_port, ld->ld_sv,
+	    ld->ld_family);
+
+	if (session != NULL) {
+		smb_llist_enter(&ld->ld_session_list, RW_WRITER);
+		smb_llist_insert_tail(&ld->ld_session_list, session);
+		smb_llist_exit(&ld->ld_session_list);
+
+		rarg = (smb_receiver_arg_t *)smb_mem_alloc(
+		    sizeof (smb_receiver_arg_t));
+		rarg->ra_listener = ld;
+		rarg->ra_session = session;
+
+		if (taskq_dispatch(ld->ld_sv->sv_receiver_pool,
+		    smb_server_receiver, rarg, TQ_NOQUEUE) != 0)
+			return;
+
+		smb_mem_free(rarg);
+		smb_session_disconnect(session);
+		smb_server_destroy_session(ld, session);
+	} else {
+		smb_soshutdown(s_so);
+		smb_sodestroy(s_so);
+	}
+	cmn_err(CE_WARN, "SMB Session: creation failed");
+}
+
+static void
+smb_server_destroy_session(smb_listener_daemon_t *ld, smb_session_t *session)
+{
+	smb_llist_enter(&ld->ld_session_list, RW_WRITER);
+	smb_llist_remove(&ld->ld_session_list, session);
+	smb_llist_exit(&ld->ld_session_list);
+	smb_session_delete(session);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c	Thu Sep 09 11:46:43 2010 -0400
@@ -46,30 +46,28 @@
 void dump_smb_inaddr(smb_inaddr_t *ipaddr);
 
 void
-smb_session_timers(smb_session_list_t *se)
+smb_session_timers(smb_llist_t *ll)
 {
 	smb_session_t	*session;
 
-	rw_enter(&se->se_lock, RW_READER);
-	session = list_head(&se->se_act.lst);
-	while (session) {
+	smb_llist_enter(ll, RW_READER);
+	session = smb_llist_head(ll);
+	while (session != NULL) {
 		/*
 		 * Walk through the table and decrement each keep_alive
 		 * timer that has not timed out yet. (keepalive > 0)
 		 */
-		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
+		SMB_SESSION_VALID(session);
 		if (session->keep_alive &&
 		    (session->keep_alive != (uint32_t)-1))
 			session->keep_alive--;
-		session = list_next(&se->se_act.lst, session);
+		session = smb_llist_next(ll, session);
 	}
-	rw_exit(&se->se_lock);
+	smb_llist_exit(ll);
 }
 
 void
-smb_session_correct_keep_alive_values(
-    smb_session_list_t	*se,
-    uint32_t		new_keep_alive)
+smb_session_correct_keep_alive_values(smb_llist_t *ll, uint32_t new_keep_alive)
 {
 	smb_session_t		*sn;
 
@@ -84,21 +82,15 @@
 	 * Walk through the table and set each session to the new keep_alive
 	 * value if they have not already timed out.  Block clock interrupts.
 	 */
-	rw_enter(&se->se_lock, RW_READER);
-	sn = list_head(&se->se_rdy.lst);
-	while (sn) {
-		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
-		sn->keep_alive = new_keep_alive;
-		sn = list_next(&se->se_rdy.lst, sn);
+	smb_llist_enter(ll, RW_READER);
+	sn = smb_llist_head(ll);
+	while (sn != NULL) {
+		SMB_SESSION_VALID(sn);
+		if (sn->keep_alive != 0)
+			sn->keep_alive = new_keep_alive;
+		sn = smb_llist_next(ll, sn);
 	}
-	sn = list_head(&se->se_act.lst);
-	while (sn) {
-		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
-		if (sn->keep_alive)
-			sn->keep_alive = new_keep_alive;
-		sn = list_next(&se->se_act.lst, sn);
-	}
-	rw_exit(&se->se_lock);
+	smb_llist_exit(ll);
 }
 
 /*
@@ -121,25 +113,25 @@
  * there is no NetBIOS name.  See also Knowledge Base article Q301673.
  */
 void
-smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *sess)
+smb_session_reconnection_check(smb_llist_t *ll, smb_session_t *sess)
 {
 	smb_session_t	*sn;
 
-	rw_enter(&se->se_lock, RW_READER);
-	sn = list_head(&se->se_act.lst);
-	while (sn) {
-		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+	smb_llist_enter(ll, RW_READER);
+	sn = smb_llist_head(ll);
+	while (sn != NULL) {
+		SMB_SESSION_VALID(sn);
 		if ((sn != sess) &&
 		    smb_inet_equal(&sn->ipaddr, &sess->ipaddr) &&
 		    smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr) &&
 		    (strcasecmp(sn->workstation, sess->workstation) == 0) &&
 		    (sn->opentime <= sess->opentime) &&
 		    (sn->s_kid < sess->s_kid)) {
-			tsignal(sn->s_thread, SIGUSR1);
+			smb_session_disconnect(sn);
 		}
-		sn = list_next(&se->se_act.lst, sn);
+		sn = smb_llist_next(ll, sn);
 	}
-	rw_exit(&se->se_lock);
+	smb_llist_exit(ll);
 }
 
 /*
@@ -465,34 +457,26 @@
 }
 
 /*
- * This is the entry point for processing SMB messages over NetBIOS or
- * SMB-over-TCP.
+ * smb_session_receiver
  *
- * NetBIOS connections require a session request to establish a session
- * on which to send session messages.
- *
- * Session requests are not valid on SMB-over-TCP.  We don't need to do
- * anything here as session requests will be treated as an error when
- * handling session messages.
+ * Receives request from the network and dispatches them to a worker.
  */
-int
-smb_session_daemon(smb_session_list_t *se)
+void
+smb_session_receiver(smb_session_t *session)
 {
-	int		rc = 0;
-	smb_session_t	*session;
+	int	rc;
 
-	session = smb_session_list_activate_head(se);
-	if (session == NULL)
-		return (EINVAL);
+	SMB_SESSION_VALID(session);
+
+	session->s_thread = curthread;
 
 	if (session->s_local_port == IPPORT_NETBIOS_SSN) {
 		rc = smb_session_request(session);
-		if (rc) {
+		if (rc != 0) {
 			smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 			session->s_state = SMB_SESSION_STATE_DISCONNECTED;
 			smb_rwx_rwexit(&session->s_lock);
-			smb_session_list_terminate(se, session);
-			return (rc);
+			return;
 		}
 	}
 
@@ -500,7 +484,7 @@
 	session->s_state = SMB_SESSION_STATE_ESTABLISHED;
 	smb_rwx_rwexit(&session->s_lock);
 
-	rc = smb_session_message(session);
+	(void) smb_session_message(session);
 
 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
@@ -511,15 +495,40 @@
 	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
 
 	smb_session_cancel(session);
-
 	/*
 	 * At this point everything related to the session should have been
 	 * cleaned up and we expect that nothing will attempt to use the
 	 * socket.
 	 */
-	smb_session_list_terminate(se, session);
+}
+
+/*
+ * smb_session_disconnect
+ *
+ * Disconnects the session passed in.
+ */
+void
+smb_session_disconnect(smb_session_t *session)
+{
+	SMB_SESSION_VALID(session);
 
-	return (rc);
+	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+	switch (session->s_state) {
+	case SMB_SESSION_STATE_INITIALIZED:
+	case SMB_SESSION_STATE_CONNECTED:
+	case SMB_SESSION_STATE_ESTABLISHED:
+	case SMB_SESSION_STATE_NEGOTIATED:
+	case SMB_SESSION_STATE_OPLOCK_BREAKING:
+	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
+	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
+		smb_soshutdown(session->sock);
+		session->s_state = SMB_SESSION_STATE_DISCONNECTED;
+		_NOTE(FALLTHRU)
+	case SMB_SESSION_STATE_DISCONNECTED:
+	case SMB_SESSION_STATE_TERMINATED:
+		break;
+	}
+	smb_rwx_rwexit(&session->s_lock);
 }
 
 /*
@@ -640,7 +649,7 @@
 		sr->sr_time_submitted = gethrtime();
 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
 		smb_srqueue_waitq_enter(session->s_srqueue);
-		(void) taskq_dispatch(session->s_server->sv_thread_pool,
+		(void) taskq_dispatch(session->s_server->sv_worker_pool,
 		    smb_session_worker, sr, TQ_SLEEP);
 	}
 }
@@ -747,11 +756,6 @@
 
 	session->s_magic = 0;
 
-	if (session->s_local_port == IPPORT_NETBIOS_SSN)
-		smb_server_dec_nbt_sess(session->s_server);
-	else
-		smb_server_dec_tcp_sess(session->s_server);
-
 	smb_rwx_destroy(&session->s_lock);
 	smb_net_txl_destructor(&session->s_txlst);
 
@@ -771,6 +775,13 @@
 	ASSERT(session->s_dir_cnt == 0);
 
 	smb_idpool_destructor(&session->s_uid_pool);
+	if (session->sock != NULL) {
+		if (session->s_local_port == IPPORT_NETBIOS_SSN)
+			smb_server_dec_nbt_sess(session->s_server);
+		else
+			smb_server_dec_tcp_sess(session->s_server);
+		smb_sodestroy(session->sock);
+	}
 	kmem_cache_free(session->s_cache, session);
 }
 
@@ -868,154 +879,6 @@
 	smb_srqueue_runq_exit(srq);
 }
 
-void
-smb_session_list_constructor(smb_session_list_t *se)
-{
-	bzero(se, sizeof (*se));
-	rw_init(&se->se_lock, NULL, RW_DEFAULT, NULL);
-	list_create(&se->se_rdy.lst, sizeof (smb_session_t),
-	    offsetof(smb_session_t, s_lnd));
-	list_create(&se->se_act.lst, sizeof (smb_session_t),
-	    offsetof(smb_session_t, s_lnd));
-}
-
-void
-smb_session_list_destructor(smb_session_list_t *se)
-{
-	list_destroy(&se->se_rdy.lst);
-	list_destroy(&se->se_act.lst);
-	rw_destroy(&se->se_lock);
-}
-
-void
-smb_session_list_append(smb_session_list_t *se, smb_session_t *session)
-{
-	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-	ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
-
-	rw_enter(&se->se_lock, RW_WRITER);
-	list_insert_tail(&se->se_rdy.lst, session);
-	se->se_rdy.count++;
-	se->se_wrop++;
-	rw_exit(&se->se_lock);
-}
-
-void
-smb_session_list_delete_tail(smb_session_list_t *se)
-{
-	smb_session_t	*session;
-
-	rw_enter(&se->se_lock, RW_WRITER);
-	session = list_tail(&se->se_rdy.lst);
-	if (session) {
-		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
-		list_remove(&se->se_rdy.lst, session);
-		ASSERT(se->se_rdy.count);
-		se->se_rdy.count--;
-		rw_exit(&se->se_lock);
-		smb_session_delete(session);
-		return;
-	}
-	rw_exit(&se->se_lock);
-}
-
-smb_session_t *
-smb_session_list_activate_head(smb_session_list_t *se)
-{
-	smb_session_t	*session;
-
-	rw_enter(&se->se_lock, RW_WRITER);
-	session = list_head(&se->se_rdy.lst);
-	if (session) {
-		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
-		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
-		session->s_thread = curthread;
-		session->s_ktdid = session->s_thread->t_did;
-		smb_rwx_rwexit(&session->s_lock);
-		list_remove(&se->se_rdy.lst, session);
-		se->se_rdy.count--;
-		list_insert_tail(&se->se_act.lst, session);
-		se->se_act.count++;
-		se->se_wrop++;
-	}
-	rw_exit(&se->se_lock);
-	return (session);
-}
-
-void
-smb_session_list_terminate(smb_session_list_t *se, smb_session_t *session)
-{
-	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-
-	rw_enter(&se->se_lock, RW_WRITER);
-
-	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
-	ASSERT(session->s_state == SMB_SESSION_STATE_DISCONNECTED);
-	session->s_state = SMB_SESSION_STATE_TERMINATED;
-	smb_sodestroy(session->sock);
-	session->sock = NULL;
-	smb_rwx_rwexit(&session->s_lock);
-
-	list_remove(&se->se_act.lst, session);
-	se->se_act.count--;
-	se->se_wrop++;
-
-	ASSERT(session->s_thread == curthread);
-
-	rw_exit(&se->se_lock);
-
-	smb_session_delete(session);
-}
-
-/*
- * smb_session_list_signal
- *
- * This function signals all the session threads. The intent is to terminate
- * them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete
- * immediately.
- *
- * This function must only be called by the threads listening and accepting
- * connections. They must pass in their respective session list.
- */
-void
-smb_session_list_signal(smb_session_list_t *se)
-{
-	smb_session_t	*session;
-
-	rw_enter(&se->se_lock, RW_WRITER);
-	while (session = list_head(&se->se_rdy.lst)) {
-
-		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-
-		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
-		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
-		session->s_state = SMB_SESSION_STATE_TERMINATED;
-		smb_sodestroy(session->sock);
-		session->sock = NULL;
-		smb_rwx_rwexit(&session->s_lock);
-
-		list_remove(&se->se_rdy.lst, session);
-		se->se_rdy.count--;
-		se->se_wrop++;
-
-		rw_exit(&se->se_lock);
-		smb_session_delete(session);
-		rw_enter(&se->se_lock, RW_WRITER);
-	}
-	rw_downgrade(&se->se_lock);
-
-	session = list_head(&se->se_act.lst);
-	while (session) {
-
-		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-		tsignal(session->s_thread, SIGUSR1);
-		session = list_next(&se->se_act.lst, session);
-	}
-	rw_exit(&se->se_lock);
-}
-
 /*
  * smb_session_lookup_user
  */
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Thu Sep 09 11:46:43 2010 -0400
@@ -428,7 +428,7 @@
 		smb_rwx_rwexit(&session->s_lock);
 		smb_srqueue_waitq_enter(session->s_srqueue);
 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
-		(void) taskq_dispatch(session->s_server->sv_thread_pool,
+		(void) taskq_dispatch(session->s_server->sv_worker_pool,
 		    smb_session_worker, sr, TQ_SLEEP);
 		smb_rwx_rwenter(&session->s_lock, RW_READER);
 		while (session->s_state == SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
--- a/usr/src/uts/common/fs/vfs.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/vfs.c	Thu Sep 09 11:46:43 2010 -0400
@@ -4718,6 +4718,15 @@
 	vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
 }
 
+void
+vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
+{
+	/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
+	if (vfsp->vfs_implp == NULL)
+		return;
+	vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
+}
+
 /*
  * Query a vfs for a feature.
  * Returns 1 if feature is present, 0 if not
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Thu Sep 09 11:46:43 2010 -0400
@@ -1086,13 +1086,22 @@
 zfs_set_fuid_feature(zfsvfs_t *zfsvfs)
 {
 	zfsvfs->z_use_fuids = USE_FUIDS(zfsvfs->z_version, zfsvfs->z_os);
-	if (zfsvfs->z_use_fuids && zfsvfs->z_vfs) {
-		vfs_set_feature(zfsvfs->z_vfs, VFSFT_XVATTR);
-		vfs_set_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS);
-		vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS);
-		vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE);
-		vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER);
-		vfs_set_feature(zfsvfs->z_vfs, VFSFT_REPARSE);
+	if (zfsvfs->z_vfs) {
+		if (zfsvfs->z_use_fuids) {
+			vfs_set_feature(zfsvfs->z_vfs, VFSFT_XVATTR);
+			vfs_set_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS);
+			vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS);
+			vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE);
+			vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER);
+			vfs_set_feature(zfsvfs->z_vfs, VFSFT_REPARSE);
+		} else {
+			vfs_clear_feature(zfsvfs->z_vfs, VFSFT_XVATTR);
+			vfs_clear_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS);
+			vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS);
+			vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE);
+			vfs_clear_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER);
+			vfs_clear_feature(zfsvfs->z_vfs, VFSFT_REPARSE);
+		}
 	}
 	zfsvfs->z_use_sa = USE_SA(zfsvfs->z_version, zfsvfs->z_os);
 }
@@ -2010,7 +2019,7 @@
 int
 zfs_resume_fs(zfsvfs_t *zfsvfs, const char *osname)
 {
-	int err, err2;
+	int err;
 
 	ASSERT(RRW_WRITE_HELD(&zfsvfs->z_teardown_lock));
 	ASSERT(RW_WRITE_HELD(&zfsvfs->z_teardown_inactive_lock));
@@ -2023,19 +2032,34 @@
 		znode_t *zp;
 		uint64_t sa_obj = 0;
 
-		err2 = zap_lookup(zfsvfs->z_os, MASTER_NODE_OBJ,
+		/*
+		 * Make sure version hasn't changed
+		 */
+
+		err = zfs_get_zplprop(zfsvfs->z_os, ZFS_PROP_VERSION,
+		    &zfsvfs->z_version);
+
+		if (err)
+			goto bail;
+
+		err = zap_lookup(zfsvfs->z_os, MASTER_NODE_OBJ,
 		    ZFS_SA_ATTRS, 8, 1, &sa_obj);
 
-		if ((err || err2) && zfsvfs->z_version >= ZPL_VERSION_SA)
+		if (err && zfsvfs->z_version >= ZPL_VERSION_SA)
 			goto bail;
 
-
 		if ((err = sa_setup(zfsvfs->z_os, sa_obj,
 		    zfs_attr_table,  ZPL_END, &zfsvfs->z_attr_table)) != 0)
 			goto bail;
 
+		if (zfsvfs->z_version >= ZPL_VERSION_SA)
+			sa_register_update_callback(zfsvfs->z_os,
+			    zfs_sa_upgrade);
+
 		VERIFY(zfsvfs_setup(zfsvfs, B_FALSE) == 0);
 
+		zfs_set_fuid_feature(zfsvfs);
+
 		/*
 		 * Attempt to re-establish all the active znodes with
 		 * their dbufs.  If a zfs_rezget() fails, then we'll let
@@ -2048,7 +2072,6 @@
 			(void) zfs_rezget(zp);
 		}
 		mutex_exit(&zfsvfs->z_znodes_lock);
-
 	}
 
 bail:
@@ -2058,8 +2081,8 @@
 
 	if (err) {
 		/*
-		 * Since we couldn't reopen zfsvfs::z_os, force
-		 * unmount this file system.
+		 * Since we couldn't reopen zfsvfs::z_os, or
+		 * setup the sa framework force unmount this file system.
 		 */
 		if (vn_vfswlock(zfsvfs->z_vfs->vfs_vnodecovered) == 0)
 			(void) dounmount(zfsvfs->z_vfs, MS_FORCE, CRED());
@@ -2219,8 +2242,7 @@
 
 	zfsvfs->z_version = newvers;
 
-	if (zfsvfs->z_version >= ZPL_VERSION_FUID)
-		zfs_set_fuid_feature(zfsvfs);
+	zfs_set_fuid_feature(zfsvfs);
 
 	return (0);
 }
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c	Thu Sep 09 11:46:43 2010 -0400
@@ -1908,12 +1908,12 @@
 
 static int
 zfs_grab_sa_handle(objset_t *osp, uint64_t obj, sa_handle_t **hdlp,
-    dmu_buf_t **db)
+    dmu_buf_t **db, void *tag)
 {
 	dmu_object_info_t doi;
 	int error;
 
-	if ((error = sa_buf_hold(osp, obj, FTAG, db)) != 0)
+	if ((error = sa_buf_hold(osp, obj, tag, db)) != 0)
 		return (error);
 
 	dmu_object_info_from_db(*db, &doi);
@@ -1921,13 +1921,13 @@
 	    doi.doi_bonus_type != DMU_OT_ZNODE) ||
 	    doi.doi_bonus_type == DMU_OT_ZNODE &&
 	    doi.doi_bonus_size < sizeof (znode_phys_t)) {
-		sa_buf_rele(*db, FTAG);
+		sa_buf_rele(*db, tag);
 		return (ENOTSUP);
 	}
 
 	error = sa_handle_get(osp, obj, NULL, SA_HDL_PRIVATE, hdlp);
 	if (error != 0) {
-		sa_buf_rele(*db, FTAG);
+		sa_buf_rele(*db, tag);
 		return (error);
 	}
 
@@ -1935,10 +1935,10 @@
 }
 
 void
-zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db)
+zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, void *tag)
 {
 	sa_handle_destroy(hdl);
-	sa_buf_rele(db, FTAG);
+	sa_buf_rele(db, tag);
 }
 
 /*
@@ -2015,7 +2015,7 @@
 		int is_xattrdir;
 
 		if (prevdb)
-			zfs_release_sa_handle(prevhdl, prevdb);
+			zfs_release_sa_handle(prevhdl, prevdb, FTAG);
 
 		if ((error = zfs_obj_to_pobj(sa_hdl, sa_table, &pobj,
 		    &is_xattrdir)) != 0)
@@ -2047,7 +2047,7 @@
 			prevhdl = sa_hdl;
 			prevdb = sa_db;
 		}
-		error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db);
+		error = zfs_grab_sa_handle(osp, obj, &sa_hdl, &sa_db, FTAG);
 		if (error != 0) {
 			sa_hdl = prevhdl;
 			sa_db = prevdb;
@@ -2057,7 +2057,7 @@
 
 	if (sa_hdl != NULL && sa_hdl != hdl) {
 		ASSERT(sa_db != NULL);
-		zfs_release_sa_handle(sa_hdl, sa_db);
+		zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
 	}
 
 	if (error == 0)
@@ -2078,13 +2078,13 @@
 	if (error != 0)
 		return (error);
 
-	error = zfs_grab_sa_handle(osp, obj, &hdl, &db);
+	error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
 	if (error != 0)
 		return (error);
 
 	error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
 
-	zfs_release_sa_handle(hdl, db);
+	zfs_release_sa_handle(hdl, db, FTAG);
 	return (error);
 }
 
@@ -2104,18 +2104,18 @@
 	if (error != 0)
 		return (error);
 
-	error = zfs_grab_sa_handle(osp, obj, &hdl, &db);
+	error = zfs_grab_sa_handle(osp, obj, &hdl, &db, FTAG);
 	if (error != 0)
 		return (error);
 
 	error = zfs_obj_to_stats_impl(hdl, sa_table, sb);
 	if (error != 0) {
-		zfs_release_sa_handle(hdl, db);
+		zfs_release_sa_handle(hdl, db, FTAG);
 		return (error);
 	}
 
 	error = zfs_obj_to_path_impl(osp, obj, hdl, sa_table, buf, len);
 
-	zfs_release_sa_handle(hdl, db);
+	zfs_release_sa_handle(hdl, db, FTAG);
 	return (error);
 }
--- a/usr/src/uts/common/fs/zfs/zio.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/fs/zfs/zio.c	Thu Sep 09 11:46:43 2010 -0400
@@ -117,6 +117,7 @@
 		size_t size = (c + 1) << SPA_MINBLOCKSHIFT;
 		size_t p2 = size;
 		size_t align = 0;
+		size_t cflags = (size > zio_buf_debug_limit) ? KMC_NODEBUG : 0;
 
 		while (p2 & (p2 - 1))
 			p2 &= p2 - 1;
@@ -133,13 +134,17 @@
 			char name[36];
 			(void) sprintf(name, "zio_buf_%lu", (ulong_t)size);
 			zio_buf_cache[c] = kmem_cache_create(name, size,
-			    align, NULL, NULL, NULL, NULL, NULL,
-			    size > zio_buf_debug_limit ? KMC_NODEBUG : 0);
-
+			    align, NULL, NULL, NULL, NULL, NULL, cflags);
+
+			/*
+			 * Since zio_data bufs do not appear in crash dumps, we
+			 * pass KMC_NOTOUCH so that no allocator metadata is
+			 * stored with the buffers.
+			 */
 			(void) sprintf(name, "zio_data_buf_%lu", (ulong_t)size);
 			zio_data_buf_cache[c] = kmem_cache_create(name, size,
 			    align, NULL, NULL, NULL, NULL, data_alloc_arena,
-			    size > zio_buf_debug_limit ? KMC_NODEBUG : 0);
+			    cflags | KMC_NOTOUCH);
 		}
 	}
 
--- a/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_clock.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_clock.c	Thu Sep 09 11:46:43 2010 -0400
@@ -42,6 +42,7 @@
 #endif /* DHCHAP_SUPPORT */
 
 static void	emlxs_timer(void *arg);
+static void	emlxs_timer_check_fw_update(emlxs_hba_t *hba);
 static void	emlxs_timer_check_heartbeat(emlxs_hba_t *hba);
 static uint32_t	emlxs_timer_check_pkts(emlxs_hba_t *hba, uint8_t *flag);
 static void	emlxs_timer_check_nodes(emlxs_port_t *port, uint8_t *flag);
@@ -157,6 +158,9 @@
 	/* Check heartbeat timer */
 	emlxs_timer_check_heartbeat(hba);
 
+	/* Check fw update timer */
+	emlxs_timer_check_fw_update(hba);
+
 #ifdef IDLE_TIMER
 	emlxs_pm_idle_timer(hba);
 #endif /* IDLE_TIMER */
@@ -811,6 +815,32 @@
 
 
 static void
+emlxs_timer_check_fw_update(emlxs_hba_t *hba)
+{
+	emlxs_port_t *port = &PPORT;
+
+	if (!(hba->fw_flag & FW_UPDATE_NEEDED)) {
+		hba->fw_timer = 0;
+		return;
+	}
+
+	if (hba->timer_tics < hba->fw_timer) {
+		return;
+	}
+
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fw_update_msg,
+	"A manual HBA reset or link reset (using luxadm or fcadm) "
+	"is required.");
+
+	/* Set timer for 24 hours */
+	hba->fw_timer = hba->timer_tics + (60 * 60 * 24);
+
+	return;
+
+} /* emlxs_timer_check_fw_update() */
+
+
+static void
 emlxs_timer_check_discovery(emlxs_port_t *port)
 {
 	emlxs_hba_t *hba = HBA;
--- a/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_download.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_download.c	Thu Sep 09 11:46:43 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Emulex.  All rights reserved.
+ * Copyright 2010 Emulex.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,33 +38,27 @@
 			PIMAGE_HDR ImageHdr, caddr_t Buffer);
 
 static int32_t	emlxs_build_parms(caddr_t Buffer, PWAKE_UP_PARMS AbsWakeUpParms,
-			uint32_t BufferSize, PAIF_HDR AifHeader,
-			int32_t DwcFile);
+			uint32_t BufferSize, PAIF_HDR AifHeader);
 static uint32_t	emlxs_validate_image(emlxs_hba_t *hba, caddr_t Buffer,
 			uint32_t Size, emlxs_fw_image_t *fw_image);
 static void	emlxs_format_dump(emlxs_hba_t *hba, MAILBOXQ *mbq,
 			uint32_t Type, uint32_t RegionId, uint32_t WordCnt,
 			uint32_t BaseAddr);
 static uint32_t	emlxs_start_abs_download(emlxs_hba_t *hba, PAIF_HDR AifHdr,
-			caddr_t Buffer, PWAKE_UP_PARMS WakeUpParms,
-			uint32_t MaxRbusSramSize, uint32_t MaxIbusSramSize,
-			PWAKE_UP_PARMS AbsWakeUpParms, int32_t DwcFile);
+			caddr_t Buffer, uint32_t len,
+			PWAKE_UP_PARMS WakeUpParms);
 static uint32_t	emlxs_start_abs_download_2mb(emlxs_hba_t *hba, caddr_t buffer,
 			uint32_t len, uint32_t offline,
 			emlxs_fw_image_t *fw_image);
-static uint32_t	emlxs_proc_abs_2mb(emlxs_hba_t *hba, PAIF_HDR AifHdr,
+static uint32_t	emlxs_proc_abs_2mb(emlxs_hba_t *hba,
 			caddr_t EntireBuffer, uint32_t FileType,
-			uint32_t BWCflag, uint32_t extType);
+			uint32_t extType);
 static void	emlxs_format_load_area_cmd(MAILBOXQ *mbq, uint32_t Base,
 			uint32_t DlByteCount, uint32_t Function,
 			uint32_t Complete, uint32_t DataOffset, uint32_t AreaId,
 			uint8_t MbxCmd, uint32_t StepCmd);
 static uint32_t	emlxs_build_parms_2mb_bwc(emlxs_hba_t *hba, PAIF_HDR AifHdr,
 			uint32_t extType, PWAKE_UP_PARMS AbsWakeUpParms);
-static uint32_t	emlxs_build_parms_2mb_dwc(emlxs_hba_t *hba, caddr_t Buffer,
-			uint32_t BufferSize, PAIF_HDR AifHeader,
-			PWAKE_UP_PARMS AbsWakeUpParms, uint32_t BWCflag,
-			uint32_t extType, uint32_t *numBootImage);
 static uint32_t	emlxs_update_exp_rom(emlxs_hba_t *hba,
 			PWAKE_UP_PARMS WakeUpParms);
 extern uint32_t	emlxs_get_max_sram(emlxs_hba_t *hba, uint32_t *MaxRbusSize,
@@ -72,7 +66,7 @@
 static void	emlxs_format_prog_flash(MAILBOXQ *mbq, uint32_t Base,
 			uint32_t DlByteCount, uint32_t Function,
 			uint32_t Complete, uint32_t BdeAddress,
-			uint32_t BdeSize, PROG_ID *ProgId);
+			uint32_t BdeSize, PROG_ID *ProgId, uint32_t keep);
 static void	emlxs_format_update_parms(MAILBOXQ *mbq,
 			PWAKE_UP_PARMS WakeUpParms);
 static void	emlxs_format_update_pci_cfg(emlxs_hba_t *hba, MAILBOXQ *mbq,
@@ -95,7 +89,7 @@
 			PWAKE_UP_PARMS WakeUpParms, PROG_ID *id);
 static uint32_t	emlxs_start_rel_download(emlxs_hba_t *hba, PIMAGE_HDR ImageHdr,
 			caddr_t Buffer, PWAKE_UP_PARMS WakeUpParms,
-			uint32_t MaxRbusSramSize, uint32_t MaxIbusSramSize);
+			uint32_t dwc_flag);
 static uint32_t	emlxs_read_load_list(emlxs_hba_t *hba, LOAD_LIST *LoadList);
 
 static uint32_t	emlxs_valid_cksum(uint32_t *StartAddr, uint32_t *EndAddr);
@@ -104,10 +98,6 @@
 
 static void	emlxs_dump_image_header(emlxs_hba_t *hba, PIMAGE_HDR image);
 
-static uint32_t	emlxs_get_abs_image_type(caddr_t Buffer, uint32_t BufferSize);
-
-static uint32_t	emlxs_get_dwc_image_type(emlxs_hba_t *hba, caddr_t Buffer,
-			uint32_t BufferSize, PAIF_HDR AifHeader);
 static uint32_t	emlxs_type_check(uint32_t type);
 
 static uint32_t	emlxs_kern_check(emlxs_hba_t *hba, uint32_t version);
@@ -142,6 +132,16 @@
 static int32_t emlxs_sli4_fw_download(emlxs_hba_t *hba, caddr_t buffer,
 			uint32_t len, uint32_t offline);
 
+static uint32_t emlxs_proc_rel_2mb(emlxs_hba_t *hba, caddr_t buffer,
+			emlxs_fw_image_t *fw_image);
+static uint32_t emlxs_delete_load_entry(emlxs_hba_t *hba, PROG_ID *progId);
+
+static void emlxs_verify_image(emlxs_hba_t *hba, emlxs_fw_image_t *image);
+
+static uint32_t emlxs_clean_flash(emlxs_hba_t *hba,
+			PWAKE_UP_PARMS OldWakeUpParms,
+			PWAKE_UP_PARMS NewWakeUpParms);
+
 /* ************************************************************************* */
 
 extern int32_t
@@ -154,11 +154,6 @@
 	AIF_HDR AifHdr;
 	uint32_t ImageType;
 	WAKE_UP_PARMS WakeUpParms;
-	WAKE_UP_PARMS AbsWakeUpParms;
-	uint32_t MaxRbusSramSize;
-	uint32_t MaxIbusSramSize;
-	int32_t AbsChangeParams = 0;
-	int32_t DwcFile = FALSE;
 	uint32_t rval = 0;
 	emlxs_fw_image_t fw_image;
 	uint32_t i;
@@ -209,6 +204,9 @@
 		goto done;
 	}
 
+	/* Verify image */
+	emlxs_verify_image(hba, &fw_image);
+
 	/* Get image type */
 	Uptr = (uint32_t *)buffer;
 	ImageType = *Uptr;
@@ -239,26 +237,16 @@
 
 	/* Pre-pegasus adapters only */
 
-	/* Check for absolute image */
-	else if (ImageType == NOP_IMAGE_TYPE) {
+	/* Initialize headers */
+	if (ImageType == NOP_IMAGE_TYPE) {
 		bcopy(buffer, &AifHdr, sizeof (AIF_HDR));
 		bzero((void *)&ImageHdr, sizeof (IMAGE_HDR));
-
-		if (AifHdr.ImageBase && (AifHdr.ImageBase == 0x20000)) {
-			DwcFile = TRUE;
-		}
-
-		AbsChangeParams = emlxs_build_parms(buffer,
-		    &AbsWakeUpParms, len, &AifHdr, DwcFile);
-	} else {	/* (ImageType != NOP_IMAGE_TYPE) Relative image */
-
+	} else { /* PRG file */
 		bzero((void *)&AifHdr, sizeof (AIF_HDR));
 		bcopy(buffer, &ImageHdr, sizeof (IMAGE_HDR));
 	}
 
-	/*
-	 * Everything checks out, now to just do it
-	 */
+	/* Everything checks out, now to just do it */
 
 	if (offline) {
 		if (emlxs_offline(hba) != FC_SUCCESS) {
@@ -268,7 +256,6 @@
 			    "Unable to take adapter offline.");
 
 			rval = EMLXS_OFFLINE_FAILED;
-
 			goto SLI_DOWNLOAD_EXIT;
 		}
 
@@ -279,11 +266,12 @@
 			    "Unable to restart adapter.");
 
 			rval = EMLXS_OFFLINE_FAILED;
-
 			goto SLI_DOWNLOAD_EXIT;
 		}
 	}
 
+	/* Pre-pegasus adapters */
+
 	if (ImageHdr.Id.Type == SBUS_FCODE) {
 		/* Erase Flash */
 		if (emlxs_erase_fcode_flash(hba)) {
@@ -291,7 +279,6 @@
 			    "Unable to erase flash.");
 
 			rval = EMLXS_IMAGE_FAILED;
-
 			goto SLI_DOWNLOAD_EXIT;
 		}
 
@@ -301,62 +288,47 @@
 			    "Unable to write flash.");
 
 			rval = EMLXS_IMAGE_FAILED;
-
 			goto SLI_DOWNLOAD_EXIT;
 		}
 
-	} else {	/* !SBUS_FCODE */
-
-
-		if (emlxs_read_wakeup_parms(hba, &WakeUpParms, 1)) {
-			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
-			    "Unable to get parameters.");
-
-			rval = EMLXS_IMAGE_FAILED;
-
-			goto SLI_DOWNLOAD_EXIT;
-		}
-
-		if (emlxs_get_max_sram(hba, &MaxRbusSramSize,
-		    &MaxIbusSramSize)) {
-			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
-			    "Unable to get RAM size.");
+		goto SLI_DOWNLOAD_EXIT;
+	}
+
+	/* Pre-pegasus PCI adapters */
+
+	if (emlxs_read_wakeup_parms(hba, &WakeUpParms, 1)) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
+		    "Unable to get parameters.");
+
+		rval = EMLXS_IMAGE_FAILED;
+
+		goto SLI_DOWNLOAD_EXIT;
+	}
+
+	if (ImageType == NOP_IMAGE_TYPE) {
+		if (emlxs_start_abs_download(hba, &AifHdr,
+		    buffer, len, &WakeUpParms)) {
+			EMLXS_MSGF(EMLXS_CONTEXT,
+			    &emlxs_download_failed_msg,
+			    "Failed to program flash.");
 
 			rval = EMLXS_IMAGE_FAILED;
 
 			goto SLI_DOWNLOAD_EXIT;
 		}
 
-		if (ImageType == NOP_IMAGE_TYPE) {
-			if (emlxs_start_abs_download(hba, &AifHdr, buffer,
-			    &WakeUpParms, MaxRbusSramSize, MaxIbusSramSize,
-			    (AbsChangeParams) ? &AbsWakeUpParms : NULL,
-			    DwcFile)) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_download_failed_msg,
-				    "Failed to program flash.");
-
-				rval = EMLXS_IMAGE_FAILED;
-
-				goto SLI_DOWNLOAD_EXIT;
-			}
-
-		} else {
-
-			if (emlxs_start_rel_download(hba, &ImageHdr, buffer,
-			    &WakeUpParms, MaxRbusSramSize, MaxIbusSramSize)) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_download_failed_msg,
-				    "Failed to program flash.");
-
-				rval = EMLXS_IMAGE_FAILED;
-
-				goto SLI_DOWNLOAD_EXIT;
-			}
+	} else { /* Relative PRG file */
+		if (emlxs_start_rel_download(hba, &ImageHdr, buffer,
+		    &WakeUpParms, 0)) {
+			EMLXS_MSGF(EMLXS_CONTEXT,
+			    &emlxs_download_failed_msg,
+			    "Failed to program flash.");
+
+			rval = EMLXS_IMAGE_FAILED;
+
+			goto SLI_DOWNLOAD_EXIT;
 		}
-
-	}	/* !SBUS_FCODE */
-
+	}
 
 SLI_DOWNLOAD_EXIT:
 
@@ -461,12 +433,13 @@
 			image_ptr  += count;
 		}
 
-		/* Set last two words of last payload with */
-		/* image size and block crc */
+		/* Set last three words of last payload with */
+		/* load address, image size and block crc */
 		if (flashrom->params.opcode == MGMT_FLASHROM_OPCODE_FLASH) {
-			wptr = (uint32_t *)&payload[(xfer_size - 8)];
-			wptr[0] = file->image_size;
-			wptr[1] = file->block_crc;
+			wptr = (uint32_t *)&payload[(xfer_size - 12)];
+			wptr[0] = file->load_address;
+			wptr[1] = file->image_size;
+			wptr[2] = file->block_crc;
 		}
 
 		/* Send write request */
@@ -1082,6 +1055,7 @@
 			file->image_offset = entry->offset;
 			file->block_size   = entry->pad_size;
 			file->block_crc    = entry->checksum;
+			file->load_address = entry->entry_point;
 		} else {
 			file->image_offset = entry->offset +
 			    sizeof (emlxs_sli4_ufi_header_t);
@@ -1097,6 +1071,10 @@
 					file->block_size = (k + 8) -
 					    file->image_offset;
 
+					/* Read load_address */
+					value = *(wptr - 2);
+					file->load_address = BE_SWAP32(value);
+
 					/* Read block_crc */
 					value = *wptr;
 					file->block_crc = BE_SWAP32(value);
@@ -1116,7 +1094,7 @@
 		}
 
 		/* Make sure image will fit in block specified */
-		if (file->image_size + 8 > file->block_size) {
+		if (file->image_size + 12 > file->block_size) {
 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
 			    "%s: Image too large for block. image=%x block=%x",
 			    file->label, file->image_size, file->block_size);
@@ -1134,6 +1112,7 @@
 			file2->image_size = file->image_size;
 			file2->block_size = file->block_size;
 			file2->block_crc = file->block_crc;
+			file2->load_address = file->load_address;
 
 			/* Save FCOE version info */
 			bptr = (uint8_t *)buffer + file->image_offset + 0x30;
@@ -1150,6 +1129,7 @@
 			file2->image_size = file->image_size;
 			file2->block_size = file->block_size;
 			file2->block_crc = file->block_crc;
+			file2->load_address = file->load_address;
 		}
 	}
 
@@ -1173,9 +1153,10 @@
 		}
 
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
-		    "%s: type=%x block=%x image=%x offset=%x crc=%x",
+		    "%s: type=%x block=%x image=%x offset=%x crc=%x load=%x",
 		    file->label, file->type, file->block_size,
-		    file->image_size, file->image_offset, file->block_crc);
+		    file->image_size, file->image_offset, file->block_crc,
+		    file->load_address);
 	}
 
 	return (0);
@@ -1660,13 +1641,11 @@
 emlxs_start_abs_download(emlxs_hba_t *hba,
     PAIF_HDR AifHdr,
     caddr_t Buffer,
-    PWAKE_UP_PARMS WakeUpParms,
-    uint32_t MaxRbusSramSize,
-    uint32_t MaxIbusSramSize, PWAKE_UP_PARMS AbsWakeUpParms, int32_t DwcFile)
+    uint32_t len,
+    PWAKE_UP_PARMS WakeUpParms)
 {
 	emlxs_port_t *port = &PPORT;
 	uint32_t DlByteCount = AifHdr->RoSize + AifHdr->RwSize;
-	IMAGE_HDR ImageHdr;
 	uint32_t *Src;
 	uint32_t *Dst;
 	caddr_t DataBuffer = NULL;
@@ -1677,8 +1656,10 @@
 	uint32_t DlToAddr = AifHdr->ImageBase;
 	uint32_t DlCount;
 	uint32_t i;
-
-	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	WAKE_UP_PARMS AbsWakeUpParms;
+	int32_t AbsChangeParams;
+
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
 	    "Performing absolute download...");
 
 	if ((DataBuffer = (caddr_t)kmem_zalloc(DL_SLIM_SEG_BYTE_COUNT,
@@ -1701,16 +1682,20 @@
 
 	mb = (MAILBOX *)mbox;
 
+	AbsChangeParams = emlxs_build_parms(Buffer,
+	    &AbsWakeUpParms, len, AifHdr);
+
 	Buffer += sizeof (AIF_HDR);
 
-	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg, "Erasing flash...");
-
-	if (DwcFile) {
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg, "Erasing flash...");
+
+	if (AifHdr->ImageBase == 0x20000) {
+		/* DWC File */
 		emlxs_format_prog_flash(mbox, 0x20000, 0x50000, ERASE_FLASH, 0,
-		    0, 0, NULL);
+		    0, 0, NULL, 0);
 	} else {
 		emlxs_format_prog_flash(mbox, DlToAddr, DlByteCount,
-		    ERASE_FLASH, 0, 0, 0, NULL);
+		    ERASE_FLASH, 0, 0, 0, NULL, 0);
 	}
 
 	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
@@ -1723,7 +1708,7 @@
 		goto EXIT_ABS_DOWNLOAD;
 	}
 
-	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
 	    "Programming flash...");
 
 	while (DlByteCount) {
@@ -1750,7 +1735,7 @@
 		    sizeof (MAILBOX)), (DlCount / sizeof (uint32_t)));
 
 		emlxs_format_prog_flash(mbox, DlToAddr, DlCount,
-		    PROGRAM_FLASH, (DlByteCount) ? 0 : 1, 0, DlCount, NULL);
+		    PROGRAM_FLASH, (DlByteCount) ? 0 : 1, 0, DlCount, NULL, 0);
 
 		if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
 		    MBX_SUCCESS) {
@@ -1779,31 +1764,12 @@
 	}
 #endif  /* FMA_SUPPORT */
 
-	bzero((caddr_t)&ImageHdr, sizeof (IMAGE_HDR));
-	ImageHdr.Id.Type = FUNC_FIRMWARE;
-
-	switch (MaxRbusSramSize) {
-	case REDUCED_RBUS_SRAM_CFG:
-		ImageHdr.Id.Id = REDUCED_SRAM_CFG_PROG_ID;
-		break;
-	case FULL_RBUS_SRAM_CFG:
-		ImageHdr.Id.Id = FULL_SRAM_CFG_PROG_ID;
-		break;
-	default:
-		ImageHdr.Id.Id = OTHER_SRAM_CFG_PROG_ID;
-		break;
-	}
-
 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg, "Updating params...");
 
-	if (AbsWakeUpParms) {
+	if (AbsChangeParams) {
 		rval =
-		    emlxs_update_wakeup_parms(hba, AbsWakeUpParms,
+		    emlxs_update_wakeup_parms(hba, &AbsWakeUpParms,
 		    WakeUpParms);
-	} else {
-		rval =
-		    emlxs_update_boot_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr.Id, 1);
 	}
 
 EXIT_ABS_DOWNLOAD:
@@ -1827,16 +1793,20 @@
     uint32_t DlByteCount,
     uint32_t Function,
     uint32_t Complete,
-    uint32_t BdeAddress, uint32_t BdeSize, PROG_ID *ProgId)
+    uint32_t BdeAddress,
+    uint32_t BdeSize,
+    PROG_ID *ProgId,
+    uint32_t keep)
 {
 	MAILBOX *mb = (MAILBOX *)mbq;
 
 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
 
-	if (ProgId)
+	if (ProgId) {
 		mb->mbxCommand = MBX_DOWN_LOAD;
-	else
+	} else {
 		mb->mbxCommand = MBX_LOAD_SM;
+	}
 
 	mb->un.varLdSM.load_cmplt = Complete;
 	mb->un.varLdSM.method = DL_FROM_SLIM;
@@ -1844,6 +1814,7 @@
 	mb->un.varLdSM.erase_or_prog = Function;
 	mb->un.varLdSM.dl_to_adr = Base;
 	mb->un.varLdSM.dl_len = DlByteCount;
+	mb->un.varLdSM.keep = keep;
 
 	if (BdeSize) {
 		mb->un.varLdSM.un.dl_from_slim_offset = DL_FROM_SLIM_OFFSET;
@@ -1911,6 +1882,7 @@
 	MAILBOX *mb;
 	MAILBOXQ *mbox;
 	uint32_t rval = 0;
+	PROG_ID old_prog_id;
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
@@ -1928,6 +1900,7 @@
 		(void) emlxs_update_exp_rom(hba, WakeUpParms);
 	}
 
+	old_prog_id = WakeUpParms->u0.boot_bios_id;
 	WakeUpParms->u0.boot_bios_id = *prog_id;
 
 	emlxs_format_update_parms(mbox, WakeUpParms);
@@ -1937,6 +1910,7 @@
 		    "Unable to update boot wakeup parms: Mailbox cmd=%x "
 		    "status=%x", mb->mbxCommand, mb->mbxStatus);
 
+		WakeUpParms->u0.boot_bios_id = old_prog_id;
 		rval = 1;
 	}
 
@@ -1958,6 +1932,7 @@
 	uint32_t rval = 0;
 	MAILBOXQ *mbox;
 	MAILBOX *mb;
+	PROG_ID old_prog_id;
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
@@ -1967,8 +1942,12 @@
 		return (1);
 	}
 
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	    "FF: Updating parms...");
+
 	mb = (MAILBOX *)mbox;
 
+	old_prog_id = WakeUpParms->prog_id;
 	WakeUpParms->prog_id = *prog_id;
 
 	emlxs_format_update_parms(mbox, WakeUpParms);
@@ -1978,6 +1957,7 @@
 		    "Unable to update wakeup parameters: Mailbox cmd=%x "
 		    "status=%x", mb->mbxCommand, mb->mbxStatus);
 
+		WakeUpParms->prog_id = old_prog_id;
 		rval = 1;
 	}
 
@@ -1998,6 +1978,7 @@
 	uint32_t rval = 0;
 	MAILBOXQ *mbox;
 	MAILBOX *mb;
+	PROG_ID old_prog_id;
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
@@ -2007,8 +1988,12 @@
 		return (1);
 	}
 
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	    "SLI1: Updating parms...");
+
 	mb = (MAILBOX *)mbox;
 
+	old_prog_id = WakeUpParms->sli1_prog_id;
 	WakeUpParms->sli1_prog_id = *prog_id;
 
 	emlxs_format_update_parms(mbox, WakeUpParms);
@@ -2018,6 +2003,7 @@
 		    "Unable to update wakeup parameters. Mailbox cmd=%x "
 		    "status=%x", mb->mbxCommand, mb->mbxStatus);
 
+		WakeUpParms->sli1_prog_id = old_prog_id;
 		rval = 1;
 	}
 
@@ -2038,6 +2024,7 @@
 	uint32_t rval = 0;
 	MAILBOXQ *mbox;
 	MAILBOX *mb;
+	PROG_ID old_prog_id;
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
@@ -2047,8 +2034,12 @@
 		return (1);
 	}
 
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	    "SLI2: Updating parms...");
+
 	mb = (MAILBOX *)mbox;
 
+	old_prog_id = WakeUpParms->sli2_prog_id;
 	WakeUpParms->sli2_prog_id = *prog_id;
 
 	emlxs_format_update_parms(mbox, WakeUpParms);
@@ -2058,6 +2049,7 @@
 		    "Unable to update wakeup parameters. Mailbox cmd=%x "
 		    "status=%x", mb->mbxCommand, mb->mbxStatus);
 
+		WakeUpParms->sli2_prog_id = old_prog_id;
 		rval = 1;
 	}
 
@@ -2078,6 +2070,7 @@
 	uint32_t rval = 0;
 	MAILBOXQ *mbox;
 	MAILBOX *mb;
+	PROG_ID old_prog_id;
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
@@ -2087,8 +2080,12 @@
 		return (1);
 	}
 
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	    "SLI3: Updating parms...");
+
 	mb = (MAILBOX *)mbox;
 
+	old_prog_id = WakeUpParms->sli3_prog_id;
 	WakeUpParms->sli3_prog_id = *prog_id;
 
 	emlxs_format_update_parms(mbox, WakeUpParms);
@@ -2098,6 +2095,7 @@
 		    "Unable to update wakeup parameters. Mailbox cmd=%x "
 		    "status=%x", mb->mbxCommand, mb->mbxStatus);
 
+		WakeUpParms->sli3_prog_id = old_prog_id;
 		rval = 1;
 	}
 
@@ -2118,6 +2116,7 @@
 	uint32_t rval = 0;
 	MAILBOXQ *mbox;
 	MAILBOX *mb;
+	PROG_ID old_prog_id;
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
@@ -2127,8 +2126,12 @@
 		return (1);
 	}
 
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+	    "SLI4: Updating parms...");
+
 	mb = (MAILBOX *)mbox;
 
+	old_prog_id = WakeUpParms->sli4_prog_id;
 	WakeUpParms->sli4_prog_id = *prog_id;
 
 	emlxs_format_update_parms(mbox, WakeUpParms);
@@ -2138,6 +2141,7 @@
 		    "Unable to update wakeup parameters. Mailbox cmd=%x "
 		    "status=%x", mb->mbxCommand, mb->mbxStatus);
 
+		WakeUpParms->sli4_prog_id = old_prog_id;
 		rval = 1;
 	}
 
@@ -2150,13 +2154,184 @@
 } /* emlxs_update_sli4_wakeup_parms() */
 
 
+static uint32_t
+emlxs_clean_flash(emlxs_hba_t *hba,
+    PWAKE_UP_PARMS OldWakeUpParms, PWAKE_UP_PARMS NewWakeUpParms)
+{
+	emlxs_port_t *port = &PPORT;
+	PROG_ID load_list[MAX_LOAD_ENTRY];
+	PROG_ID *wakeup_list[MAX_LOAD_ENTRY];
+	uint32_t count;
+	uint32_t i;
+	uint32_t j;
+	uint32_t k = 0;
+	uint32_t *wptr;
+
+	if (!NewWakeUpParms) {
+		return (1);
+	}
+
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+	    "Cleaning flash...");
+
+	/* If old wakeup parameter list is available, */
+	/* then cleanup old entries */
+	if (OldWakeUpParms) {
+		if (bcmp(&OldWakeUpParms->prog_id, &NewWakeUpParms->prog_id,
+		    sizeof (PROG_ID))) {
+
+			wptr = (uint32_t *)&OldWakeUpParms->prog_id;
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "OLD:      prog_id: 0x%08x 0x%08x  Removing.",
+			    wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba,
+			    &OldWakeUpParms->prog_id);
+		}
+
+		if (bcmp(&OldWakeUpParms->u0.boot_bios_id,
+		    &NewWakeUpParms->u0.boot_bios_id, sizeof (PROG_ID))) {
+
+			wptr = (uint32_t *)&OldWakeUpParms->u0.boot_bios_id;
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "OLD: boot_bios_id: 0x%08x 0x%08x  Removing.",
+			    wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba,
+			    &OldWakeUpParms->u0.boot_bios_id);
+		}
+
+		if (bcmp(&OldWakeUpParms->sli1_prog_id,
+		    &NewWakeUpParms->sli1_prog_id, sizeof (PROG_ID))) {
+
+			wptr = (uint32_t *)&OldWakeUpParms->sli1_prog_id;
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "OLD: sli1_prog_id: 0x%08x 0x%08x  Removing.",
+			    wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba,
+			    &OldWakeUpParms->sli1_prog_id);
+		}
+
+		if (bcmp(&OldWakeUpParms->sli2_prog_id,
+		    &NewWakeUpParms->sli2_prog_id, sizeof (PROG_ID))) {
+
+			wptr = (uint32_t *)&OldWakeUpParms->sli2_prog_id;
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "OLD: sli2_prog_id: 0x%08x 0x%08x  Removing.",
+			    wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba,
+			    &OldWakeUpParms->sli2_prog_id);
+		}
+
+		if (bcmp(&OldWakeUpParms->sli3_prog_id,
+		    &NewWakeUpParms->sli3_prog_id, sizeof (PROG_ID))) {
+
+			wptr = (uint32_t *)&OldWakeUpParms->sli3_prog_id;
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "OLD: sli3_prog_id: 0x%08x 0x%08x  Removing.",
+			    wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba,
+			    &OldWakeUpParms->sli3_prog_id);
+		}
+
+		if (bcmp(&OldWakeUpParms->sli4_prog_id,
+		    &NewWakeUpParms->sli4_prog_id, sizeof (PROG_ID))) {
+
+			wptr = (uint32_t *)&OldWakeUpParms->sli4_prog_id;
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "OLD: sli4_prog_id: 0x%08x 0x%08x  Removing.",
+			    wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba,
+			    &OldWakeUpParms->sli4_prog_id);
+		}
+
+		return (0);
+	}
+
+	/* Otherwise use the current load list */
+	count = emlxs_get_load_list(hba, load_list);
+
+	if (!count) {
+		return (1);
+	}
+
+	/* Init the wakeup list */
+	wptr = (uint32_t *)&NewWakeUpParms->prog_id;
+	if (*wptr) {
+		wakeup_list[k++] = &NewWakeUpParms->prog_id;
+	}
+
+	wptr = (uint32_t *)&NewWakeUpParms->u0.boot_bios_id;
+	if (*wptr) {
+		wakeup_list[k++] = &NewWakeUpParms->u0.boot_bios_id;
+	}
+
+	wptr = (uint32_t *)&NewWakeUpParms->sli1_prog_id;
+	if (*wptr) {
+		wakeup_list[k++] = &NewWakeUpParms->sli1_prog_id;
+	}
+
+	wptr = (uint32_t *)&NewWakeUpParms->sli2_prog_id;
+	if (*wptr) {
+		wakeup_list[k++] = &NewWakeUpParms->sli2_prog_id;
+	}
+
+	wptr = (uint32_t *)&NewWakeUpParms->sli3_prog_id;
+	if (*wptr) {
+		wakeup_list[k++] = &NewWakeUpParms->sli3_prog_id;
+	}
+
+	wptr = (uint32_t *)&NewWakeUpParms->sli4_prog_id;
+	if (*wptr) {
+		wakeup_list[k++] = &NewWakeUpParms->sli4_prog_id;
+	}
+
+	if (k == 0) {
+		return (0);
+	}
+
+	/* Match load list to wakeup list */
+	for (i = 0; i < count; i++) {
+
+		wptr = (uint32_t *)&load_list[i];
+
+		for (j = 0; j < k; j++) {
+			if (bcmp((uint8_t *)wakeup_list[j],
+			    (uint8_t *)&load_list[i], sizeof (PROG_ID)) == 0) {
+				break;
+			}
+		}
+
+		/* No match */
+		if (j == k) {
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "Load List[%d]: %08x %08x  Removing.",
+			    i, wptr[0], wptr[1]);
+
+			(void) emlxs_delete_load_entry(hba, &load_list[i]);
+		} else {
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+			    "Load List[%d]: %08x %08x  Preserving.",
+			    i, wptr[0], wptr[1]);
+		}
+	}
+
+	return (0);
+
+} /* emlxs_clean_flash() */
+
+
 /* ARGSUSED */
 static uint32_t
 emlxs_start_rel_download(emlxs_hba_t *hba,
     PIMAGE_HDR ImageHdr,
     caddr_t Buffer,
     PWAKE_UP_PARMS WakeUpParms,
-    uint32_t MaxRbusSramSize, uint32_t MaxIbusSramSize)
+    uint32_t dwc_flag)
 {
 	emlxs_port_t *port = &PPORT;
 	MAILBOXQ *mbox;
@@ -2164,21 +2339,23 @@
 	uint32_t *Src;
 	uint32_t *Dst;
 	caddr_t DataBuffer = NULL;
-	uint32_t rval = 1;
-	uint32_t DlByteCount = ImageHdr->BlockSize;
+	uint32_t rval = 0;
+	uint32_t DlByteCount;
 	uint32_t SegSize = DL_SLIM_SEG_BYTE_COUNT;
 	uint32_t DlCount;
 	uint32_t i;
-
-	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-	    "Performing relative download...");
+	uint32_t *wptr;
+
+	wptr = (uint32_t *)&ImageHdr->Id;
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
+	    "Relative download: %08x %08x", wptr[0], wptr[1]);
 
 	if ((DataBuffer = (caddr_t)kmem_zalloc(DL_SLIM_SEG_BYTE_COUNT,
 	    KM_NOSLEEP)) == NULL) {
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
 		    "Unable to allocate data buffer.");
 
-		return (rval);
+		return (1);
 	}
 
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
@@ -2188,60 +2365,31 @@
 
 		kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
 
-		return (rval);
-	}
-
-	if (ImageHdr->Id.Type == FUNC_FIRMWARE) {
-		switch (MaxRbusSramSize) {
-		case REDUCED_RBUS_SRAM_CFG:
-			if (ImageHdr->Id.Id != REDUCED_SRAM_CFG_PROG_ID) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_image_bad_msg,
-				    "Invalid header id.");
-
-				return (1);
-			}
-			break;
-		case FULL_RBUS_SRAM_CFG:
-			if (ImageHdr->Id.Id != FULL_SRAM_CFG_PROG_ID) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_image_bad_msg,
-				    "Invalid header id.");
-
-				return (1);
-			}
-			break;
-		default:
-			if (ImageHdr->Id.Id != OTHER_SRAM_CFG_PROG_ID) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_image_bad_msg,
-				    "Invalid header id.");
-
-				return (1);
-			}
-			break;
-		}
+		return (1);
 	}
 
 	mb = (MAILBOX *)mbox;
 
+	DlByteCount = ImageHdr->BlockSize;
+
 	emlxs_format_prog_flash(mbox, 0, DlByteCount, ERASE_FLASH, 0, 0, 0,
-	    &ImageHdr->Id);
-
-	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg, "Erasing flash...");
-
-	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
+	    &ImageHdr->Id, 0);
+
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
+	    "  Erasing flash...");
+
+	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0);
+
+	if (rval) {
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
 		    "Unable to erase flash. Mailbox cmd=%x status=%x",
 		    mb->mbxCommand, mb->mbxStatus);
 
-		rval = 1;
-
 		goto EXIT_REL_DOWNLOAD;
 	}
 
-	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-	    "Programming flash...");
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
+	    "  Programming flash...");
 
 	while (DlByteCount) {
 		if (DlByteCount > SegSize) {
@@ -2269,16 +2417,16 @@
 		    0,
 		    DlCount,
 		    PROGRAM_FLASH,
-		    (DlByteCount) ? 0 : 1, 0, DlCount, &ImageHdr->Id);
-
-		if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
-		    MBX_SUCCESS) {
+		    (DlByteCount) ? 0 : 1,
+		    0, DlCount, &ImageHdr->Id, dwc_flag);
+
+		rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0);
+
+		if (rval) {
 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
 			    "Unable to program flash. Mailbox cmd=%x status=%x",
 			    mb->mbxCommand, mb->mbxStatus);
 
-			rval = 1;
-
 			goto EXIT_REL_DOWNLOAD;
 		}
 
@@ -2297,57 +2445,73 @@
 	}
 #endif  /* FMA_SUPPORT */
 
+	/* Update wakeup parameters */
 	switch (ImageHdr->Id.Type) {
 	case TEST_PROGRAM:
-		rval = 0;
 		break;
 
 	case FUNC_FIRMWARE:
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "FF: Updating parms...");
-		rval =
-		    emlxs_update_ff_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr->Id);
+		if (!dwc_flag) {
+			rval = emlxs_update_ff_wakeup_parms(hba, WakeUpParms,
+			    &ImageHdr->Id);
+		} else {
+			WakeUpParms->prog_id = ImageHdr->Id;
+		}
 		break;
 
 	case BOOT_BIOS:
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "BOOT: Updating parms...");
-		rval =
-		    emlxs_update_boot_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr->Id, 1);
+		if (!dwc_flag) {
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+			    "BOOT: Updating parms...");
+
+			rval = emlxs_update_boot_wakeup_parms(hba, WakeUpParms,
+			    &ImageHdr->Id, 1);
+		} else {
+			if (hba->wakeup_parms.u0.boot_bios_wd[0]) {
+				WakeUpParms->u0.boot_bios_id = ImageHdr->Id;
+			}
+
+			if (!(hba->model_info.chip &
+			    (EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP))) {
+				WakeUpParms->u1.EROM_prog_id = ImageHdr->Id;
+			}
+		}
 		break;
 
 	case SLI1_OVERLAY:
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "SLI1: Updating parms...");
-		rval =
-		    emlxs_update_sli1_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr->Id);
+		if (!dwc_flag) {
+			rval = emlxs_update_sli1_wakeup_parms(hba, WakeUpParms,
+			    &ImageHdr->Id);
+		} else {
+			WakeUpParms->sli1_prog_id = ImageHdr->Id;
+		}
 		break;
 
 	case SLI2_OVERLAY:
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "SLI2: Updating parms...");
-		rval =
-		    emlxs_update_sli2_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr->Id);
+		if (!dwc_flag) {
+			rval = emlxs_update_sli2_wakeup_parms(hba, WakeUpParms,
+			    &ImageHdr->Id);
+		} else {
+			WakeUpParms->sli2_prog_id = ImageHdr->Id;
+		}
 		break;
 
 	case SLI3_OVERLAY:
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "SLI3: Updating parms...");
-		rval =
-		    emlxs_update_sli3_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr->Id);
+		if (!dwc_flag) {
+			rval = emlxs_update_sli3_wakeup_parms(hba, WakeUpParms,
+			    &ImageHdr->Id);
+		} else {
+			WakeUpParms->sli3_prog_id = ImageHdr->Id;
+		}
 		break;
 
 	case SLI4_OVERLAY:
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "SLI4: Updating parms...");
-		rval =
-		    emlxs_update_sli4_wakeup_parms(hba, WakeUpParms,
-		    &ImageHdr->Id);
+		if (!dwc_flag) {
+			rval = emlxs_update_sli4_wakeup_parms(hba, WakeUpParms,
+			    &ImageHdr->Id);
+		} else {
+			WakeUpParms->sli4_prog_id = ImageHdr->Id;
+		}
 		break;
 
 	default:
@@ -2371,6 +2535,74 @@
 } /* emlxs_start_rel_download() */
 
 
+static uint32_t
+emlxs_proc_rel_2mb(emlxs_hba_t *hba, caddr_t buffer, emlxs_fw_image_t *fw_image)
+{
+	emlxs_port_t *port = &PPORT;
+	uint32_t rval = 0;
+	WAKE_UP_PARMS RelWakeUpParms;
+	WAKE_UP_PARMS WakeUpParms;
+	uint32_t i;
+	IMAGE_HDR ImageHdr;
+	caddr_t bptr;
+	uint32_t flash_cleaned = 0;
+
+	if (emlxs_read_wakeup_parms(hba, &WakeUpParms, 0)) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
+		    "Unable to get wakeup parameters.");
+
+		return (EMLXS_IMAGE_FAILED);
+	}
+
+download:
+
+	bcopy(&WakeUpParms, &RelWakeUpParms, sizeof (WAKE_UP_PARMS));
+
+	for (i = 0; i < MAX_PROG_TYPES; i++) {
+		if (!fw_image->prog[i].version) {
+			continue;
+		}
+
+		bptr = buffer + fw_image->prog[i].offset;
+
+		bcopy(bptr, &ImageHdr, sizeof (IMAGE_HDR));
+
+		rval = emlxs_start_rel_download(hba, &ImageHdr, bptr,
+		    &RelWakeUpParms, 1);
+
+		if (rval) {
+			EMLXS_MSGF(EMLXS_CONTEXT,
+			    &emlxs_download_failed_msg,
+			    "Failed to program flash.");
+
+			if ((rval == NO_FLASH_MEM_AVAIL) && !flash_cleaned) {
+				/* Cleanup using current load list */
+				(void) emlxs_clean_flash(hba, 0, &WakeUpParms);
+
+				flash_cleaned = 1;
+				goto download;
+			}
+
+			return (EMLXS_IMAGE_FAILED);
+		}
+	}
+
+	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
+	    "Updating wakeup parameters.");
+
+	if (emlxs_update_wakeup_parms(hba, &RelWakeUpParms,
+	    &RelWakeUpParms)) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
+		    "Unable to update parameters.");
+
+		return (EMLXS_IMAGE_FAILED);
+	}
+
+	return (0);
+
+} /* emlxs_proc_rel_2mb() */
+
+
 #define	FLASH_POLLING_BIT	0x80
 #define	FLASH_ERROR_BIT		0x20
 
@@ -2639,6 +2871,46 @@
 } /* emlxs_erase_fcode_flash() */
 
 
+static uint32_t
+emlxs_delete_load_entry(emlxs_hba_t *hba, PROG_ID *progId)
+{
+	emlxs_port_t *port = &PPORT;
+	MAILBOXQ *mbox = NULL;
+	MAILBOX *mb;
+	uint32_t rval = 0;
+
+	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
+	    KM_NOSLEEP)) == NULL) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+		    "Unable to allocate mailbox buffer.");
+
+		return (1);
+	}
+
+	mb = (MAILBOX *)mbox;
+	mb->mbxCommand = MBX_DEL_LD_ENTRY;
+	mb->un.varDelLdEntry.list_req = FLASH_LOAD_LIST;
+	mb->un.varDelLdEntry.prog_id = *progId;
+
+	if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
+		    "Unable to delete load entry: Mailbox cmd=%x status=%x",
+		    mb->mbxCommand, mb->mbxStatus);
+
+		rval = 1;
+	}
+
+done:
+
+	if (mbox) {
+		kmem_free(mbox, sizeof (MAILBOXQ));
+	}
+
+	return (rval);
+
+} /* emlxs_delete_load_entry() */
+
+
 extern uint32_t
 emlxs_get_load_list(emlxs_hba_t *hba, PROG_ID *load_list)
 {
@@ -2646,7 +2918,7 @@
 	LOAD_ENTRY *LoadEntry;
 	LOAD_LIST *LoadList = NULL;
 	uint32_t i;
-	uint32_t rval = 0;
+	uint32_t count = 0;
 
 	bzero(load_list, (sizeof (PROG_ID) * MAX_LOAD_ENTRY));
 
@@ -2655,12 +2927,10 @@
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
 		    "Unable to allocate LOADLIST buffer.");
 
-		rval = 1;
 		goto done;
 	}
 
 	if (emlxs_read_load_list(hba, LoadList)) {
-		rval = 1;
 		goto done;
 	}
 
@@ -2668,10 +2938,11 @@
 		LoadEntry = &LoadList->load_entry[i];
 		if ((LoadEntry->un.wd[0] != 0) &&
 		    (LoadEntry->un.wd[0] != 0xffffffff)) {
-			load_list[i] = LoadEntry->un.id;
 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
-			    "Load List[%d]: %08x %08x", i,
+			    "Load List[%d]: %08x %08x", count,
 			    LoadEntry->un.wd[0], LoadEntry->un.wd[1]);
+
+			load_list[count++] = LoadEntry->un.id;
 		}
 	}
 
@@ -2681,7 +2952,7 @@
 		kmem_free(LoadList, sizeof (LOAD_LIST));
 	}
 
-	return (rval);
+	return (count);
 
 } /* emlxs_get_load_list() */
 
@@ -2920,74 +3191,11 @@
 } /* emlxs_read_load_list() */
 
 
-static uint32_t
-emlxs_get_abs_image_type(caddr_t Buffer, uint32_t BufferSize)
-{
-	uint32_t Version;
-
-	if (BufferSize < (SLI_VERSION_LOC + 4))
-		return (0xffffffff);
-
-	Buffer += SLI_VERSION_LOC;
-	Version = *((uint32_t *)Buffer);
-
-	return (Version);
-
-} /* emlxs_get_abs_image_type() */
-
-
-static uint32_t
-emlxs_get_dwc_image_type(emlxs_hba_t *hba, caddr_t Buffer,
-    uint32_t BufferSize, PAIF_HDR AifHeader)
-{
-	emlxs_port_t *port = &PPORT;
-	IMAGE_HDR ImageHdr;
-	uint32_t NextImage;
-	uint32_t i;
-	uint8_t *Sptr;
-	uint8_t *Dptr;
-	uint32_t HwId = 0xffffffff;
-
-	NextImage = SLI_IMAGE_START - AifHeader->ImageBase;
-
-	while (BufferSize > NextImage) {
-		Sptr = (uint8_t *)&Buffer[NextImage];
-		Dptr = (uint8_t *)&ImageHdr;
-		for (i = 0; i < sizeof (IMAGE_HDR); i++) {
-			Dptr[i] = Sptr[i];
-		}
-
-		if (ImageHdr.BlockSize == 0xffffffff)
-			break;
-
-		switch (ImageHdr.Id.Type) {
-		case 6:
-		case 7:
-			if (HwId == 0xffffffff) {
-				HwId = ImageHdr.Id.Id;
-			}
-
-			if (HwId != ImageHdr.Id.Id) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_image_bad_msg,
-				    "Invalid hardware id. %x %x", HwId,
-				    ImageHdr.Id.Id);
-			}
-			break;
-		}
-
-		NextImage += ImageHdr.BlockSize;
-	}
-
-	return (HwId);
-
-} /* emlxs_get_dwc_image_type() */
-
 
 static int
 emlxs_build_parms(caddr_t Buffer,
     PWAKE_UP_PARMS AbsWakeUpParms,
-    uint32_t BufferSize, PAIF_HDR AifHeader, int32_t DwcFile)
+    uint32_t BufferSize, PAIF_HDR AifHeader)
 {
 	IMAGE_HDR ImageHdr;
 	uint32_t NextImage;
@@ -2998,7 +3206,8 @@
 
 	bzero((caddr_t)AbsWakeUpParms, sizeof (WAKE_UP_PARMS));
 
-	if (!DwcFile && ((AifHeader->RoSize + AifHeader->RwSize) <= 0x20000)) {
+	if ((AifHeader->ImageBase != 0x20000) &&
+	    ((AifHeader->RoSize + AifHeader->RwSize) <= 0x20000)) {
 		return (FALSE);
 	}
 
@@ -3257,6 +3466,164 @@
 } /* emlxs_validate_version() */
 
 
+static void
+emlxs_verify_image(emlxs_hba_t *hba, emlxs_fw_image_t *fw_image)
+{
+	emlxs_port_t *port = &PPORT;
+	emlxs_vpd_t *vpd = &VPD;
+	uint32_t i;
+	uint32_t count;
+
+	/* Check for AWC file */
+	if (fw_image->awc.version) {
+		if (fw_image->awc.version == vpd->postKernRev) {
+			fw_image->awc.version = 0;
+		}
+
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+		    "AWC file: KERN: old=%s  new=%s  %s.",
+		    vpd->postKernName,
+		    fw_image->awc.label,
+		    (fw_image->awc.version)? "Update":"Skip");
+	}
+
+	/* Check for BWC file */
+	if (fw_image->bwc.version) {
+		if (strcmp(vpd->fcode_version, fw_image->bwc.label) == 0) {
+			fw_image->bwc.version = 0;
+		}
+
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+		    "BWC file: BOOT: old=%s  new=%s  %s.",
+		    vpd->fcode_version,
+		    fw_image->bwc.label,
+		    (fw_image->bwc.version)? "Update":"Skip");
+	}
+
+	/* Check for DWC file */
+	if (fw_image->dwc.version) {
+		/* Check for program files */
+		count = 0;
+		for (i = 0; i < MAX_PROG_TYPES; i++) {
+			if (!fw_image->prog[i].version) {
+				continue;
+			}
+
+			/* Skip components that don't need updating */
+			switch (i) {
+			case TEST_PROGRAM:
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: TEST:             new=%s  "
+				    "Update.",
+				    fw_image->prog[i].label);
+				break;
+
+			case BOOT_BIOS:
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: BOOT:             new=%s  "
+				    "Update.",
+				    fw_image->prog[i].label);
+				break;
+
+			case FUNC_FIRMWARE:
+				if (vpd->opFwRev &&
+				    (fw_image->prog[i].version ==
+				    vpd->opFwRev)) {
+					fw_image->prog[i].version = 0;
+				}
+
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: STUB: old=%s  new=%s  %s.",
+				    vpd->opFwName,
+				    fw_image->prog[i].label,
+				    (fw_image->prog[i].version)?
+				    "Update":"Skip");
+				break;
+
+			case SLI1_OVERLAY:
+				if (vpd->sli1FwRev &&
+				    (fw_image->prog[i].version ==
+				    vpd->sli1FwRev)) {
+					fw_image->prog[i].version = 0;
+				}
+
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: SLI1: old=%s  new=%s  %s.",
+				    vpd->sli1FwName,
+				    fw_image->prog[i].label,
+				    (fw_image->prog[i].version)?
+				    "Update":"Skip");
+				break;
+
+			case SLI2_OVERLAY:
+				if (vpd->sli2FwRev &&
+				    (fw_image->prog[i].version ==
+				    vpd->sli2FwRev)) {
+					fw_image->prog[i].version = 0;
+				}
+
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: SLI2: old=%s  new=%s  %s.",
+				    vpd->sli2FwName,
+				    fw_image->prog[i].label,
+				    (fw_image->prog[i].version)?
+				    "Update":"Skip");
+				break;
+
+			case SLI3_OVERLAY:
+				if (vpd->sli3FwRev &&
+				    (fw_image->prog[i].version ==
+				    vpd->sli3FwRev)) {
+					fw_image->prog[i].version = 0;
+				}
+
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: SLI3: old=%s  new=%s  %s.",
+				    vpd->sli3FwName,
+				    fw_image->prog[i].label,
+				    (fw_image->prog[i].version)?
+				    "Update":"Skip");
+				break;
+
+			case SLI4_OVERLAY:
+				if (vpd->sli4FwRev &&
+				    (fw_image->prog[i].version ==
+				    vpd->sli4FwRev)) {
+					fw_image->prog[i].version = 0;
+				}
+
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: SLI4: old=%s  new=%s  %s.",
+				    vpd->sli4FwRev,
+				    fw_image->prog[i].label,
+				    (fw_image->prog[i].version)?
+				    "Update":"Skip");
+				break;
+
+			default:
+				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+				    "DWC file: type=%x version=%x label=%s  "
+				    "Update.",
+				    i,
+				    fw_image->prog[i].version,
+				    fw_image->prog[i].label);
+			}
+
+			if (fw_image->prog[i].version) {
+				count++;
+			}
+		}
+
+		if (!count) {
+			fw_image->dwc.version = 0;
+		}
+	}
+
+	return;
+
+} /* emlxs_verify_image() */
+
+
 static uint32_t
 emlxs_validate_image(emlxs_hba_t *hba, caddr_t Buffer, uint32_t Size,
     emlxs_fw_image_t *image)
@@ -3266,6 +3633,7 @@
 	AIF_HDR AifHdr;
 	IMAGE_HDR ImageHdr;
 	uint32_t NextImage;
+	uint32_t count;
 	uint32_t FileType;
 	uint32_t FileLen = 0;
 	uint32_t TotalLen = 0;
@@ -3379,6 +3747,7 @@
 				NextImage = sizeof (AIF_HDR) + 4;
 				BufferSize = AifHdr.RoSize + AifHdr.RwSize;
 
+				count = 0;
 				while (BufferSize > NextImage) {
 					bcopy(&bptr[NextImage], &ImageHdr,
 					    sizeof (IMAGE_HDR));
@@ -3416,10 +3785,19 @@
 						return (rval);
 					}
 
+					count++;
 					NextImage += ImageHdr.BlockSize;
 
 				}	/* while () */
 
+				if (count == 0) {
+					EMLXS_MSGF(EMLXS_CONTEXT,
+					    &emlxs_image_bad_msg,
+					    "DWC file has no PRG images.");
+
+					return (EMLXS_IMAGE_BAD);
+				}
+
 				break;
 			}
 
@@ -3520,7 +3898,9 @@
 
 			NextImage += ImageHdr.BlockSize;
 		}
-	} else {
+
+	} else { /* PRG File */
+
 		/* Precheck image size */
 		if (Size < sizeof (IMAGE_HDR)) {
 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
@@ -3570,8 +3950,10 @@
 
 		/* Acquire the versions */
 		image->prog[type].version =
-		    (ImageHdr.Id.Type << 24) | (ImageHdr.Id.
-		    Id << 16) | (ImageHdr.Id.Ver << 8) | ImageHdr.Id.Rev;
+		    (ImageHdr.Id.Type << 24) |
+		    (ImageHdr.Id.Id << 16) |
+		    (ImageHdr.Id.Ver << 8) |
+		    ImageHdr.Id.Rev;
 
 		image->prog[type].revcomp = ImageHdr.Id.un.revcomp;
 
@@ -3584,23 +3966,19 @@
 
 	/*
 	 * This checks if a DragonFly (pre-V2 ASIC) SLI2
-	 * image file is greater than version 3.8
+	 * image file is < version 3.8
 	 */
 	if (FC_JEDEC_ID(vpd->biuRev) == DRAGONFLY_JEDEC_ID) {
-		if (image->prog[SLI2_OVERLAY].version != 0) {
-			ver = (image->prog[SLI2_OVERLAY].version &
-			    0x0000ff00) >> 8;
-
-			if ((((ver & 0xf0) == 0x30) &&
-			    ((ver & 0x0f) >= 0x08)) ||
-			    ((ver & 0xf0) > 0x30)) {
-				EMLXS_MSGF(EMLXS_CONTEXT,
-				    &emlxs_image_incompat_msg,
-				    "ASIC Check: Image requires DragonFly "
-				    "V2 ASIC");
-
-				return (EMLXS_IMAGE_INCOMPATIBLE);
-			}
+		ver = (image->prog[SLI2_OVERLAY].version &
+		    0x0000ff00) >> 8;
+
+		if (ver >= 0x38) {
+			EMLXS_MSGF(EMLXS_CONTEXT,
+			    &emlxs_image_incompat_msg,
+			    "ASIC Check: Image requires DragonFly "
+			    "V2 ASIC");
+
+			return (EMLXS_IMAGE_INCOMPATIBLE);
 		}
 	}
 
@@ -3752,63 +4130,14 @@
     uint32_t offline, emlxs_fw_image_t *fw_image)
 {
 	emlxs_port_t *port = &PPORT;
-	caddr_t AwcBuffer = NULL;
-	caddr_t BwcBuffer = NULL;
-	caddr_t DwcBuffer = NULL;
-	AIF_HDR *AwcAifHdr;
-	AIF_HDR *BwcAifHdr;
-	AIF_HDR *DwcAifHdr;
-	uint32_t BWCflag;
-	emlxs_vpd_t *vpd;
-	uint32_t i;
-	uint32_t count;
-	uint32_t extType = 0;
 	uint32_t rval = 0;
 
-	vpd = &VPD;
-
-	/* Check for AWC file */
-	if (fw_image->awc.version) {
-		AwcBuffer = buffer + fw_image->awc.offset;
-		AwcAifHdr = (AIF_HDR *)AwcBuffer;
-	}
-
-	/* Check for BWC file */
-	if (fw_image->bwc.version) {
-		extType = BWCext;
-		BwcBuffer = buffer + fw_image->bwc.offset;
-		BwcAifHdr = (AIF_HDR *)BwcBuffer;
-	}
-
-	/* Check for DWC file */
-	if (fw_image->dwc.version) {
-		extType = DWCext;
-		DwcBuffer = buffer + fw_image->dwc.offset;
-		DwcAifHdr = (AIF_HDR *)DwcBuffer;
-	}
-
-	/* Check for program files */
-	count = 0;
-	for (i = 0; i < MAX_PROG_TYPES; i++) {
-		if (fw_image->prog[i].version) {
-			count++;
-		}
-	}
-
-	if (count > 1) {
-		extType = ALLext;
-
-		if (fw_image->bwc.version) {
-			BWCflag = ALL_WITH_BWC;
-		} else {
-			BWCflag = ALL_WITHOUT_BWC;
-		}
-	} else {
-		BWCflag = NO_ALL;
-	}
-
 	/* If nothing to download then quit now */
-	if (!AwcBuffer && !DwcBuffer && !BwcBuffer) {
+	if (!fw_image->awc.version &&
+	    !fw_image->dwc.version &&
+	    !fw_image->bwc.version) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
+		    "Nothing new to update.  Exiting.");
 		return (0);
 	}
 
@@ -3825,65 +4154,33 @@
 		}
 	}
 
-	if (AwcBuffer) {
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "AWC file: KERN: old=%s  new=%s ", vpd->postKernName,
-		    fw_image->awc.label);
-
+	if (fw_image->awc.version) {
 		rval = emlxs_proc_abs_2mb(hba,
-		    AwcAifHdr, AwcBuffer, FILE_TYPE_AWC, BWCflag, extType);
+		    (buffer + fw_image->awc.offset),
+		    FILE_TYPE_AWC, 0);
 
 		if (rval) {
 			goto SLI_DOWNLOAD_2MB_EXIT;
 		}
 	}
 
-	if (DwcBuffer) {
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "DWC file: TEST:             new=%s ",
-		    fw_image->prog[TEST_PROGRAM].label);
-
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "DWC file: STUB: old=%s  new=%s ", vpd->opFwName,
-		    fw_image->prog[FUNC_FIRMWARE].label);
-
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "DWC file: SLI1: old=%s  new=%s ", vpd->sli1FwName,
-		    fw_image->prog[SLI1_OVERLAY].label);
-
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "DWC file: SLI2: old=%s  new=%s ", vpd->sli2FwName,
-		    fw_image->prog[SLI2_OVERLAY].label);
-
-		if (vpd->sli3FwRev || fw_image->prog[SLI3_OVERLAY].version) {
-			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-			    "DWC file: SLI3: old=%s  new=%s ",
-			    vpd->sli3FwName,
-			    fw_image->prog[SLI3_OVERLAY].label);
-		}
-
-		if (vpd->sli4FwRev || fw_image->prog[SLI4_OVERLAY].version) {
-			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-			    "DWC file: SLI4: old=%s  new=%s ",
-			    vpd->sli4FwName,
-			    fw_image->prog[SLI4_OVERLAY].label);
-		}
-
+	if (fw_image->bwc.version) {
 		rval = emlxs_proc_abs_2mb(hba,
-		    DwcAifHdr, DwcBuffer, FILE_TYPE_DWC, BWCflag, extType);
+		    (buffer + fw_image->bwc.offset),
+		    FILE_TYPE_BWC,
+		    (fw_image->dwc.version)? ALLext:BWCext);
 
 		if (rval) {
 			goto SLI_DOWNLOAD_2MB_EXIT;
 		}
 	}
 
-	if (BwcBuffer) {
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
-		    "BWC file: BOOT: old=%s  new=%s ", vpd->fcode_version,
-		    fw_image->bwc.label);
-
-		rval = emlxs_proc_abs_2mb(hba,
-		    BwcAifHdr, BwcBuffer, FILE_TYPE_BWC, BWCflag, extType);
+	if (fw_image->dwc.version) {
+		rval = emlxs_proc_rel_2mb(hba, buffer, fw_image);
+
+		if (rval) {
+			goto SLI_DOWNLOAD_2MB_EXIT;
+		}
 	}
 
 SLI_DOWNLOAD_2MB_EXIT:
@@ -3912,22 +4209,21 @@
  *
  */
 static uint32_t
-emlxs_proc_abs_2mb(emlxs_hba_t *hba,
-    PAIF_HDR AifHdr,
-    caddr_t EntireBuffer,
-    uint32_t FileType, uint32_t BWCflag, uint32_t extType)
+emlxs_proc_abs_2mb(emlxs_hba_t *hba, caddr_t EntireBuffer,
+    uint32_t FileType, uint32_t extType)
 {
 	emlxs_port_t *port = &PPORT;
+	PAIF_HDR AifHdr;
 	caddr_t Buffer = NULL;
 	caddr_t DataBuffer = NULL;
 	uint32_t *Src;
 	uint32_t *Dst;
 	MAILBOXQ *mbox;
 	MAILBOX *mb;
-	uint32_t DlByteCount = AifHdr->RoSize + AifHdr->RwSize;
+	uint32_t DlByteCount;
 	uint32_t rval = 0;
 	uint32_t SegSize = DL_SLIM_SEG_BYTE_COUNT;
-	uint32_t DlToAddr = AifHdr->ImageBase;
+	uint32_t DlToAddr;
 	uint32_t DlCount;
 	WAKE_UP_PARMS AbsWakeUpParms;
 	uint32_t i;
@@ -3935,9 +4231,11 @@
 	uint32_t EraseByteCount;
 	uint32_t AreaId;
 	uint32_t RspProgress = 0;
-	uint32_t numBootImage = 0;
-	uint32_t ParamsChg = 0;
-	uint32_t BufferSize;
+	uint32_t ParamsChg;
+
+	AifHdr = (PAIF_HDR)EntireBuffer;
+	DlByteCount = AifHdr->RoSize + AifHdr->RwSize;
+	DlToAddr = AifHdr->ImageBase;
 
 	if ((DataBuffer = (caddr_t)kmem_zalloc(DL_SLIM_SEG_BYTE_COUNT,
 	    KM_NOSLEEP)) == NULL) {
@@ -3947,8 +4245,6 @@
 		return (EMLXS_IMAGE_FAILED);
 	}
 
-	bzero(DataBuffer, sizeof (DL_SLIM_SEG_BYTE_COUNT));
-
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
@@ -3961,18 +4257,18 @@
 
 	mb = (MAILBOX *)mbox;
 
-	BufferSize = DlByteCount + sizeof (AIF_HDR) + sizeof (uint32_t);
 	Buffer = EntireBuffer + sizeof (AIF_HDR);
 
 	switch (FileType) {
 	case FILE_TYPE_AWC:
+		ParamsChg = 0;
 		break;
 
 	case FILE_TYPE_BWC:
-		ParamsChg = emlxs_build_parms_2mb_bwc(hba,
+		rval = emlxs_build_parms_2mb_bwc(hba,
 		    AifHdr, extType, &AbsWakeUpParms);
 
-		if (ParamsChg == FALSE) {
+		if (rval == FALSE) {
 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
 			    "BWC build parms failed.");
 
@@ -3980,22 +4276,7 @@
 
 			goto EXIT_ABS_DOWNLOAD;
 		}
-		break;
-
-	case FILE_TYPE_DWC:
-		ParamsChg = emlxs_build_parms_2mb_dwc(hba,
-		    Buffer,
-		    BufferSize,
-		    AifHdr, &AbsWakeUpParms, BWCflag, extType, &numBootImage);
-
-		if (ParamsChg == FALSE) {
-			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
-			    "DWC build parms failed.");
-
-			rval = EMLXS_IMAGE_FAILED;
-
-			goto EXIT_ABS_DOWNLOAD;
-		}
+		ParamsChg = 1;
 		break;
 
 	default:
@@ -4190,7 +4471,7 @@
 
 	/* Read wakeup paramters */
 	if (emlxs_read_wakeup_parms(hba, AbsWakeUpParms, 0) ==
-	    CFG_DATA_NO_REGION) {
+	    (uint32_t)CFG_DATA_NO_REGION) {
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
 		    "Unable to get BWC parameters.");
 		return (FALSE);
@@ -4242,148 +4523,6 @@
 } /* emlxs_build_parms_2mb_bwc() */
 
 
-/* ARGSUSED */
-static uint32_t
-emlxs_build_parms_2mb_dwc(emlxs_hba_t *hba,
-    caddr_t Buffer,
-    uint32_t BufferSize,
-    PAIF_HDR AifHeader,
-    PWAKE_UP_PARMS AbsWakeUpParms,
-    uint32_t BWCflag, uint32_t extType, uint32_t *numBootImage)
-{
-	emlxs_port_t *port = &PPORT;
-	uint32_t NextImage;
-	uint32_t i;
-	IMAGE_HDR ImageHdr;
-	uint32_t *ptr1;
-	uint32_t *ptr2;
-	PROG_ID BootId[MAX_BOOTID];
-	uint32_t ChangeParams = FALSE;
-	WAKE_UP_PARMS WakeUpParms;
-	caddr_t Sptr;
-	caddr_t Dptr;
-
-	bzero(&BootId, (sizeof (PROG_ID)) * MAX_BOOTID);
-
-	/* Read wakeup paramters */
-	if (emlxs_read_wakeup_parms(hba, AbsWakeUpParms, 0) ==
-	    CFG_DATA_NO_REGION) {
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
-		    "Unable to get DWC parameters.");
-		return (FALSE);
-	}
-
-	bcopy((caddr_t)AbsWakeUpParms, (caddr_t)&WakeUpParms,
-	    sizeof (WAKE_UP_PARMS));
-
-	if (((BWCflag == ALL_WITHOUT_BWC) || (extType == DWCext)) &&
-	    (WakeUpParms.u0.boot_bios_wd[0])) {
-		*numBootImage = 0;
-	}
-
-	/* incoming buffer is without aif header */
-	NextImage = 0x84 - sizeof (AIF_HDR);
-	BufferSize -= (sizeof (AIF_HDR) + sizeof (uint32_t));
-
-	while (BufferSize > NextImage) {
-		Sptr = &Buffer[NextImage];
-		Dptr = (caddr_t)&ImageHdr;
-		for (i = 0; i < sizeof (IMAGE_HDR); i++) {
-			Dptr[i] = Sptr[i];
-		}
-
-		if (ImageHdr.BlockSize == 0xffffffff) {
-			break;
-		}
-
-		switch (ImageHdr.Id.Type) {
-		case TEST_PROGRAM:
-			break;
-
-		case FUNC_FIRMWARE:
-			AbsWakeUpParms->prog_id = ImageHdr.Id;
-			ChangeParams = TRUE;
-			break;
-
-		case BOOT_BIOS:
-			if (!WakeUpParms.u0.boot_bios_wd[0]) {
-				if (extType == DWCext) {
-					break;
-				} else if (BWCflag == ALL_WITHOUT_BWC) {
-					/* for possible future changes */
-					break;
-				}
-			}
-			ChangeParams = TRUE;
-
-			if (*numBootImage < MAX_BOOTID) {
-				BootId[*numBootImage] = ImageHdr.Id;
-				(*numBootImage)++;
-			}
-			break;
-
-		case SLI1_OVERLAY:
-			AbsWakeUpParms->sli1_prog_id = ImageHdr.Id;
-			ChangeParams = TRUE;
-			break;
-
-		case SLI2_OVERLAY:
-			AbsWakeUpParms->sli2_prog_id = ImageHdr.Id;
-			ChangeParams = TRUE;
-			break;
-
-		case SLI3_OVERLAY:
-			AbsWakeUpParms->sli3_prog_id = ImageHdr.Id;
-			ChangeParams = TRUE;
-			break;
-
-		case SLI4_OVERLAY:
-			AbsWakeUpParms->sli4_prog_id = ImageHdr.Id;
-			ChangeParams = TRUE;
-			break;
-		}
-
-		NextImage += ImageHdr.BlockSize;
-	}
-
-	if ((ChangeParams) && ((BWCflag == ALL_WITHOUT_BWC) ||
-	    (extType == DWCext))) {
-
-		if (*numBootImage > 1) {
-			for (i = 0; i < *numBootImage; i++) {
-				ptr1 =
-				    (uint32_t *)&WakeUpParms.u0.
-				    boot_bios_id;
-				ptr2 = (uint32_t *)&BootId[i];
-
-				if (ptr1[0] == ptr2[0]) {
-					AbsWakeUpParms->u1.EROM_prog_id =
-					    BootId[i];
-					(void) emlxs_update_exp_rom(hba,
-					    AbsWakeUpParms);
-					break;
-				}
-			}
-		} else {
-			if (*numBootImage == 1) {
-				ptr2 = (uint32_t *)&BootId[0];
-
-				if (WakeUpParms.u0.boot_bios_wd[0] == ptr2[0]) {
-					AbsWakeUpParms->u1.EROM_prog_id =
-					    BootId[0];
-					(void) emlxs_update_exp_rom(hba,
-					    AbsWakeUpParms);
-				}
-			}
-		}
-	}
-
-	return (ChangeParams);
-
-
-} /* emlxs_build_parms_2mb_dwc() */
-
-
 extern uint32_t
 emlxs_get_max_sram(emlxs_hba_t *hba, uint32_t *MaxRbusSize,
     uint32_t *MaxIbusSize)
@@ -4394,6 +4533,14 @@
 	uint32_t *Uptr;
 	uint32_t rval = 0;
 
+	if (MaxRbusSize) {
+		*MaxRbusSize = 0;
+	}
+
+	if (MaxIbusSize) {
+		*MaxIbusSize = 0;
+	}
+
 	if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
 	    KM_NOSLEEP)) == NULL) {
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
@@ -4425,8 +4572,13 @@
 		Uptr = (uint32_t *)&mb->un.varDmp.resp_offset;
 	}
 
-	*MaxRbusSize = Uptr[0];
-	*MaxIbusSize = Uptr[1];
+	if (MaxRbusSize) {
+		*MaxRbusSize = Uptr[0];
+	}
+
+	if (MaxIbusSize) {
+		*MaxIbusSize = Uptr[1];
+	}
 
 Exit_Function:
 
@@ -4684,6 +4836,7 @@
 	emlxs_vpd_t *vpd;
 	PROG_ID load_list[MAX_LOAD_ENTRY];
 	uint32_t i;
+	uint32_t count;
 
 	vpd = &VPD;
 
@@ -4716,12 +4869,14 @@
 		    &hba->wakeup_parms.u1.EROM_prog_id, 0);
 	} else {	/* (EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP) */
 
-		if (emlxs_get_load_list(hba, load_list)) {
+		count = emlxs_get_load_list(hba, load_list);
+
+		if (!count) {
 			return (FC_FAILURE);
 		}
 
 		/* Scan load list for a boot image */
-		for (i = 0; i < MAX_LOAD_ENTRY; i++) {
+		for (i = 0; i < count; i++) {
 			if (load_list[i].Type == BOOT_BIOS) {
 				/* Update the parms with the boot image id */
 				/* Don't load the EROM this time */
@@ -4732,7 +4887,7 @@
 			}
 		}
 
-		if (i == MAX_LOAD_ENTRY) {
+		if (i == count) {
 			return (EMLXS_NO_BOOT_CODE);
 		}
 	}
--- a/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_fcp.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_fcp.c	Thu Sep 09 11:46:43 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Emulex.  All rights reserved.
+ * Copyright 2010 Emulex.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1353,6 +1353,7 @@
 			if (vport->vpi == 0) {
 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
 				    "%s%s%s", linkspeed, topology, mode);
+
 			} else if (npiv_linkup) {
 				EMLXS_MSGF(EMLXS_CONTEXT,
 				    &emlxs_npiv_link_up_msg, "%s%s%s",
@@ -1372,6 +1373,7 @@
 			if (vport->vpi == 0) {
 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
 				    "%s%s%s *", linkspeed, topology, mode);
+
 			} else if (npiv_linkup) {
 				EMLXS_MSGF(EMLXS_CONTEXT,
 				    &emlxs_npiv_link_up_msg, "%s%s%s *",
--- a/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_sli3.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_sli3.c	Thu Sep 09 11:46:43 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Emulex.  All rights reserved.
+ * Copyright 2010 Emulex.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -196,6 +196,7 @@
 	uint32_t read_rev_reset;
 	uint32_t key = 0;
 	uint32_t fw_check;
+	uint32_t kern_update = 0;
 	uint32_t rval = 0;
 	uint32_t offset;
 	uint8_t vpd_data[DMP_VPD_SIZE];
@@ -215,6 +216,29 @@
 		(void) READ_SBUS_CSR_REG(hba, FC_SHS_REG(hba));
 	}
 
+	/*
+	 * Get a buffer which will be used repeatedly for mailbox commands
+	 */
+	mbq = (MAILBOXQ *) kmem_zalloc((sizeof (MAILBOXQ)), KM_SLEEP);
+
+	mb = (MAILBOX *)mbq;
+
+	hba->mbox_queue_flag = 0;
+	hba->sli.sli3.hc_copy = 0;
+	hba->fc_edtov = FF_DEF_EDTOV;
+	hba->fc_ratov = FF_DEF_RATOV;
+	hba->fc_altov = FF_DEF_ALTOV;
+	hba->fc_arbtov = FF_DEF_ARBTOV;
+
+	/* Set the fw_check flag */
+	fw_check = cfg[CFG_FW_CHECK].current;
+
+	if ((fw_check & 0x04) ||
+	    (hba->fw_flag & FW_UPDATE_KERNEL)) {
+		kern_update = 1;
+	}
+
+reset:
 	/* Initialize sli mode based on configuration parameter */
 	switch (cfg[CFG_SLI_MODE].current) {
 	case 2:	/* SLI2 mode */
@@ -244,24 +268,6 @@
 		sli_mode_mask = EMLXS_SLI2_MASK;
 	}
 
-	/* Set the fw_check flag */
-	fw_check = cfg[CFG_FW_CHECK].current;
-
-	hba->mbox_queue_flag = 0;
-	hba->sli.sli3.hc_copy = 0;
-	hba->fc_edtov = FF_DEF_EDTOV;
-	hba->fc_ratov = FF_DEF_RATOV;
-	hba->fc_altov = FF_DEF_ALTOV;
-	hba->fc_arbtov = FF_DEF_ARBTOV;
-
-	/*
-	 * Get a buffer which will be used repeatedly for mailbox commands
-	 */
-	mbq = (MAILBOXQ *) kmem_zalloc((sizeof (MAILBOXQ)), KM_SLEEP);
-
-	mb = (MAILBOX *)mbq;
-reset:
-
 	/* Reset & Initialize the adapter */
 	if (emlxs_sli3_hba_init(hba)) {
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
@@ -682,8 +688,11 @@
 	 * If firmware checking is enabled and the adapter model indicates
 	 * a firmware image, then perform firmware version check
 	 */
-	if (((fw_check == 1) && (hba->model_info.flags & EMLXS_SUN_BRANDED) &&
-	    hba->model_info.fwid) || ((fw_check == 2) &&
+	hba->fw_flag = 0;
+	hba->fw_timer = 0;
+
+	if (((fw_check & 0x1) && (hba->model_info.flags & EMLXS_SUN_BRANDED) &&
+	    hba->model_info.fwid) || ((fw_check & 0x2) &&
 	    hba->model_info.fwid)) {
 		emlxs_firmware_t *fw;
 
@@ -701,7 +710,14 @@
 		 * versions of adapter
 		 */
 		if (fw) {
-			if ((fw->kern && (vpd->postKernRev != fw->kern)) ||
+			if (!kern_update &&
+			    ((fw->kern && (vpd->postKernRev != fw->kern)) ||
+			    (fw->stub && (vpd->opFwRev != fw->stub)))) {
+
+				hba->fw_flag |= FW_UPDATE_NEEDED;
+
+			} else if ((fw->kern && (vpd->postKernRev !=
+			    fw->kern)) ||
 			    (fw->stub && (vpd->opFwRev != fw->stub)) ||
 			    (fw->sli1 && (vpd->sli1FwRev != fw->sli1)) ||
 			    (fw->sli2 && (vpd->sli2FwRev != fw->sli2)) ||
@@ -728,6 +744,9 @@
 						EMLXS_MSGF(EMLXS_CONTEXT,
 						    &emlxs_init_msg,
 						    "Firmware update failed.");
+
+						hba->fw_flag |=
+						    FW_UPDATE_NEEDED;
 					}
 #ifdef MODFW_SUPPORT
 					/*
@@ -3569,8 +3588,9 @@
 
 		iocb->ULPCOMMAND = CMD_FCP_TSEND64_CX;
 
-		if (dbuf->db_data_size ==
-		    fct_task->task_expected_xfer_length)
+		if ((hba->sli_mode == EMLXS_HBA_SLI3_MODE) &&
+		    (dbuf->db_data_size ==
+		    fct_task->task_expected_xfer_length))
 			iocb->ULPCT = 0x1;
 			/* enable auto-rsp AP feature */
 	}
--- a/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_sli4.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_sli4.c	Thu Sep 09 11:46:43 2010 -0400
@@ -180,6 +180,7 @@
 	uint8_t *outptr;
 	uint32_t status;
 	uint32_t fw_check;
+	uint32_t kern_update = 0;
 	emlxs_firmware_t hba_fw;
 	emlxs_firmware_t *fw;
 
@@ -192,6 +193,11 @@
 	/* Set the fw_check flag */
 	fw_check = cfg[CFG_FW_CHECK].current;
 
+	if ((fw_check & 0x04) ||
+	    (hba->fw_flag & FW_UPDATE_KERNEL)) {
+		kern_update = 1;
+	}
+
 	hba->mbox_queue_flag = 0;
 	hba->fc_edtov = FF_DEF_EDTOV;
 	hba->fc_ratov = FF_DEF_RATOV;
@@ -532,8 +538,11 @@
 	 * If firmware checking is enabled and the adapter model indicates
 	 * a firmware image, then perform firmware version check
 	 */
-	if (((fw_check == 1) && (hba->model_info.flags & EMLXS_SUN_BRANDED) &&
-	    hba->model_info.fwid) || ((fw_check == 2) &&
+	hba->fw_flag = 0;
+	hba->fw_timer = 0;
+
+	if (((fw_check & 0x1) && (hba->model_info.flags & EMLXS_SUN_BRANDED) &&
+	    hba->model_info.fwid) || ((fw_check & 0x2) &&
 	    hba->model_info.fwid)) {
 
 		/* Find firmware image indicated by adapter model */
@@ -563,7 +572,13 @@
 				hba_fw.sli4 = vpd->sli4FwRev;
 			}
 
-			if ((fw->kern && (hba_fw.kern != fw->kern)) ||
+			if (!kern_update &&
+			    ((fw->kern && (hba_fw.kern != fw->kern)) ||
+			    (fw->stub && (hba_fw.stub != fw->stub)))) {
+
+				hba->fw_flag |= FW_UPDATE_NEEDED;
+
+			} else if ((fw->kern && (hba_fw.kern != fw->kern)) ||
 			    (fw->stub && (hba_fw.stub != fw->stub)) ||
 			    (fw->sli1 && (hba_fw.sli1 != fw->sli1)) ||
 			    (fw->sli2 && (hba_fw.sli2 != fw->sli2)) ||
@@ -591,6 +606,9 @@
 						EMLXS_MSGF(EMLXS_CONTEXT,
 						    &emlxs_init_msg,
 						    "Firmware update failed.");
+
+						hba->fw_flag |=
+						    FW_UPDATE_NEEDED;
 					}
 #ifdef MODFW_SUPPORT
 					/*
@@ -6689,6 +6707,7 @@
 emlxs_sli4_check_fcf_config(emlxs_hba_t *hba, FCF_RECORD_t *fcfrec)
 {
 	int i;
+	uint32_t rval = 1;
 
 	if (!(hba->flag & FC_FIP_SUPPORTED)) {
 		if (!hba->sli.sli4.cfgFCOE.length) {
@@ -6718,12 +6737,15 @@
 	/* Just check FabricName for now */
 	for (i = 0; i < MAX_FCFCONNECTLIST_ENTRIES; i++) {
 		if ((hba->sli.sli4.cfgFCF.entry[i].FabricNameValid) &&
-		    (bcmp((char *)fcfrec->fabric_name_identifier,
-		    hba->sli.sli4.cfgFCF.entry[i].FabricName, 8) == 0)) {
-			return (1);  /* success */
-		}
-	}
-	return (0);
+		    (hba->sli.sli4.cfgFCF.entry[i].Valid)) {
+			rval = 0;
+			if (bcmp((char *)fcfrec->fabric_name_identifier,
+			    hba->sli.sli4.cfgFCF.entry[i].FabricName, 8) == 0) {
+				return (1);  /* success */
+			}
+		}
+	}
+	return (rval);
 }
 
 
--- a/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_solaris.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_solaris.c	Thu Sep 09 11:46:43 2010 -0400
@@ -46,6 +46,7 @@
 static void	emlxs_fca_attach(emlxs_hba_t *hba);
 static void	emlxs_fca_detach(emlxs_hba_t *hba);
 static void	emlxs_drv_banner(emlxs_hba_t *hba);
+static int32_t	emlxs_fca_reset(opaque_t fca_port_handle, uint32_t cmd);
 
 static int32_t	emlxs_get_props(emlxs_hba_t *hba);
 static int32_t	emlxs_send_fcp_cmd(emlxs_port_t *port, emlxs_buf_t *sbp);
@@ -268,7 +269,7 @@
 	emlxs_ub_free,
 	emlxs_ub_release,
 	emlxs_pkt_abort,
-	emlxs_reset,
+	emlxs_fca_reset,
 	emlxs_port_manage,
 	emlxs_get_device,
 	emlxs_notify
@@ -306,7 +307,7 @@
 	emlxs_ub_free,
 	emlxs_ub_release,
 	emlxs_pkt_abort,
-	emlxs_reset,
+	emlxs_fca_reset,
 	emlxs_port_manage,
 	emlxs_get_device,
 	emlxs_notify
@@ -344,7 +345,7 @@
 	emlxs_ub_free,
 	emlxs_ub_release,
 	emlxs_pkt_abort,
-	emlxs_reset,
+	emlxs_fca_reset,
 	emlxs_port_manage,
 	emlxs_get_device,
 	emlxs_notify
@@ -375,7 +376,7 @@
 	emlxs_ub_free,
 	emlxs_ub_release,
 	emlxs_pkt_abort,
-	emlxs_reset,
+	emlxs_fca_reset,
 	emlxs_port_manage,
 	emlxs_get_device,
 	emlxs_notify
@@ -3851,21 +3852,13 @@
 
 
 extern int32_t
-emlxs_reset(opaque_t fca_port_handle, uint32_t cmd)
-{
-	emlxs_port_t	*port = (emlxs_port_t *)fca_port_handle;
+emlxs_reset(emlxs_port_t *port, uint32_t cmd)
+{
 	emlxs_hba_t	*hba = HBA;
 	int		rval;
 	int		ret;
 	clock_t		timeout;
 
-	if (!(port->flag & EMLXS_PORT_BOUND)) {
-		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
-		    "fca_reset failed. Port not bound.");
-
-		return (FC_UNBOUND);
-	}
-
 	switch (cmd) {
 	case FC_FCA_LINK_RESET:
 
@@ -3875,7 +3868,7 @@
 		}
 
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
-		    "fca_reset: Resetting Link.");
+		    "Resetting Link.");
 
 		mutex_enter(&EMLXS_LINKUP_LOCK);
 		hba->linkup_wait_flag = TRUE;
@@ -3910,7 +3903,7 @@
 	case FC_FCA_CORE:
 #ifdef DUMP_SUPPORT
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
-		    "fca_reset: Core dump.");
+		    "Dumping Core.");
 
 		/* Schedule a USER dump */
 		emlxs_dump(hba, EMLXS_USER_DUMP, 0, 0);
@@ -3925,7 +3918,7 @@
 	case FC_FCA_RESET_CORE:
 
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
-		    "fca_reset: Resetting Adapter.");
+		    "Resetting Adapter.");
 
 		rval = FC_SUCCESS;
 
@@ -3933,7 +3926,7 @@
 			(void) emlxs_online(hba);
 		} else {
 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
-			    "fca_reset: Adapter reset failed. Device busy.");
+			    "Adapter reset failed. Device busy.");
 
 			rval = FC_DEVICE_BUSY;
 		}
@@ -3942,7 +3935,7 @@
 
 	default:
 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
-		    "fca_reset: Unknown command. cmd=%x", cmd);
+		    "emlxs_reset: Unknown command. cmd=%x", cmd);
 
 		break;
 	}
@@ -3952,6 +3945,64 @@
 } /* emlxs_reset() */
 
 
+static int32_t
+emlxs_fca_reset(opaque_t fca_port_handle, uint32_t cmd)
+{
+	emlxs_port_t	*port = (emlxs_port_t *)fca_port_handle;
+	emlxs_hba_t	*hba = HBA;
+	int32_t		rval;
+
+	if (!(port->flag & EMLXS_PORT_BOUND)) {
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+		    "fca_reset: Port not bound.");
+
+		return (FC_UNBOUND);
+	}
+
+	switch (cmd) {
+	case FC_FCA_LINK_RESET:
+		if (hba->fw_flag & FW_UPDATE_NEEDED) {
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+			    "fca_reset: FC_FCA_LINK_RESET -> FC_FCA_RESET");
+			cmd = FC_FCA_RESET;
+		} else {
+			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+			    "fca_reset: FC_FCA_LINK_RESET");
+		}
+		break;
+
+	case FC_FCA_CORE:
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+		    "fca_reset: FC_FCA_CORE");
+		break;
+
+	case FC_FCA_RESET:
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+		    "fca_reset: FC_FCA_RESET");
+		break;
+
+	case FC_FCA_RESET_CORE:
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+		    "fca_reset: FC_FCA_RESET_CORE");
+		break;
+
+	default:
+		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
+		    "fca_reset: Unknown command. cmd=%x", cmd);
+		return (FC_FAILURE);
+	}
+
+	if (hba->fw_flag & FW_UPDATE_NEEDED) {
+		hba->fw_flag |= FW_UPDATE_KERNEL;
+	}
+
+	rval = emlxs_reset(port, cmd);
+
+	return (rval);
+
+} /* emlxs_fca_reset() */
+
+
 extern int
 emlxs_port_manage(opaque_t fca_port_handle, fc_fca_pm_t *pm)
 {
@@ -6862,6 +6913,18 @@
 		}
 		break;
 
+	case CFG_FW_CHECK:
+		/* The 0x2 bit implies the 0x1 bit will also be set */
+		if (new_value & 0x2) {
+			new_value |= 0x1;
+		}
+
+		/* The 0x4 bit should not be set if 0x1 or 0x2 is not set */
+		if (!(new_value & 0x3) && (new_value & 0x4)) {
+			new_value &= ~0x4;
+		}
+		break;
+
 	case CFG_LINK_SPEED:
 		if (vpd->link_speed) {
 			switch (new_value) {
--- a/usr/src/uts/common/io/fibre-channel/fca/qlge/qlge.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/qlge/qlge.c	Thu Sep 09 11:46:43 2010 -0400
@@ -58,7 +58,6 @@
     size_t, size_t, caddr_t *, ddi_dma_cookie_t *);
 static void ql_free_phys(ddi_dma_handle_t *, ddi_acc_handle_t *);
 static int ql_set_routing_reg(qlge_t *, uint32_t, uint32_t, int);
-static int ql_route_initialize(qlge_t *);
 static int ql_attach(dev_info_t *, ddi_attach_cmd_t);
 static int ql_detach(dev_info_t *, ddi_detach_cmd_t);
 static int ql_bringdown_adapter(qlge_t *);
@@ -1446,13 +1445,18 @@
 	int i;
 	ddi_dma_cookie_t dma_cookie;
 
+	rx_ring->sbq_use_head = 0;
+	rx_ring->sbq_use_tail = 0;
+	rx_ring->sbuf_in_use_count = 0;
+	rx_ring->sbq_free_head = 0;
+	rx_ring->sbq_free_tail = 0;
+	rx_ring->sbuf_free_count = 0;
 	rx_ring->sbuf_free = kmem_zalloc(rx_ring->sbq_len *
 	    sizeof (struct bq_desc *), KM_NOSLEEP);
 	if (rx_ring->sbuf_free == NULL) {
 		cmn_err(CE_WARN,
 		    "!%s: sbuf_free_list alloc: failed",
 		    __func__);
-		rx_ring->sbuf_free_count = 0;
 		goto alloc_sbuf_err;
 	}
 
@@ -1462,13 +1466,9 @@
 		cmn_err(CE_WARN,
 		    "!%s: sbuf_inuse_list alloc: failed",
 		    __func__);
-		rx_ring->sbuf_in_use_count = 0;
 		goto alloc_sbuf_err;
 	}
-	rx_ring->sbq_use_head = 0;
-	rx_ring->sbq_use_tail = 0;
-	rx_ring->sbq_free_head = 0;
-	rx_ring->sbq_free_tail = 0;
+
 	sbq_desc = &rx_ring->sbq_desc[0];
 
 	for (i = 0; i < rx_ring->sbq_len; i++, sbq_desc++) {
@@ -1591,13 +1591,18 @@
 	int i;
 	uint32_t lbq_buf_size;
 
+	rx_ring->lbq_use_head = 0;
+	rx_ring->lbq_use_tail = 0;
+	rx_ring->lbuf_in_use_count = 0;
+	rx_ring->lbq_free_head = 0;
+	rx_ring->lbq_free_tail = 0;
+	rx_ring->lbuf_free_count = 0;
 	rx_ring->lbuf_free = kmem_zalloc(rx_ring->lbq_len *
 	    sizeof (struct bq_desc *), KM_NOSLEEP);
 	if (rx_ring->lbuf_free == NULL) {
 		cmn_err(CE_WARN,
 		    "!%s: lbuf_free_list alloc: failed",
 		    __func__);
-		rx_ring->lbuf_free_count = 0;
 		goto alloc_lbuf_err;
 	}
 
@@ -1608,13 +1613,8 @@
 		cmn_err(CE_WARN,
 		    "!%s: lbuf_inuse_list alloc: failed",
 		    __func__);
-		rx_ring->lbuf_in_use_count = 0;
 		goto alloc_lbuf_err;
 	}
-	rx_ring->lbq_use_head = 0;
-	rx_ring->lbq_use_tail = 0;
-	rx_ring->lbq_free_head = 0;
-	rx_ring->lbq_free_tail = 0;
 
 	lbq_buf_size = (qlge->mtu == ETHERMTU) ?
 	    LRG_BUF_NORMAL_SIZE : LRG_BUF_JUMBO_SIZE;
@@ -1710,7 +1710,7 @@
 	return (DDI_SUCCESS);
 
 alloc_err:
-
+	ql_free_rx_buffers(qlge);
 	return (DDI_FAILURE);
 }
 
@@ -3189,11 +3189,13 @@
 static void
 ql_free_phys(ddi_dma_handle_t *dma_handle, ddi_acc_handle_t *acc_handle)
 {
-	if (dma_handle != NULL) {
+	if (*dma_handle != NULL) {
 		(void) ddi_dma_unbind_handle(*dma_handle);
-		if (acc_handle != NULL)
+		if (*acc_handle != NULL)
 			ddi_dma_mem_free(acc_handle);
 		ddi_dma_free_handle(dma_handle);
+		*acc_handle = NULL;
+		*dma_handle = NULL;
 	}
 }
 
@@ -3319,9 +3321,11 @@
 	struct tx_ring_desc *tx_ring_desc;
 	int i, j;
 
-	ql_free_phys(&tx_ring->wq_dma.dma_handle, &tx_ring->wq_dma.acc_handle);
-	bzero(&tx_ring->wq_dma, sizeof (tx_ring->wq_dma));
-
+	if (tx_ring->wq_dma.dma_handle != NULL) {
+		ql_free_phys(&tx_ring->wq_dma.dma_handle,
+		    &tx_ring->wq_dma.acc_handle);
+		bzero(&tx_ring->wq_dma, sizeof (tx_ring->wq_dma));
+	}
 	if (tx_ring->wq_desc != NULL) {
 		tx_ring_desc = tx_ring->wq_desc;
 		for (i = 0; i < tx_ring->wq_len; i++, tx_ring_desc++) {
@@ -3417,7 +3421,7 @@
 				cmn_err(CE_WARN, "%s(%d): reqQ tx buf &"
 				    "oal alloc failed.",
 				    __func__, qlge->instance);
-				return (DDI_FAILURE);
+				goto err;
 			}
 
 			tx_ring_desc->oal = tx_ring_desc->oal_dma.vaddr;
@@ -3436,10 +3440,14 @@
 				    DDI_DMA_DONTWAIT,
 				    0, &tx_ring_desc->tx_dma_handle[j])
 				    != DDI_SUCCESS) {
+					tx_ring_desc->tx_dma_handle[j] = NULL;
 					cmn_err(CE_WARN,
 					    "!%s: ddi_dma_alloc_handle: "
 					    "tx_dma_handle "
 					    "alloc failed", __func__);
+					ql_free_phys(
+					    &tx_ring_desc->oal_dma.dma_handle,
+					    &tx_ring_desc->oal_dma.acc_handle);
 					goto err;
 				}
 			}
@@ -3457,7 +3465,7 @@
 		bzero(&tx_ring->wqicb_dma, sizeof (tx_ring->wqicb_dma));
 		cmn_err(CE_WARN, "%s(%d): wqicb allocation failed.",
 		    __func__, qlge->instance);
-		return (DDI_FAILURE);
+		goto err;
 	}
 	tx_ring->wqicb_dma.dma_addr = dma_cookie.dmac_laddress;
 
@@ -3482,9 +3490,11 @@
 	}
 
 	/* Free the small buffer queue control blocks. */
-	kmem_free(rx_ring->sbq_desc, rx_ring->sbq_len *
-	    sizeof (struct bq_desc));
-	rx_ring->sbq_desc = NULL;
+	if (rx_ring->sbq_desc != NULL) {
+		kmem_free(rx_ring->sbq_desc, rx_ring->sbq_len *
+		    sizeof (struct bq_desc));
+		rx_ring->sbq_desc = NULL;
+	}
 
 	/* Free the large buffer queue. */
 	if (rx_ring->lbq_dma.dma_handle) {
@@ -3494,9 +3504,11 @@
 	}
 
 	/* Free the large buffer queue control blocks. */
-	kmem_free(rx_ring->lbq_desc, rx_ring->lbq_len *
-	    sizeof (struct bq_desc));
-	rx_ring->lbq_desc = NULL;
+	if (rx_ring->lbq_desc != NULL) {
+		kmem_free(rx_ring->lbq_desc, rx_ring->lbq_len *
+		    sizeof (struct bq_desc));
+		rx_ring->lbq_desc = NULL;
+	}
 
 	/* Free cqicb struct */
 	if (rx_ring->cqicb_dma.dma_handle) {
@@ -3616,7 +3628,7 @@
 		bzero(&rx_ring->cqicb_dma, sizeof (rx_ring->cqicb_dma));
 		cmn_err(CE_WARN, "%s(%d): cqicb allocation failed.",
 		    __func__, qlge->instance);
-		return (DDI_FAILURE);
+		goto err_mem;
 	}
 	rx_ring->cqicb_dma.dma_addr = dma_cookie.dmac_laddress;
 
@@ -3709,13 +3721,14 @@
 		bzero(&qlge->ricb_dma, sizeof (qlge->ricb_dma));
 		cmn_err(CE_WARN, "%s(%d): ricb allocation failed.",
 		    __func__, qlge->instance);
-		return (DDI_FAILURE);
+		goto err_mem;
 	}
 	qlge->ricb_dma.dma_addr = dma_cookie.dmac_laddress;
 
 	return (DDI_SUCCESS);
 
 err_mem:
+	ql_free_mem_resources(qlge);
 	return (DDI_FAILURE);
 }
 
@@ -3758,6 +3771,7 @@
 	    dma_handle) != DDI_SUCCESS) {
 		cmn_err(CE_WARN, QL_BANG "%s:  ddi_dma_alloc_handle FAILED",
 		    __func__);
+		*dma_handle = NULL;
 		return (QL_ERROR);
 	}
 	/*
@@ -3769,6 +3783,8 @@
 	    NULL, vaddr, &rlen, acc_handle) != DDI_SUCCESS) {
 		cmn_err(CE_WARN, "alloc_phys: DMA Memory alloc Failed");
 		ddi_dma_free_handle(dma_handle);
+		*acc_handle = NULL;
+		*dma_handle = NULL;
 		return (QL_ERROR);
 	}
 
@@ -3780,6 +3796,8 @@
 		ddi_dma_free_handle(dma_handle);
 		cmn_err(CE_WARN, "%s ddi_dma_addr_bind_handle FAILED",
 		    __func__);
+		*acc_handle = NULL;
+		*dma_handle = NULL;
 		return (QL_ERROR);
 	}
 
@@ -3834,6 +3852,7 @@
 	    dma_handle) != DDI_SUCCESS) {
 		cmn_err(CE_WARN, QL_BANG "%s:  ddi_dma_alloc_handle FAILED",
 		    __func__);
+		*dma_handle = NULL;
 		return (QL_ERROR);
 	}
 	/*
@@ -3845,6 +3864,8 @@
 	    NULL, vaddr, &rlen, acc_handle) != DDI_SUCCESS) {
 		cmn_err(CE_WARN, "alloc_phys: DMA Memory alloc Failed");
 		ddi_dma_free_handle(dma_handle);
+		*acc_handle = NULL;
+		*dma_handle = NULL;
 		return (QL_ERROR);
 	}
 
@@ -3852,10 +3873,11 @@
 	    dma_flags, DDI_DMA_DONTWAIT, NULL,
 	    dma_cookie, &cnt) != DDI_DMA_MAPPED) {
 		ddi_dma_mem_free(acc_handle);
-
 		ddi_dma_free_handle(dma_handle);
 		cmn_err(CE_WARN, "%s ddi_dma_addr_bind_handle FAILED",
 		    __func__);
+		*acc_handle = NULL;
+		*dma_handle = NULL;
 		return (QL_ERROR);
 	}
 
@@ -4462,7 +4484,7 @@
 		qlge->sequence &= ~INIT_PCI_CONFIG_SETUP;
 	}
 
-	if (qlge->sequence & INIT_ADD_INTERRUPT) {
+	if (qlge->sequence & INIT_INTR_ALLOC) {
 		ql_free_irq_vectors(qlge);
 		qlge->sequence &= ~INIT_ADD_INTERRUPT;
 	}
@@ -6862,7 +6884,7 @@
 }
 
 /* Initialize the frame-to-queue routing. */
-static int
+int
 ql_route_initialize(qlge_t *qlge)
 {
 	int status = 0;
--- a/usr/src/uts/common/io/fibre-channel/fca/qlge/qlge_dbg.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/qlge/qlge_dbg.c	Thu Sep 09 11:46:43 2010 -0400
@@ -1478,6 +1478,7 @@
 	{ normal,	"normal",	QLGE_LOOP_NONE			},
 	{ internal,	"parallel",	QLGE_LOOP_INTERNAL_PARALLEL	},
 	{ internal,	"serial",	QLGE_LOOP_INTERNAL_SERIAL	},
+	{ external,	"phy",		QLGE_LOOP_EXTERNAL_PHY		}
 };
 
 /*
@@ -1502,6 +1503,7 @@
 	case QLGE_LOOP_NONE:
 	case QLGE_LOOP_INTERNAL_PARALLEL:
 	case QLGE_LOOP_INTERNAL_SERIAL:
+	case QLGE_LOOP_EXTERNAL_PHY:
 		break;
 	}
 
@@ -1512,6 +1514,13 @@
 	mutex_enter(&qlge->mbx_mutex);
 	(void) ql_set_loop_back_mode(qlge);
 	mutex_exit(&qlge->mbx_mutex);
+	/* if loopback mode test is done */
+	if (mode == QLGE_LOOP_NONE) {
+		mutex_enter(&qlge->hw_mutex);
+		(void) ql_route_initialize(qlge);
+		mutex_exit(&qlge->hw_mutex);
+	}
+
 	return (IOC_REPLY);
 }
 /*
--- a/usr/src/uts/common/io/fibre-channel/fca/qlge/qlge_mpi.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/io/fibre-channel/fca/qlge/qlge_mpi.c	Thu Sep 09 11:46:43 2010 -0400
@@ -981,6 +981,8 @@
 		qlge->port_cfg_info.link_cfg |= LOOP_INTERNAL_PARALLEL;
 	else if (qlge->loop_back_mode == QLGE_LOOP_INTERNAL_SERIAL)
 		qlge->port_cfg_info.link_cfg |= LOOP_INTERNAL_SERIAL;
+	else if (qlge->loop_back_mode == QLGE_LOOP_EXTERNAL_PHY)
+		qlge->port_cfg_info.link_cfg |= LOOP_EXTERNAL_PHY;
 
 	return (ql_set_mpi_port_config(qlge, qlge->port_cfg_info));
 
--- a/usr/src/uts/common/os/dumpsubr.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/os/dumpsubr.c	Thu Sep 09 11:46:43 2010 -0400
@@ -412,7 +412,6 @@
 	char	*maxvm;		/* reserved VM for spare pages */
 	lock_t	helper_lock;	/* protect helper state */
 	char	helpers_wanted;	/* flag to enable parallelism */
-	char	helper_present;	/* at least one helper showed up */
 } dumpcfg_t;
 
 static dumpcfg_t dumpcfg;	/* config vars */
@@ -883,15 +882,10 @@
 	int k;
 
 	/*
-	 * Fall back to doing a serial dump if no helpers showed
-	 * up. It is possible for other CPUs to be stuck in PROM, or
-	 * DRd out. panic("sync initiated") in sync_handler() is one
-	 * case. A parallel dump will hang (dump time out) unless
-	 * there is at least one helper CPU. At this point dumpsys()
-	 * has done some I/O, which means there has been plenty of
-	 * time for helpers to arrive.
+	 * Setting dump_plat_mincpu to 0 at any time forces a serial
+	 * dump.
 	 */
-	if (!cfg->helper_present) {
+	if (dump_plat_mincpu == 0) {
 		cfg->clevel = 0;
 		return;
 	}
@@ -2189,8 +2183,6 @@
 void
 dumpsys_helper()
 {
-	if (!dumpcfg.helper_present)
-		dumpcfg.helper_present = 1;
 	dumpsys_spinlock(&dumpcfg.helper_lock);
 	if (dumpcfg.helpers_wanted) {
 		helper_t *hp, *hpend = &dumpcfg.helper[dumpcfg.nhelper];
@@ -2229,8 +2221,6 @@
 void
 dumpsys_helper_nw()
 {
-	if (!dumpcfg.helper_present)
-		dumpcfg.helper_present = 1;
 	if (dumpcfg.helpers_wanted)
 		dumpsys_helper();
 }
@@ -2295,7 +2285,29 @@
 	cbuf_t *cp;
 	pgcnt_t baseoff, pfnoff;
 	pfn_t base, pfn;
-	int sec;
+	int sec, i, dumpserial;
+
+	/*
+	 * Fall back to serial mode if there are no helpers.
+	 * dump_plat_mincpu can be set to 0 at any time.
+	 * dumpcfg.helpermap must contain at least one member.
+	 */
+	dumpserial = 1;
+
+	if (dump_plat_mincpu != 0 && dumpcfg.clevel != 0) {
+		for (i = 0; i < BT_BITOUL(NCPU); ++i) {
+			if (dumpcfg.helpermap[i] != 0) {
+				dumpserial = 0;
+				break;
+			}
+		}
+	}
+
+	if (dumpserial) {
+		dumpcfg.clevel = 0;
+		if (dumpcfg.helper[0].lzbuf == NULL)
+			dumpcfg.helper[0].lzbuf = dumpcfg.helper[1].page;
+	}
 
 	dump_init_memlist_walker(&mlw);
 
@@ -2430,7 +2442,7 @@
 			 * If there are no helpers the main task does
 			 * non-streams lzjb compress.
 			 */
-			if (dumpcfg.clevel == 0) {
+			if (dumpserial) {
 				dumpsys_lzjb_page(dumpcfg.helper, cp);
 				break;
 			}
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h	Thu Sep 09 11:46:43 2010 -0400
@@ -39,21 +39,17 @@
 
 #define	SMB_IOC_CONFIG		_IOW(SMB_IOC_BASE, 1, int)
 #define	SMB_IOC_START		_IOW(SMB_IOC_BASE, 2, int)
-#define	SMB_IOC_NBT_LISTEN	_IOW(SMB_IOC_BASE, 3, int)
-#define	SMB_IOC_TCP_LISTEN	_IOW(SMB_IOC_BASE, 4, int)
-#define	SMB_IOC_NBT_RECEIVE	_IOW(SMB_IOC_BASE, 5, int)
-#define	SMB_IOC_TCP_RECEIVE	_IOW(SMB_IOC_BASE, 6, int)
-#define	SMB_IOC_GMTOFF		_IOW(SMB_IOC_BASE, 7, int)
-#define	SMB_IOC_SHARE		_IOW(SMB_IOC_BASE, 8, int)
-#define	SMB_IOC_UNSHARE		_IOW(SMB_IOC_BASE, 9, int)
-#define	SMB_IOC_NUMOPEN		_IOW(SMB_IOC_BASE, 10, int)
-#define	SMB_IOC_SVCENUM		_IOW(SMB_IOC_BASE, 11, int)
-#define	SMB_IOC_FILE_CLOSE	_IOW(SMB_IOC_BASE, 12, int)
-#define	SMB_IOC_SESSION_CLOSE	_IOW(SMB_IOC_BASE, 13, int)
-#define	SMB_IOC_STOP		_IOW(SMB_IOC_BASE, 14, int)
-#define	SMB_IOC_EVENT		_IOW(SMB_IOC_BASE, 15, int)
-#define	SMB_IOC_SHAREINFO	_IOW(SMB_IOC_BASE, 16, int)
-#define	SMB_IOC_SPOOLDOC	_IOW(SMB_IOC_BASE, 17, int)
+#define	SMB_IOC_GMTOFF		_IOW(SMB_IOC_BASE, 3, int)
+#define	SMB_IOC_SHARE		_IOW(SMB_IOC_BASE, 4, int)
+#define	SMB_IOC_UNSHARE		_IOW(SMB_IOC_BASE, 5, int)
+#define	SMB_IOC_NUMOPEN		_IOW(SMB_IOC_BASE, 6, int)
+#define	SMB_IOC_SVCENUM		_IOW(SMB_IOC_BASE, 7, int)
+#define	SMB_IOC_FILE_CLOSE	_IOW(SMB_IOC_BASE, 8, int)
+#define	SMB_IOC_SESSION_CLOSE	_IOW(SMB_IOC_BASE, 9, int)
+#define	SMB_IOC_STOP		_IOW(SMB_IOC_BASE, 10, int)
+#define	SMB_IOC_EVENT		_IOW(SMB_IOC_BASE, 11, int)
+#define	SMB_IOC_SHAREINFO	_IOW(SMB_IOC_BASE, 12, int)
+#define	SMB_IOC_SPOOLDOC	_IOW(SMB_IOC_BASE, 13, int)
 
 typedef struct smb_ioc_header {
 	uint32_t	version;
@@ -87,11 +83,6 @@
 	uint32_t	shortnames;
 } smb_ioc_shareinfo_t;
 
-typedef	struct smb_ioc_listen {
-	smb_ioc_header_t hdr;
-	int		error;
-} smb_ioc_listen_t;
-
 typedef	struct smb_ioc_start {
 	smb_ioc_header_t hdr;
 	int		opipe;
@@ -181,7 +172,6 @@
 	smb_ioc_cfg_t		ioc_cfg;
 	smb_ioc_start_t		ioc_start;
 	smb_ioc_event_t		ioc_event;
-	smb_ioc_listen_t	ioc_listen;
 	smb_ioc_opennum_t	ioc_opennum;
 	smb_ioc_svcenum_t	ioc_svcenum;
 	smb_ioc_session_t	ioc_session;
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Thu Sep 09 11:46:43 2010 -0400
@@ -367,10 +367,6 @@
 boolean_t smb_server_is_stopping(void);
 int smb_server_cancel_event(uint32_t);
 int smb_server_notify_event(smb_ioc_event_t *);
-int smb_server_nbt_listen(smb_ioc_listen_t *);
-int smb_server_tcp_listen(smb_ioc_listen_t *);
-int smb_server_nbt_receive(void);
-int smb_server_tcp_receive(void);
 uint32_t smb_server_get_session_count(void);
 int smb_server_set_gmtoff(smb_ioc_gmt_t *);
 int smb_server_numopen(smb_ioc_opennum_t *);
@@ -514,28 +510,22 @@
  * session functions (file smb_session.c)
  */
 smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *, int);
-int smb_session_daemon(smb_session_list_t *);
-void smb_session_reconnection_check(smb_session_list_t *, smb_session_t *);
-void smb_session_timers(smb_session_list_t *);
+void smb_session_receiver(smb_session_t *);
+void smb_session_disconnect(smb_session_t *);
+void smb_session_reconnection_check(smb_llist_t *, smb_session_t *);
+void smb_session_timers(smb_llist_t *);
 void smb_session_delete(smb_session_t *session);
 void smb_session_cancel_requests(smb_session_t *, smb_tree_t *,
     smb_request_t *);
 void smb_session_config(smb_session_t *session);
-void smb_session_disconnect_from_share(smb_session_list_t *, char *);
-void smb_session_list_constructor(smb_session_list_t *);
-void smb_session_list_destructor(smb_session_list_t *);
-void smb_session_list_append(smb_session_list_t *, smb_session_t *);
-void smb_session_list_delete_tail(smb_session_list_t *);
-smb_session_t *smb_session_list_activate_head(smb_session_list_t *);
-void smb_session_list_terminate(smb_session_list_t *, smb_session_t *);
-void smb_session_list_signal(smb_session_list_t *);
+void smb_session_disconnect_from_share(smb_llist_t *, char *);
 smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *);
 smb_user_t *smb_session_lookup_uid(smb_session_t *, uint16_t);
 void smb_session_post_user(smb_session_t *, smb_user_t *);
 void smb_session_disconnect_share(smb_session_t *, const char *);
 void smb_session_getclient(smb_session_t *, char *, size_t);
 boolean_t smb_session_isclient(smb_session_t *, const char *);
-void smb_session_correct_keep_alive_values(smb_session_list_t *, uint32_t);
+void smb_session_correct_keep_alive_values(smb_llist_t *, uint32_t);
 void smb_session_oplock_break(smb_session_t *, uint16_t, uint16_t, uint8_t);
 int smb_session_send(smb_session_t *, uint8_t type, mbuf_chain_t *);
 int smb_session_xprt_gethdr(smb_session_t *, smb_xprt_t *);
@@ -745,8 +735,7 @@
 krw_t   smb_rwx_rwupgrade(smb_rwx_t *rwx);
 void    smb_rwx_rwdowngrade(smb_rwx_t *rwx, krw_t mode);
 
-void	smb_thread_init(smb_thread_t *, char *, smb_thread_ep_t, void *,
-    smb_thread_aw_t, void *);
+void	smb_thread_init(smb_thread_t *, char *, smb_thread_ep_t, void *);
 void	smb_thread_destroy(smb_thread_t *);
 int	smb_thread_start(smb_thread_t *);
 void	smb_thread_stop(smb_thread_t *);
@@ -754,7 +743,6 @@
 boolean_t smb_thread_continue(smb_thread_t *);
 boolean_t smb_thread_continue_nowait(smb_thread_t *);
 boolean_t smb_thread_continue_timedwait(smb_thread_t *, int /* seconds */);
-void smb_thread_set_awaken(smb_thread_t *, smb_thread_aw_t, void *);
 
 uint32_t smb_denymode_to_sharemode(uint32_t desired_access, char *fname);
 uint32_t smb_ofun_to_crdisposition(uint16_t ofun);
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Thu Sep 09 11:46:43 2010 -0400
@@ -238,13 +238,6 @@
  * Transition T5
  *
  *    This transition is executed in smb_thread_destroy().
- *
- * Comments
- * --------
- *
- *    The field smb_thread_aw_t contains a function pointer that knows how to
- *    awake the thread. It is a temporary solution to work around the fact that
- *    kernel threads (not part of a userspace process) cannot be signaled.
  */
 typedef enum smb_thread_state {
 	SMB_THREAD_STATE_STARTING = 0,
@@ -256,7 +249,6 @@
 struct _smb_thread;
 
 typedef void (*smb_thread_ep_t)(struct _smb_thread *, void *ep_arg);
-typedef void (*smb_thread_aw_t)(struct _smb_thread *, void *aw_arg);
 
 #define	SMB_THREAD_MAGIC	0x534D4254	/* SMBT */
 
@@ -268,8 +260,6 @@
 	kt_did_t		sth_did;
 	smb_thread_ep_t		sth_ep;
 	void			*sth_ep_arg;
-	smb_thread_aw_t		sth_aw;
-	void			*sth_aw_arg;
 	boolean_t		sth_kill;
 	kmutex_t		sth_mtx;
 	kcondvar_t		sth_cv;
@@ -453,19 +443,6 @@
 	smb_avl_nops_t	*avl_nops;
 } smb_avl_t;
 
-typedef struct smb_session_list {
-	krwlock_t	se_lock;
-	uint64_t	se_wrop;
-	struct {
-		list_t		lst;
-		uint32_t	count;
-	} se_rdy;
-	struct {
-		list_t		lst;
-		uint32_t	count;
-	} se_act;
-} smb_session_list_t;
-
 typedef struct {
 	kcondvar_t	rwx_cv;
 	kmutex_t	rwx_mutex;
@@ -1806,13 +1783,20 @@
 #define	SMB_SERVER_VALID(s)	\
     ASSERT(((s) != NULL) && ((s)->sv_magic == SMB_SERVER_MAGIC))
 
+#define	SMB_LISTENER_MAGIC	0x4C53544E	/* 'LSTN' */
+#define	SMB_LISTENER_VALID(ld)	\
+    ASSERT(((ld) != NULL) && ((ld)->ld_magic == SMB_LISTENER_MAGIC))
+
 typedef struct {
-	kthread_t		*ld_kth;
-	kt_did_t		ld_ktdid;
+	uint32_t		ld_magic;
+	struct smb_server	*ld_sv;
+	smb_thread_t		ld_thread;
 	ksocket_t		ld_so;
+	in_port_t		ld_port;
+	int			ld_family;
 	struct sockaddr_in	ld_sin;
 	struct sockaddr_in6	ld_sin6;
-	smb_session_list_t	ld_session_list;
+	smb_llist_t		ld_session_list;
 } smb_listener_daemon_t;
 
 #define	SMB_SSETUP_CMD			"authentication"
@@ -1881,7 +1865,8 @@
 
 	smb_thread_t		si_thread_timers;
 
-	taskq_t			*sv_thread_pool;
+	taskq_t			*sv_worker_pool;
+	taskq_t			*sv_receiver_pool;
 
 	kmem_cache_t		*si_cache_request;
 	kmem_cache_t		*si_cache_session;
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_config.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_config.h	Thu Sep 09 11:46:43 2010 -0400
@@ -283,10 +283,10 @@
 
 	/* CFG_FW_CHECK */
 	{"fw-check",
-		0, 2, 1, 0,
-		PARM_DYNAMIC_RESET | PARM_BOOLEAN | PARM_HIDDEN,
-	"Enables firmware revision checking of adapters. "
-		"[0=Off 1=Sun-only 2=All]"},
+		0, 7, 1, 0,
+		PARM_DYNAMIC_RESET | PARM_HEX | PARM_HIDDEN,
+	"Enables firmware revision checking. "
+		"[0=Off 1=Sun-only 2=All 4=kern-update]"},
 
 	/* CFG_TRI_REQUIRED */
 	{"tri-required",
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_extern.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_extern.h	Thu Sep 09 11:46:43 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Emulex.  All rights reserved.
+ * Copyright 2010 Emulex.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -170,8 +170,7 @@
 
 extern uint32_t			emlxs_get_instance(int32_t ddiinst);
 extern char			*emlxs_mscmd_xlate(uint16_t cmd);
-extern int32_t			emlxs_reset(opaque_t fca_port_handle,
-					uint32_t cmd);
+extern int32_t			emlxs_reset(emlxs_port_t *port, uint32_t cmd);
 extern void			emlxs_swap_service_params(SERV_PARM *sp);
 extern void			emlxs_swap_fcp_pkt(emlxs_buf_t *sbp);
 extern void			emlxs_swap_ct_pkt(emlxs_buf_t *sbp);
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_fc.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_fc.h	Thu Sep 09 11:46:43 2010 -0400
@@ -1813,6 +1813,11 @@
 #define	FC_LINKDOWN_MASK	0xFFF30C1F	/* Bits to protect during */
 						/* a linkdown */
 
+	uint32_t fw_timer;
+	uint32_t fw_flag;
+#define	FW_UPDATE_NEEDED	0x00000001
+#define	FW_UPDATE_KERNEL	0x00000002
+
 	uint32_t temperature;			/* Last reported temperature */
 
 	/* SBUS adapter management */
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_hw.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_hw.h	Thu Sep 09 11:46:43 2010 -0400
@@ -2261,6 +2261,7 @@
 	uint32_t	image_size;
 	uint32_t	block_size;
 	uint32_t	block_crc;
+	uint32_t	load_address;
 	char		label[BE_VERSION_SIZE];
 } emlxs_be_fw_file_t;
 
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_mbox.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_mbox.h	Thu Sep 09 11:46:43 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Emulex.  All rights reserved.
+ * Copyright 2010 Emulex.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -391,7 +391,8 @@
 typedef struct
 {
 #ifdef EMLXS_BIG_ENDIAN
-	uint32_t	rsvd2:25;
+	uint32_t	rsvd2:24;
+	uint32_t	keep:1;
 	uint32_t	acknowledgment:1;
 	uint32_t	version:1;
 	uint32_t	erase_or_prog:1;
@@ -408,7 +409,8 @@
 	uint32_t	erase_or_prog:1;
 	uint32_t	version:1;
 	uint32_t	acknowledgment:1;
-	uint32_t	rsvd2:25;
+	uint32_t	keep:1;
+	uint32_t	rsvd2:24;
 #endif
 
 #define	DL_FROM_BDE	0	/* method */
@@ -3685,7 +3687,7 @@
 
 
 #define	PROG_DESCR_STR_LEN	24
-#define	MAX_LOAD_ENTRY		10
+#define	MAX_LOAD_ENTRY		32
 
 typedef struct
 {
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_messages.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_messages.h	Thu Sep 09 11:46:43 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Emulex.  All rights reserved.
+ * Copyright 2010 Emulex.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1733,6 +1733,20 @@
 		NULL, \
 		0)
 
+	DEFINE_MSG(1540, \
+		emlxs_fw_update_msg, \
+		"Firmware update required.", \
+		EMLXS_WARNING, \
+		MSG_FIRMWARE, \
+		"This indicates that a firmware update is required on the " \
+		"adapter.", \
+		"The user must perform a manual adapter reset or link reset" \
+		"once the host environment is stable to trigger an automatic" \
+		"firmware download. DO NOT POWER CYCLE OR REBOOT THE SYSTEM" \
+		"DURING THE DOWNLOAD OPERATION.", \
+		NULL, \
+		0)
+
 	/* GROUP:  CT		1600 - 1699 */
 
 	DEFINE_MSG(1600, \
--- a/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_version.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/emlxs/emlxs_version.h	Thu Sep 09 11:46:43 2010 -0400
@@ -31,11 +31,11 @@
 extern "C" {
 #endif
 
-#define	EMLXS_VERSION		"2.50o"
-#define	EMLXS_DATE_MINUTE	"45"	/* 00-59 */
-#define	EMLXS_DATE_HOUR		"09"	/* 00-23 */
-#define	EMLXS_DATE_DAY		"08"	/* 00-31 */
-#define	EMLXS_DATE_MONTH	"01"	/* 01-12 */
+#define	EMLXS_VERSION		"2.50q"
+#define	EMLXS_DATE_MINUTE	"00"	/* 00-59 */
+#define	EMLXS_DATE_HOUR		"17"	/* 00-23 */
+#define	EMLXS_DATE_DAY		"30"	/* 00-31 */
+#define	EMLXS_DATE_MONTH	"07"	/* 01-12 */
 #define	EMLXS_DATE_YEAR		"2010"	/* YYYY  */
 
 #define	EMLXS_REVISION		EMLXS_DATE_YEAR "." EMLXS_DATE_MONTH "." \
--- a/usr/src/uts/common/sys/fibre-channel/fca/qlge/qlge.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/qlge/qlge.h	Thu Sep 09 11:46:43 2010 -0400
@@ -876,6 +876,7 @@
 extern void ql_atomic_set_32(volatile uint32_t *target, uint32_t newval);
 extern uint32_t ql_atomic_read_32(volatile uint32_t *target);
 extern void ql_restart_timer(qlge_t *qlge);
+extern int ql_route_initialize(qlge_t *);
 /*
  * Global Function Prototypes in qlge_flash.c source file.
  */
--- a/usr/src/uts/common/sys/fibre-channel/fca/qlge/qlge_open.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/fibre-channel/fca/qlge/qlge_open.h	Thu Sep 09 11:46:43 2010 -0400
@@ -31,7 +31,7 @@
 #endif
 
 #ifndef VERSIONSTR
-#define	VERSIONSTR	"100429-v1.05"
+#define	VERSIONSTR	"100721-v1.07"
 #endif
 
 #ifndef	QL_DEBUG
--- a/usr/src/uts/common/sys/vfs.h	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/sys/vfs.h	Thu Sep 09 11:46:43 2010 -0400
@@ -494,6 +494,7 @@
 
 /* VFS feature routines */
 void	vfs_set_feature(vfs_t *, vfs_feature_t);
+void	vfs_clear_feature(vfs_t *, vfs_feature_t);
 int	vfs_has_feature(vfs_t *, vfs_feature_t);
 void	vfs_propagate_features(vfs_t *, vfs_t *);
 
--- a/usr/src/uts/common/vm/seg_kmem.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/common/vm/seg_kmem.c	Thu Sep 09 11:46:43 2010 -0400
@@ -1519,8 +1519,13 @@
 	ASSERT(zio_mem_base != NULL);
 	ASSERT(zio_mem_size != 0);
 
+	/*
+	 * To reduce VA space fragmentation, we set up quantum caches for the
+	 * smaller sizes;  we chose 32k because that translates to 128k VA
+	 * slabs, which matches nicely with the common 128k zio_data bufs.
+	 */
 	zio_arena = vmem_create("zfs_file_data", zio_mem_base, zio_mem_size,
-	    PAGESIZE, NULL, NULL, NULL, 0, VM_SLEEP);
+	    PAGESIZE, NULL, NULL, NULL, 32 * 1024, VM_SLEEP);
 
 	zio_alloc_arena = vmem_create("zfs_file_data_buf", NULL, 0, PAGESIZE,
 	    segkmem_zio_alloc, segkmem_zio_free, zio_arena, 0, VM_SLEEP);
--- a/usr/src/uts/sun4/os/startup.c	Fri Sep 03 23:10:16 2010 +0200
+++ b/usr/src/uts/sun4/os/startup.c	Thu Sep 09 11:46:43 2010 -0400
@@ -55,6 +55,7 @@
 #include <sys/cpu_sgnblk_defs.h>
 #include <sys/clock.h>
 #include <sys/cmn_err.h>
+#include <sys/dumphdr.h>
 #include <sys/promif.h>
 #include <sys/prom_debug.h>
 #include <sys/traptrace.h>
@@ -626,6 +627,11 @@
 	}
 
 	/*
+	 * Force a serial dump, since there are no CPUs to help.
+	 */
+	dump_plat_mincpu = 0;
+
+	/*
 	 * We've managed to get here without going through the
 	 * normal panic code path. Try and save some useful
 	 * information.