changeset 10264:1196af6129ec

PSARC 2008/311 FCoE (Fibre Channel over Ethernet) Initiator 6823827 FCoE initiator for Leadville
author Zhong Wang <Zhong.Wang@Sun.COM>
date Wed, 05 Aug 2009 17:14:23 -0700
parents 56e344f46306
children b988146c84e5
files usr/src/cmd/fcinfo/fcinfo.c usr/src/cmd/fcinfo/fcoeadm.c usr/src/cmd/fcoesvc/Makefile usr/src/cmd/fcoesvc/fcoe_initiator.xml usr/src/cmd/fcoesvc/fcoeisvc.c usr/src/lib/storage/libg_fc/common/genf.c usr/src/pkgdefs/Makefile usr/src/pkgdefs/SUNWfcoei/Makefile usr/src/pkgdefs/SUNWfcoei/depend usr/src/pkgdefs/SUNWfcoei/pkginfo.tmpl usr/src/pkgdefs/SUNWfcoei/postinstall usr/src/pkgdefs/SUNWfcoei/preremove usr/src/pkgdefs/SUNWfcoei/prototype_com usr/src/pkgdefs/SUNWfcoei/prototype_i386 usr/src/pkgdefs/SUNWfcoei/prototype_sparc usr/src/pkgdefs/SUNWfcprtr/preremove usr/src/pkgdefs/SUNWfcprtr/prototype_com usr/src/tools/scripts/bfu.sh usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/comstar/port/fcoet/fcoet.c usr/src/uts/common/io/comstar/port/fcoet/fcoet.h usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c usr/src/uts/common/io/fcoe/fcoe.c usr/src/uts/common/io/fcoe/fcoe.h usr/src/uts/common/io/fcoe/fcoe_eth.c usr/src/uts/common/io/fcoe/fcoe_fc.c usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.conf usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.h usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_lv.c usr/src/uts/common/io/fibre-channel/impl/fctl.c usr/src/uts/common/io/fibre-channel/impl/fp.c usr/src/uts/common/io/fibre-channel/ulp/fcp.c usr/src/uts/common/io/fibre-channel/ulp/fcsm.c usr/src/uts/common/sys/fcoe/fcoe_common.h usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h usr/src/uts/common/sys/fibre-channel/impl/fctl.h usr/src/uts/common/sys/fibre-channel/ulp/fcp.h usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/fcoei/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/fcoei/Makefile
diffstat 48 files changed, 7083 insertions(+), 786 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fcinfo/fcinfo.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/cmd/fcinfo/fcinfo.c	Wed Aug 05 17:14:23 2009 -0700
@@ -78,6 +78,7 @@
 	{"scsi-target", no_argument,	's', NULL},
 	{"fcoe-force-promisc", no_argument, 'f', NULL},
 	{"target", no_argument,		't', NULL},
+	{"initiator", no_argument,	'i', NULL},
 	{NULL, 0, 0}
 };
 
@@ -113,13 +114,13 @@
 	    npivCreatePortListFunc, NULL, NULL, NULL,
 	    OPERAND_NONE, NULL},
 	{"create-fcoe-port",
-	    fcoeAdmCreatePortFunc, "tpnf", "t", NULL,
+	    fcoeAdmCreatePortFunc, "itpnf", NULL, NULL,
 		OPERAND_MANDATORY_SINGLE, "Network Interface Name"},
 	{"delete-fcoe-port",
 	    fcoeAdmDeletePortFunc, NULL, NULL, NULL,
 		OPERAND_MANDATORY_SINGLE, "Network Interface Name"},
 	{"list-fcoe-ports",
-	    fcoeListPortsFunc, "t", NULL, NULL,
+	    fcoeListPortsFunc, "it", NULL, NULL,
 		OPERAND_NONE, NULL},
 	{NULL, 0, NULL, NULL, NULL, 0, NULL, NULL}
 };
--- a/usr/src/cmd/fcinfo/fcoeadm.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/cmd/fcinfo/fcoeadm.c	Wed Aug 05 17:14:23 2009 -0700
@@ -86,11 +86,11 @@
 
 	fprintf(stdout, gettext("\tMTU Size: %d\n"), attr->mtu_size);
 
-	fprintf(stdout, gettext("\tMAC Factory Address: "));
+	fprintf(stdout, gettext("\tPrimary MAC Address: "));
 	for (i = 0; i < 6; i++) {
 		fprintf(stdout, gettext("%02x"), attr->mac_factory_addr[i]);
 	}
-	fprintf(stdout, gettext("\n\tMAC Current Address: "));
+	fprintf(stdout, gettext("\n\tCurrent MAC Address: "));
 	for (i = 0; i < 6; i++) {
 		fprintf(stdout, gettext("%02x"), attr->mac_current_addr[i]);
 	}
@@ -268,6 +268,9 @@
 {
 	FCOE_STATUS status;
 	FCOE_UINT8	*macLinkName;
+	FCOE_UINT32		port_num;
+	FCOE_PORT_ATTRIBUTE	*portlist = NULL;
+	int			i;
 
 	/* check the mac name operand */
 	assert(objects == 1);
@@ -312,9 +315,39 @@
 			break;
 
 		case  FCOE_STATUS_ERROR_OFFLINE_DEV:
-			fprintf(stderr,
-			    gettext("Error: Please use stmfadm to offline "
-			    "the FCoE target first\n"));
+			status = FCOE_GetPortList(&port_num, &portlist);
+			if (status != FCOE_STATUS_OK || port_num == 0) {
+				fprintf(stderr,
+				    gettext("Error: FCoE port not found on the "
+				    "specified MAC link\n"));
+				break;
+			}
+			for (i = 0; i < port_num; i++) {
+				if (strcmp(
+				    (char *)portlist[i].mac_link_name,
+				    (char *)macLinkName) == 0) {
+					if (portlist[i].port_type ==
+					    FCOE_PORTTYPE_TARGET) {
+						fprintf(stderr,
+						    gettext("Error: Please use "
+						    "stmfadm to offline the "
+						    "FCoE target first\n"));
+					} else {
+						fprintf(stderr,
+						    gettext("Error: Failed to "
+						    "delete FCoE port because "
+						    "unable to offline the "
+						    "device\n"));
+					}
+					break;
+				}
+			}
+			free(portlist);
+			if (i == port_num) {
+				fprintf(stderr,
+				    gettext("Error: FCoE port not found on the "
+				    "specified MAC link\n"));
+			}
 			break;
 
 		case FCOE_STATUS_ERROR_GET_LINKINFO:
--- a/usr/src/cmd/fcoesvc/Makefile	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/cmd/fcoesvc/Makefile	Wed Aug 05 17:14:23 2009 -0700
@@ -24,31 +24,43 @@
 # Use is subject to license terms.
 #
 
-PROG =	svc-fcoet
+PROGFCOET	= svc-fcoet
+PROGFCOEI	= svc-fcoei
+PROG		= ${PROGFCOET} ${PROGFCOEI}
 
 include ../Makefile.cmd
 
-COMMONBASE = ../../common
+COMMONBASE	= ../../common
 
-LOCAL_OBJS = fcoetsvc.o
-LOCAL_SRCS =	$(LOCAL_OBJS:%.o=%.c)
-OBJS =	$(LOCAL_OBJS)
-SRCS = $(LOCAL_SRCS)
+OBJSFCOET	= fcoetsvc.o
+OBJSFCOEI	= fcoeisvc.o
+SRCSFCOET	= $(OBJSFCOET:%.o=%.c)
+SRCSFCOEI	= $(OBJSFCOEI:%.o=%.c)
+SRCS		= $(SRCSFCOET) ${SRCSFCOEI}
 
-LDLIBS += -lfcoe
+LDLIBS		+= -lfcoe
 
-MANIFEST    = fcoe_target.xml
-SVCMETHOD   = svc-fcoet
+MANIFEST	= fcoe_target.xml
+MANIFEST	+= fcoe_initiator.xml
+SVCMETHOD	= svc-fcoet
+SVCMETHOD	+= svc-fcoei
 
 ROOTMANIFESTDIR	= $(ROOTSVCSYSTEM)
 $(ROOTSVCSYSTEM)/fcoe_target.xml	:= FILEMODE = 0444
+$(ROOTSVCSYSTEM)/fcoe_initiator.xml	:= OWNER = root
+$(ROOTSVCSYSTEM)/fcoe_initiator.xml	:= GROUP = bin
+$(ROOTSVCSYSTEM)/fcoe_initiator.xml	:= FILEMODE = 0444
 
 .KEEP_STATE:
 
 all: $(PROG)
 
-$(PROG): $(OBJS)
-	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+$(PROGFCOET): $(OBJSFCOET)
+	$(LINK.c) -o $@ $(OBJSFCOET) $(LDLIBS)
+	$(POST_PROCESS)
+
+$(PROGFCOEI): $(OBJSFCOEI)
+	$(LINK.c) -o $@ $(OBJSFCOEI) $(LDLIBS)
 	$(POST_PROCESS)
 
 install: all $(ROOTMANIFEST) $(ROOTSVCMETHOD)
@@ -56,13 +68,11 @@
 check:	$(CHKMANIFEST)
 	$(CSTYLE) -pPc $(SRCS:%=%)
 
-cmdparse.o:
-	    $(COMPILE.c) -o $@
-	    $(POST_PROCESS_O)
+clean:
+	$(RM) $(OBJSFCOET) ${OBJSFCOEI}
 
-clean:
-	$(RM) $(OBJS)
-
-lint:	lint_SRCS
+lint:
+	$(LINT.c) $(SRCSFCOET) $(LDLIBS)
+	$(LINT.c) $(SRCSFCOEI) ${LDLIBS}
 
 include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fcoesvc/fcoe_initiator.xml	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+
+<!--
+
+CDDL HEADER START
+
+The contents of this file are subject to the terms of the
+Common Development and Distribution License (the "License").
+You may not use this file except in compliance with the License.
+
+You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+or http://www.opensolaris.org/os/licensing.
+See the License for the specific language governing permissions
+and limitations under the License.
+
+When distributing Covered Code, include this CDDL HEADER in each
+file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+If applicable, add the following below this CDDL HEADER, with the
+fields enclosed by brackets "[]" replaced with your own identifying
+information: Portions Copyright [yyyy] [name of copyright owner]
+
+CDDL HEADER END
+
+Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+Use is subject to license terms.
+
+Service manifests for the FCoE initiator configuration
+-->
+
+<!--
+	system/fcoe_initiator - Export FCoE initiator port services
+-->
+
+<service_bundle type='manifest' name='SUNWfcprtr:fcoe_initiator'>
+
+<service
+	name='system/fcoe_initiator'
+	type='service'
+	version='1'>
+
+	<create_default_instance enabled='true' />
+
+	<single_instance/>
+
+	<dependency name = 'network'
+		grouping='require_any'
+		restart_on='error'
+		type='service'>
+		<service_fmri value='svc:/milestone/network'/>
+	</dependency>
+
+	<exec_method
+		type='method'
+		name='start'
+		exec='/lib/svc/method/svc-fcoei'
+		timeout_seconds='600'>
+		<method_context>
+			<method_credential
+			user='root'
+			group='root'
+			privileges='basic,sys_devices'
+			/>
+		</method_context>
+	</exec_method>
+
+	<exec_method
+		type='method'
+		name='stop'
+		exec=':true'
+		timeout_seconds='60'>
+		<method_context>
+			<method_credential
+			user='root'
+			group='root'
+			privileges='basic,sys_devices'
+			/>
+		</method_context>
+	</exec_method>
+
+	<property_group name='startd' type='framework'>
+		<propval name='duration' type='astring'
+			value='transient' />
+	</property_group>
+
+	<stability value='Evolving' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+				fcoe initiator service
+			</loctext>
+		</common_name>
+		<documentation>
+			<manpage title='fcadm' section='1M'
+				manpath='/usr/share/man' />
+		</documentation>
+	</template>
+
+</service>
+
+</service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fcoesvc/fcoeisvc.c	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,64 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <libfcoe.h>
+#include <locale.h>
+
+int
+main()
+{
+	FCOE_STATUS	status;
+	PFCOE_SMF_PORT_LIST portlist = NULL;
+	PFCOE_SMF_PORT_INSTANCE port = NULL;
+	int i;
+	int ret;
+
+	(void) setlocale(LC_ALL, "");
+
+	status = FCOE_LoadConfig(FCOE_PORTTYPE_INITIATOR, &portlist);
+
+	if (status != FCOE_STATUS_OK) {
+		ret = 1;
+	} else if (portlist == NULL) {
+		return (0);
+	} else {
+		for (i = 0; i < portlist->port_num; i++) {
+			port = &portlist->ports[i];
+			if (port->port_type == FCOE_PORTTYPE_INITIATOR) {
+				(void) FCOE_CreatePort(port->mac_link_name,
+				    port->port_type,
+				    port->port_pwwn,
+				    port->port_nwwn,
+				    port->mac_promisc);
+			}
+		}
+		ret = 0;
+	}
+
+	if (portlist != NULL) {
+		free(portlist);
+	}
+	return (ret);
+} /* end main */
--- a/usr/src/lib/storage/libg_fc/common/genf.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/lib/storage/libg_fc/common/genf.c	Wed Aug 05 17:14:23 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -78,6 +78,7 @@
 /* Bus strings - for internal use by g_get_path_type() only */
 #define	PCI_BUS			1
 #define	SBUS			2
+#define	FCOE			3
 
 struct str_type {
 	char *string;
@@ -87,6 +88,7 @@
 static struct str_type ValidBusStrings[] = {
 	{"pci@", PCI_BUS},
 	{"sbus@", SBUS},
+	{"fcoe", FCOE},
 	{NULL, 0}
 };
 
--- a/usr/src/pkgdefs/Makefile	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/pkgdefs/Makefile	Wed Aug 05 17:14:23 2009 -0700
@@ -255,6 +255,7 @@
 	SUNWfcoe \
 	SUNWfcoeu \
 	SUNWfcoet \
+	SUNWfcoei \
 	SUNWfilebench \
 	SUNWfmd  \
 	SUNWfmdr  \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/Makefile	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all: $(FILES) depend preremove postinstall
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/depend	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr      Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr       Core Solaris Kernel (Root)
+P SUNWcnetr     Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+P SUNWfcoe	Sun FCoE Transport Driver
+P SUNWfctl	Sun Fibre Channel Transport layer
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/pkginfo.tmpl	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+ 
+PKG="SUNWfcoei"
+NAME="Sun FCoE Initiator Driver"
+ARCH="ISA"
+CATEGORY="system"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKGTYPE="root"
+CLASSES="none"
+DESC="Sun FCoE (Fibre Channel over Ethernet) Initiator Driver"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+VERSION="ONVERS,REV=0.0.0"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+MAXINST="1000"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/postinstall	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+PATH=/usr/bin:/usr/sbin:$PATH; export PATH
+
+# Driver definitions
+DRVR_NAME=fcoei
+DRVR_PERM="-m '* 0600 root sys'"
+DRVR_CLASS=""
+DRVR_ALIASES=""
+
+
+if [ -z "${BASEDIR}" ]; then
+	echo "\n$0 Failed: BASEDIR is not set.\n" >&2
+	exit 1
+fi
+
+# Remove existing definition, if it exists. 
+/usr/sbin/rem_drv -b "${BASEDIR}" ${DRVR_NAME} > /dev/null 2>&1
+
+ADD_DRV="add_drv -n -b ${BASEDIR}"
+
+eval ${ADD_DRV} "${DRVR_PERM}" ${DRVR_CLASS} "${DRVR_ALIASES}" ${DRVR_NAME}
+if [ $? -ne 0 ]; then
+	echo "\nCommand Failed:\n${ADD_DRV} "${DRVR_PERM}" ${DRVR_CLASS} \
+		"${DRVR_ALIASES}" ${DRVR_NAME}\n" >&2
+	exit 1
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/preremove	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+DRVR_NAME=fcoei
+
+# Remove the driver entries but leave it attached.
+/usr/sbin/rem_drv -b ${BASEDIR} ${DRVR_NAME}
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/prototype_com	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+#
+i copyright
+i pkginfo 
+i depend
+i postinstall
+i preremove
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/prototype_i386	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+#
+# List files which are Intel specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWfcoei
+#
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+d none kernel/drv/amd64 0755 root sys
+f none kernel/drv/fcoei.conf 0644 root sys
+f none kernel/drv/fcoei 0755 root sys
+f none kernel/drv/amd64/fcoei 0755 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWfcoei/prototype_sparc	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+#
+# List files which are SPARC specific here
+#
+# source locations relative to the prototype file
+#
+#
+# SUNWfcoei
+#
+d none kernel 0755 root sys
+d none kernel/drv 0755 root sys
+f none kernel/drv/fcoei.conf 0644 root sys
+d none kernel/drv/sparcv9 0755 root sys
+f none kernel/drv/sparcv9/fcoei 0755 root sys
--- a/usr/src/pkgdefs/SUNWfcprtr/preremove	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/pkgdefs/SUNWfcprtr/preremove	Wed Aug 05 17:14:23 2009 -0700
@@ -71,4 +71,7 @@
 SERVICE="svc:/system/fcoe_target:default"
 disable_service
 
+SERVICE="svc:/system/fcoe_initiator:default"
+disable_service
+
 exit $exitcode
--- a/usr/src/pkgdefs/SUNWfcprtr/prototype_com	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/pkgdefs/SUNWfcprtr/prototype_com	Wed Aug 05 17:14:23 2009 -0700
@@ -47,9 +47,11 @@
 d none var/svc/manifest/network 0755 root sys
 d none var/svc/manifest/system 0755 root sys
 f manifest var/svc/manifest/network/npiv_config.xml 0444 root sys
+f manifest var/svc/manifest/system/fcoe_initiator.xml 0444 root sys
 f manifest var/svc/manifest/system/fcoe_target.xml 0444 root sys
 d none lib 755 root bin
 d none lib/svc 755 root bin
 d none lib/svc/method 755 root bin
 f none lib/svc/method/npivconfig 0555 root bin
+f none lib/svc/method/svc-fcoei 0555 root bin
 f none lib/svc/method/svc-fcoet 0555 root bin
--- a/usr/src/tools/scripts/bfu.sh	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/tools/scripts/bfu.sh	Wed Aug 05 17:14:23 2009 -0700
@@ -313,6 +313,7 @@
 	lib/svc/method/svc-drd
 	lib/svc/method/svc-dscp
 	lib/svc/method/svc-dumpadm
+	lib/svc/method/svc-fcoei
 	lib/svc/method/svc-fcoet
 	lib/svc/method/svc-intrd
 	lib/svc/method/svc-hal
@@ -383,6 +384,7 @@
 	var/svc/manifest/system/device/devices-audio.xml
 	var/svc/manifest/system/device/devices-fc-fabric.xml
 	var/svc/manifest/system/dumpadm.xml
+	var/svc/manifest/system/fcoe_initiator.xml
 	var/svc/manifest/system/fcoe_target.xml
 	var/svc/manifest/system/filesystem/rmvolmgr.xml
 	var/svc/manifest/system/fmd.xml
--- a/usr/src/uts/common/Makefile.files	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/Makefile.files	Wed Aug 05 17:14:23 2009 -0700
@@ -894,6 +894,8 @@
 
 FCOET_OBJS += fcoet.o fcoet_eth.o fcoet_fc.o
 
+FCOEI_OBJS += fcoei.o fcoei_eth.o fcoei_lv.o
+
 ISCSIT_SHARED_OBJS += \
 		iscsit_common.o
 
--- a/usr/src/uts/common/Makefile.rules	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/Makefile.rules	Wed Aug 05 17:14:23 2009 -0700
@@ -983,6 +983,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/fibre-channel/fca/fcoei/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/sdcard/adapters/sdhost/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2117,6 +2121,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/fibre-channel/fca/emlxs/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/fibre-channel/fca/fcoei/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/scsi/conf/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c	Wed Aug 05 17:14:23 2009 -0700
@@ -453,6 +453,8 @@
 	client_fcoet.ect_port_event = fcoet_port_event;
 	client_fcoet.ect_release_sol_frame = fcoet_release_sol_frame;
 	client_fcoet.ect_client_port_struct = ss;
+	client_fcoet.ect_fcoe_ver = FCOE_VER_NOW;
+	FCOET_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
 	ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
 	if (ret == -1) {
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h	Wed Aug 05 17:14:23 2009 -0700
@@ -33,7 +33,7 @@
 
 #ifdef	_KERNEL
 
-#define	FCOET_VERSION	"v20090311-1.00"
+#define	FCOET_VERSION	"v20090729-1.01"
 #define	FCOET_NAME	"COMSTAR FCoET "
 #define	FCOET_MOD_NAME	FCOET_NAME FCOET_VERSION
 
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c	Wed Aug 05 17:14:23 2009 -0700
@@ -540,9 +540,11 @@
 
 	bcopy(frm->frm_payload, dbuf->db_sglist[sge_idx].seg_addr,
 	    frm->frm_payload_size);
+	atomic_add_16(&dbuf->db_sglist_length, 1);
 
 	xch->xch_left_data_size -= frm->frm_payload_size;
-	if (xch->xch_left_data_size <= 0) {
+	if ((xch->xch_left_data_size <= 0) ||
+	    dbuf->db_sglist_length >= FCOET_GET_SEG_NUM(dbuf)) {
 		fc_st = FCT_SUCCESS;
 		iof = 0;
 		dbuf->db_xfer_status = fc_st;
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c	Wed Aug 05 17:14:23 2009 -0700
@@ -234,6 +234,7 @@
 		 * If it's write type command, we need send xfer_rdy now
 		 * We may need to consider bidirectional command later
 		 */
+		dbuf->db_sglist_length = 0;
 		frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(
 		    CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) +
 		    FCFH_SIZE, NULL);
--- a/usr/src/uts/common/io/fcoe/fcoe.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fcoe/fcoe.c	Wed Aug 05 17:14:23 2009 -0700
@@ -195,7 +195,7 @@
 	ddi_quiesce_not_needed
 };
 
-#define	FCOE_VERSION	"20090311-1.00"
+#define	FCOE_VERSION	"20090729-1.01"
 #define	FCOE_NAME	"FCoE Transport v" FCOE_VERSION
 #define	TASKQ_NAME_LEN	32
 
@@ -223,6 +223,7 @@
 /*
  * Driver's global variables
  */
+const fcoe_ver_e	 fcoe_ver_now	  = FCOE_VER_NOW;
 static void		*fcoe_state	  = NULL;
 fcoe_soft_state_t	*fcoe_global_ss	  = NULL;
 int			 fcoe_use_ext_log = 1;
@@ -409,23 +410,19 @@
 static int
 fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip)
 {
-	char		 name[32];
-	static int	 inicounter = 0;
-	static int	 tgtcounter = 0;
-	int		*counter;
+	char	client_addr[FCOE_STR_LEN];
+	int	rval;
 
-	if (strcmp(ddi_driver_name(client_dip), FCOET_DRIVER_NAME) == 0) {
-		counter = &tgtcounter;
-		tgtcounter++;
-	} else {
-		counter = &inicounter;
-		inicounter++;
+	rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip,
+	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
+	if (rval == -1) {
+		FCOE_LOG(__FUNCTION__, "no mac_id property: %p", client_dip);
+		return (DDI_FAILURE);
 	}
 
-	bzero(name, 32);
-	(void) sprintf((char *)name, "%x,0", *counter);
-	ddi_set_name_addr(client_dip, name);
-
+	bzero(client_addr, FCOE_STR_LEN);
+	(void) sprintf((char *)client_addr, "%x,0", rval);
+	ddi_set_name_addr(client_dip, client_addr);
 	return (DDI_SUCCESS);
 }
 
@@ -778,11 +775,9 @@
 		mutex_enter(&ss->ss_ioctl_mutex);
 		ret = fcoe_delete_port(ss->ss_dip, fcoeio,
 		    del_port_param->fdp_mac_linkid, is_target);
-		if (ret != 0) {
-			FCOE_LOG("fcoe",
-			    "fcoe_delete_port failed: %d", ret);
-		}
 		mutex_exit(&ss->ss_ioctl_mutex);
+		FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d",
+		    del_port_param->fdp_mac_linkid, ret);
 		break;
 	}
 
@@ -818,8 +813,8 @@
 		return (ENOTTY);
 	}
 
-	FCOE_LOG("fcoe", "fcoe_ioctl returned %d, fcoeio_status = %d",
-	    ret, fcoeio->fcoeio_status);
+	FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d",
+	    fcoeio->fcoeio_cmd, ret, fcoeio->fcoeio_status);
 
 fcoeiocmd_release_buf:
 	if (ret == 0) {
--- a/usr/src/uts/common/io/fcoe/fcoe.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fcoe/fcoe.h	Wed Aug 05 17:14:23 2009 -0700
@@ -156,6 +156,7 @@
 
 #define	FCOE_MAC_FLAG_ENABLED		0x01
 #define	FCOE_MAC_FLAG_BOUND		0x02
+#define	FCOE_MAC_FLAG_USER_DEL		0x04
 
 typedef struct fcoe_frame_header {
 	uint8_t		 ffh_ver[1];	/* version field - upper 4 bits */
--- a/usr/src/uts/common/io/fcoe/fcoe_eth.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fcoe/fcoe_eth.c	Wed Aug 05 17:14:23 2009 -0700
@@ -199,6 +199,9 @@
 	    mac_stat_get(mac->fm_handle, MAC_STAT_LINK_UP)?
 	    FCOE_MAC_LINK_STATE_UP:FCOE_MAC_LINK_STATE_DOWN;
 
+	mac->fm_eport.eport_link_speed =
+	    mac_client_stat_get(mac->fm_cli_handle, MAC_STAT_IFSPEED);
+
 	/*
 	 * Add a notify function so that we get updates from MAC
 	 */
@@ -259,6 +262,7 @@
 		frame_size = raw_frame_size - PADDING_SIZE;
 		frm = fcoe_allocate_frame(&mac->fm_eport, frame_size, mp);
 		if (frm != NULL) {
+			frm->frm_clock = CURRENT_CLOCK;
 			fcoe_post_frame(frm);
 		}
 
@@ -290,7 +294,6 @@
 			mac->fm_eport.eport_link_speed =
 			    mac_client_stat_get(mac->fm_cli_handle,
 			    MAC_STAT_IFSPEED);
-
 			(void) fcoe_mac_set_address(&mac->fm_eport,
 			    mac->fm_primary_addr, B_FALSE);
 
--- a/usr/src/uts/common/io/fcoe/fcoe_fc.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fcoe/fcoe_fc.c	Wed Aug 05 17:14:23 2009 -0700
@@ -72,7 +72,11 @@
 	fcoe_mac_t	*mac;
 	fcoe_port_t	*eport;
 
-	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
+	if (client->ect_fcoe_ver != fcoe_ver_now) {
+		cmn_err(CE_WARN, "FCoE modules version mismatch, "
+		    "fail registering client.");
+		return (NULL);
+	}
 
 	/*
 	 * We will not come here, when someone is changing ss_mac_list,
@@ -131,8 +135,6 @@
 {
 	fcoe_mac_t	*mac = EPORT2MAC(eport);
 
-	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
-
 	/*
 	 * Wait for all the related frame to be freed, this should be fast
 	 * because before deregister fcoei/fcoet will make sure its port
@@ -144,6 +146,11 @@
 	}
 
 	atomic_and_32(&EPORT2MAC(eport)->fm_flags, ~FCOE_MAC_FLAG_BOUND);
+	atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
+	if (!(EPORT2MAC(eport)->fm_flags & FCOE_MAC_FLAG_USER_DEL)) {
+		(void) fcoe_close_mac(mac);
+		fcoe_destroy_mac(mac);
+	}
 }
 
 /* ARGSUSED */
@@ -466,14 +473,21 @@
 	}
 
 	*is_target = EPORT_CLT_TYPE(&mac->fm_eport);
-
 	if ((mac->fm_flags & FCOE_MAC_FLAG_ENABLED) != FCOE_MAC_FLAG_ENABLED) {
 		fcoeio->fcoeio_status = FCOEIOE_ALREADY;
 		return (EALREADY);
 	}
 
+	if (!(mac->fm_flags & FCOE_MAC_FLAG_BOUND)) {
+		/*
+		 * It means that deferred detach has finished
+		 * of last delete operation
+		 */
+		goto skip_devi_offline;
+	}
+
 	atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
-
+	mac->fm_flags |= FCOE_MAC_FLAG_USER_DEL;
 	rval = ndi_devi_offline(mac->fm_client_dev, NDI_DEVI_REMOVE);
 	if (rval != NDI_SUCCESS) {
 		FCOE_LOG("fcoe", "fcoe%d: offline_driver %s failed",
@@ -485,6 +499,8 @@
 		fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE;
 		return (EBUSY);
 	}
+
+skip_devi_offline:
 	(void) fcoe_close_mac(mac);
 	fcoe_destroy_mac(mac);
 	return (0);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,1130 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/stat.h>
+#include <sys/pci.h>
+#include <sys/sunddi.h>
+#include <sys/modctl.h>
+#include <sys/file.h>
+#include <sys/cred.h>
+#include <sys/byteorder.h>
+#include <sys/atomic.h>
+#include <sys/scsi/scsi.h>
+#include <sys/mac_client.h>
+#include <sys/modhash.h>
+
+/*
+ * leadville header files
+ */
+#include <sys/fibre-channel/fc.h>
+#include <sys/fibre-channel/impl/fc_fcaif.h>
+
+/*
+ * fcoe header files
+ */
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * fcoei header files
+ */
+#include <fcoei.h>
+
+/*
+ * forward declaration of stack functions
+ */
+static uint32_t fcoei_xch_check(
+	mod_hash_key_t key, mod_hash_val_t *val, void *arg);
+static int fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp);
+static int fcoei_close(dev_t dev, int flag, int otype, cred_t *credp);
+static int fcoei_ioctl(
+	dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval);
+static int fcoei_attach_init(fcoei_soft_state_t *ss);
+static int fcoei_detach_uninit(fcoei_soft_state_t *ss);
+static void fcoei_watchdog(void *arg);
+static void fcoei_process_events(fcoei_soft_state_t *ss);
+static void fcoei_trigger_fp_attach(void *arg);
+static void fcoei_abts_exchange(fcoei_exchange_t *xch);
+static void fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss);
+
+/*
+ * Driver identificaton stuff
+ */
+static struct cb_ops fcoei_cb_ops = {
+	fcoei_open,
+	fcoei_close,
+	nodev,
+	nodev,
+	nodev,
+	nodev,
+	nodev,
+	fcoei_ioctl,
+	nodev,
+	nodev,
+	nodev,
+	nochpoll,
+	ddi_prop_op,
+	0,
+	D_MP | D_NEW | D_HOTPLUG,
+	CB_REV,
+	nodev,
+	nodev
+};
+
+static struct dev_ops fcoei_ops = {
+	DEVO_REV,
+	0,
+	nodev,
+	nulldev,
+	nulldev,
+	fcoei_attach,
+	fcoei_detach,
+	nodev,
+	&fcoei_cb_ops,
+	NULL,
+	ddi_power,
+	ddi_quiesce_not_needed
+};
+
+static struct modldrv modldrv = {
+	&mod_driverops,
+	FCOEI_NAME_VERSION,
+	&fcoei_ops,
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,
+	&modldrv,
+	NULL
+};
+
+/*
+ * Driver's global variables
+ */
+void	*fcoei_state	   = NULL;
+int	 fcoei_use_ext_log = 0;
+
+/*
+ * Common loadable module entry points _init, _fini, _info
+ */
+int
+_init(void)
+{
+	int ret;
+
+	ret = ddi_soft_state_init(&fcoei_state, sizeof (fcoei_soft_state_t), 0);
+	if (ret != DDI_SUCCESS) {
+		FCOEI_LOG(__FUNCTION__, "soft state init failed: %x", ret);
+		return (ret);
+	}
+
+	ret = mod_install(&modlinkage);
+	if (ret != 0) {
+		ddi_soft_state_fini(&fcoei_state);
+		FCOEI_LOG(__FUNCTION__, "fcoei mod_install failed: %x", ret);
+		return (ret);
+	}
+
+	/*
+	 * Let FCTL initialize devo_bus_ops
+	 */
+	fc_fca_init(&fcoei_ops);
+
+	FCOEI_LOG(__FUNCTION__, "fcoei _init succeeded");
+	return (ret);
+}
+
+int
+_fini(void)
+{
+	int ret;
+
+	ret = mod_remove(&modlinkage);
+	if (ret != 0) {
+		FCOEI_EXT_LOG(__FUNCTION__, "fcoei mod_remove failed: %x", ret);
+		return (ret);
+	}
+
+	ddi_soft_state_fini(&fcoei_state);
+	FCOEI_LOG(__FUNCTION__, "fcoei _fini succeeded");
+	return (ret);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * Autoconfiguration entry points: attach, detach, getinfo
+ */
+
+static int
+fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	int			 ret;
+	int			 fcoe_ret;
+	int			 instance;
+	fcoei_soft_state_t	*ss;
+
+	instance = ddi_get_instance(dip);
+	FCOEI_LOG(__FUNCTION__, "instance is %d", instance);
+	switch (cmd) {
+	case DDI_ATTACH:
+		ret = ddi_soft_state_zalloc(fcoei_state, instance);
+		if (ret != DDI_SUCCESS) {
+			FCOEI_LOG(__FUNCTION__, "ss zalloc failed: %x", ret);
+			return (ret);
+		}
+
+		/*
+		 * Get the soft state, and do basic initialization with dip
+		 */
+		ss = ddi_get_soft_state(fcoei_state, instance);
+		ss->ss_dip = dip;
+
+		fcoe_ret = fcoei_attach_init(ss);
+		if (fcoe_ret != FCOE_SUCCESS) {
+			ddi_soft_state_free(fcoei_state, instance);
+			FCOEI_LOG(__FUNCTION__, "fcoei_attach_init failed: "
+			    "%x", fcoe_ret);
+			return (DDI_FAILURE);
+		}
+
+		ss->ss_flags |= SS_FLAG_TRIGGER_FP_ATTACH;
+		(void) timeout(fcoei_trigger_fp_attach, ss, FCOE_SEC2TICK(1));
+		FCOEI_LOG(__FUNCTION__, "fcoei_attach succeeded: dip-%p, "
+		    "cmd-%x", dip, cmd);
+		return (DDI_SUCCESS);
+
+	case DDI_RESUME:
+		return (DDI_SUCCESS);
+
+	default:
+		FCOEI_LOG(__FUNCTION__, "unsupported attach cmd-%X", cmd);
+		return (DDI_FAILURE);
+	}
+}
+
+static int
+fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	int			 fcoe_ret;
+	int			 instance;
+	fcoei_soft_state_t	*ss;
+
+	instance = ddi_get_instance(dip);
+	ss = ddi_get_soft_state(fcoei_state, instance);
+	if (ss == NULL) {
+		FCOEI_LOG(__FUNCTION__, "get ss failed: dip-%p", dip);
+		return (DDI_FAILURE);
+	}
+
+	switch (cmd) {
+	case DDI_DETACH:
+		if (ss->ss_flags & SS_FLAG_TRIGGER_FP_ATTACH) {
+			FCOEI_LOG(__FUNCTION__, "still await fp attach");
+			return (DDI_FAILURE);
+		}
+
+		if (ss->ss_flags & SS_FLAG_LV_BOUND) {
+			FCOEI_LOG(__FUNCTION__, "fp is not detached yet");
+			return (DDI_FAILURE);
+		}
+
+		fcoe_ret = fcoei_detach_uninit(ss);
+		if (fcoe_ret != FCOE_SUCCESS) {
+			FCOEI_LOG(__FUNCTION__, "fcoei_detach_uninit failed:"
+			    " dip-%p, fcoe_ret-%d", dip, fcoe_ret);
+			return (DDI_FAILURE);
+		}
+
+		FCOEI_LOG(__FUNCTION__, "succeeded: dip-%p, cmd-%x", dip, cmd);
+		return (DDI_SUCCESS);
+
+	case DDI_SUSPEND:
+		return (DDI_SUCCESS);
+
+	default:
+		FCOEI_LOG(__FUNCTION__, "unspported detach cmd-%X", cmd);
+		return (DDI_FAILURE);
+	}
+}
+
+/*
+ * Device access entry points: open, close, ioctl
+ */
+
+static int
+fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp)
+{
+	fcoei_soft_state_t	*ss;
+
+	if (otype != OTYP_CHR) {
+		FCOEI_LOG(__FUNCTION__, "flag: %x", flag);
+		return (EINVAL);
+	}
+
+	if (drv_priv(credp)) {
+		return (EPERM);
+	}
+
+	/*
+	 * First of all, get related soft state
+	 */
+	ss = ddi_get_soft_state(fcoei_state, (int)getminor(*devp));
+	if (ss == NULL) {
+		return (ENXIO);
+	}
+
+	mutex_enter(&ss->ss_ioctl_mutex);
+	if (ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN) {
+		/*
+		 * We don't support concurrent open
+		 */
+		mutex_exit(&ss->ss_ioctl_mutex);
+		return (EBUSY);
+	}
+
+	ss->ss_ioctl_flags |= FCOEI_IOCTL_FLAG_OPEN;
+	mutex_exit(&ss->ss_ioctl_mutex);
+
+	return (0);
+}
+
+static int
+fcoei_close(dev_t dev, int flag, int otype, cred_t *credp)
+{
+	fcoei_soft_state_t	*ss;
+
+	if (otype != OTYP_CHR) {
+		FCOEI_LOG(__FUNCTION__, "flag: %x, %p", flag, credp);
+		return (EINVAL);
+	}
+
+	/*
+	 * First of all, get related soft state
+	 */
+	ss = ddi_get_soft_state(fcoei_state, (int)getminor(dev));
+	if (ss == NULL) {
+		return (ENXIO);
+	}
+
+	mutex_enter(&ss->ss_ioctl_mutex);
+	if (!(ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN)) {
+		/*
+		 * If it's not open, we can exit
+		 */
+
+		mutex_exit(&ss->ss_ioctl_mutex);
+		return (ENODEV);
+	}
+
+	ss->ss_ioctl_flags &= ~FCOEI_IOCTL_FLAG_OPEN;
+	mutex_exit(&ss->ss_ioctl_mutex);
+
+	return (0);
+}
+
+static int
+fcoei_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
+    cred_t *credp, int *rval)
+{
+	fcoei_soft_state_t	*ss;
+	int			 ret = 0;
+
+	if (drv_priv(credp) != 0) {
+		FCOEI_LOG(__FUNCTION__, "data: %p, %x", data, mode);
+		return (EPERM);
+	}
+
+	/*
+	 * Get related soft state
+	 */
+	ss = ddi_get_soft_state(fcoei_state, (int32_t)getminor(dev));
+	if (!ss) {
+		return (ENXIO);
+	}
+
+	/*
+	 * Process ioctl
+	 */
+	switch (cmd) {
+
+	default:
+		FCOEI_LOG(__FUNCTION__, "ioctl-0x%02X", cmd);
+		ret = ENOTTY;
+	}
+
+	/*
+	 * Set return value
+	 */
+	*rval = ret;
+	return (ret);
+}
+
+/*
+ * fcoei_attach_init
+ *	init related stuff of the soft state
+ *
+ * Input:
+ *	ss = the soft state that will be processed
+ *
+ * Return:
+ *	if it succeeded or not
+ *
+ * Comment:
+ *	N/A
+ */
+static int
+fcoei_attach_init(fcoei_soft_state_t *ss)
+{
+	fcoe_port_t		*eport;
+	fcoe_client_t		 client_fcoei;
+	char			 taskq_name[32];
+	int			 ret;
+	la_els_logi_t		*els = &ss->ss_els_logi;
+	svc_param_t		*class3_param;
+
+	/*
+	 * Register fcoei to FCOE as its client
+	 */
+	client_fcoei.ect_eport_flags = EPORT_FLAG_INI_MODE |
+	    EPORT_FLAG_IS_DIRECT_P2P;
+	client_fcoei.ect_max_fc_frame_size = FCOE_MAX_FC_FRAME_SIZE;
+	client_fcoei.ect_private_frame_struct_size = sizeof (fcoei_frame_t);
+	fcoei_init_ect_vectors(&client_fcoei);
+	client_fcoei.ect_client_port_struct = ss;
+	client_fcoei.ect_fcoe_ver = FCOE_VER_NOW;
+	FCOEI_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
+	ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
+	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
+	if (ret == -1) {
+		FCOEI_LOG(__FUNCTION__, "get mac_id failed");
+		return (DDI_FAILURE);
+	} else {
+		client_fcoei.ect_channelid = ret;
+	}
+
+	/*
+	 * It's fcoe's responsiblity to initialize eport's all elements,
+	 * so we needn't do eport initialization
+	 */
+	eport = fcoe_register_client(&client_fcoei);
+	if (eport == NULL) {
+		goto fail_register_client;
+	} else {
+		ss->ss_eport = eport;
+		FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
+	}
+
+	/*
+	 * Now it's time to register fca_tran to FCTL
+	 * Remember fc_local_port is transparent to FCA (fcoei)
+	 */
+	ss->ss_fca_tran.fca_version  = FCTL_FCA_MODREV_5;
+	ss->ss_fca_tran.fca_numports = 1;
+	ss->ss_fca_tran.fca_pkt_size = sizeof (fcoei_exchange_t);
+	ss->ss_fca_tran.fca_cmd_max  = 2048;
+
+	/*
+	 * scsi_tran_hba_setup could need these stuff
+	 */
+	ss->ss_fca_tran.fca_dma_lim  = NULL;
+	ss->ss_fca_tran.fca_iblock   = NULL;
+	ss->ss_fca_tran.fca_dma_attr = NULL;
+	ss->ss_fca_tran.fca_acc_attr = NULL;
+
+	/*
+	 * Initialize vectors
+	 */
+	fcoei_init_fcatran_vectors(&ss->ss_fca_tran);
+
+	/*
+	 * fc_fca_attach only sets driver's private, it has nothing to with
+	 * common port object between fcoei and leadville.
+	 * After this attach, fp_attach will be triggered, and it will call
+	 * fca_bind_port to let fcoei to know about common port object.
+	 */
+	if (fc_fca_attach(ss->ss_dip, &ss->ss_fca_tran) != DDI_SUCCESS) {
+		goto fail_fca_attach;
+	}
+
+	/*
+	 * It's time to do ss initialization
+	 */
+	ret = ddi_create_minor_node(ss->ss_dip, "admin",
+	    S_IFCHR, ddi_get_instance(ss->ss_dip), DDI_NT_NEXUS, 0);
+	if (ret != DDI_SUCCESS) {
+		goto fail_minor_node;
+	}
+
+	ss->ss_flags	   = 0;
+	ss->ss_port	   = NULL;
+	/*
+	 * ss->ss_eport has been initialized
+	 */
+
+	ss->ss_sol_oxid_hash = mod_hash_create_idhash(
+	    "fcoei_sol_oxid_hash", FCOEI_SOL_HASH_SIZE,
+	    mod_hash_null_valdtor);
+	ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
+	    "fcoei_unsol_rxid_hash", FCOEI_UNSOL_HASH_SIZE,
+	    mod_hash_null_valdtor);
+	list_create(&ss->ss_comp_xch_list, sizeof (fcoei_exchange_t),
+	    offsetof(fcoei_exchange_t, xch_comp_node));
+	ss->ss_next_sol_oxid   = 0xFFFF;
+	ss->ss_next_unsol_rxid = 0xFFFF;
+
+	mutex_init(&ss->ss_watchdog_mutex, 0, MUTEX_DRIVER, 0);
+	cv_init(&ss->ss_watchdog_cv, NULL, CV_DRIVER, NULL);
+	(void) snprintf(taskq_name, 32, "leadville_fcoei_%d_taskq",
+	    ddi_get_instance(ss->ss_dip));
+	taskq_name[31] = 0;
+	ss->ss_taskq = ddi_taskq_create(ss->ss_dip,
+	    taskq_name, 64, TASKQ_DEFAULTPRI, DDI_SLEEP);
+
+	ss->ss_link_state	  = FC_STATE_OFFLINE;
+	ss->ss_link_speed	  = 0;
+	ss->ss_port_event_counter = 0;
+
+	list_create(&ss->ss_event_list, sizeof (fcoei_event_t),
+	    offsetof(fcoei_event_t, ae_node));
+
+	ss->ss_sol_cnt1   = 0;
+	ss->ss_sol_cnt2   = 0;
+	ss->ss_sol_cnt	   = &ss->ss_sol_cnt1;
+	ss->ss_unsol_cnt1 = 0;
+	ss->ss_unsol_cnt2 = 0;
+	ss->ss_unsol_cnt  = &ss->ss_unsol_cnt1;
+	ss->ss_ioctl_flags = 0;
+
+	mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
+
+	bcopy(eport->eport_portwwn, els->nport_ww_name.raw_wwn, 8);
+	bcopy(eport->eport_nodewwn, els->node_ww_name.raw_wwn, 8);
+	els->common_service.fcph_version = 0x2008;
+	els->common_service.btob_credit = 3;
+	els->common_service.cmn_features = 0x8800;
+	els->common_service.conc_sequences = 0xff;
+	els->common_service.relative_offset = 3;
+	els->common_service.e_d_tov = 0x07d0;
+	class3_param = (svc_param_t *)&els->class_3;
+	class3_param->class_opt = 0x8800;
+	class3_param->rcv_size = els->common_service.rx_bufsize = 2048;
+	class3_param->conc_sequences = 0xff;
+	class3_param->open_seq_per_xchng = 1;
+
+	/*
+	 * Fill out RNID Management Information
+	 */
+	bcopy(ss->ss_eport->eport_portwwn, ss->ss_rnid.global_id, 8);
+	ss->ss_rnid.unit_type  = FCOEI_RNID_HBA;
+	ss->ss_rnid.ip_version = FCOEI_RNID_IPV4;
+
+	/*
+	 * Start our watchdog
+	 */
+	(void) ddi_taskq_dispatch(ss->ss_taskq,
+	    fcoei_watchdog, ss, DDI_SLEEP);
+	while (!(ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING)) {
+		delay(50);
+	}
+
+	/*
+	 * Report the device to the system
+	 */
+	ddi_report_dev(ss->ss_dip);
+	return (DDI_SUCCESS);
+
+
+fail_minor_node:
+	FCOEI_LOG(__FUNCTION__, "fail_minor_node");
+	fc_fca_detach(ss->ss_dip);
+
+fail_fca_attach:
+	eport->eport_deregister_client(eport);
+	FCOEI_LOG(__FUNCTION__, "fail_fca_attach");
+
+fail_register_client:
+	FCOEI_LOG(__FUNCTION__, "fail_register_client");
+	return (DDI_FAILURE);
+}
+
+/*
+ * fcoei_detach_uninit
+ *	uninit related stuff of the soft state
+ *
+ * Input:
+ *	ss = the soft state that will be processed
+ *
+ * Return:
+ *	if it succeeded or not
+ *
+ * Comment:
+ *	N/A
+ */
+int
+fcoei_detach_uninit(fcoei_soft_state_t *ss)
+{
+	/*
+	 * Stop watchdog first
+	 */
+	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
+		ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
+		cv_broadcast(&ss->ss_watchdog_cv);
+	}
+
+	/*
+	 * Destroy the taskq
+	 */
+	ddi_taskq_wait(ss->ss_taskq);
+	ddi_taskq_destroy(ss->ss_taskq);
+
+	/*
+	 * Release all allocated resources
+	 */
+	mutex_destroy(&ss->ss_ioctl_mutex);
+	mutex_destroy(&ss->ss_watchdog_mutex);
+	cv_destroy(&ss->ss_watchdog_cv);
+	mod_hash_destroy_idhash(ss->ss_sol_oxid_hash);
+	mod_hash_destroy_idhash(ss->ss_unsol_rxid_hash);
+	list_destroy(&ss->ss_event_list);
+	ss->ss_eport->eport_deregister_client(ss->ss_eport);
+	ddi_remove_minor_node(ss->ss_dip, NULL);
+
+	/*
+	 * Release itself
+	 */
+	ddi_soft_state_free(fcoei_state, ddi_get_instance(ss->ss_dip));
+	return (FCOE_SUCCESS);
+}
+
+/*
+ * fcoei_watchdog
+ *	Perform periodic checking and routine tasks
+ *
+ * Input:
+ *	arg = the soft state that will be processed
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	N/A
+ */
+static void
+fcoei_watchdog(void *arg)
+{
+	fcoei_soft_state_t	*ss;
+	clock_t			 tmp_delay;
+	clock_t			 start_clock;
+	clock_t			 last_clock;
+
+	/*
+	 * For debugging
+	 */
+	ss = (fcoei_soft_state_t *)arg;
+	FCOEI_LOG(__FUNCTION__, "ss %p", ss);
+	FCOEI_LOG(__FUNCTION__, "sol_hash %p", ss->ss_sol_oxid_hash);
+	FCOEI_LOG(__FUNCTION__, "unsol_hash %p", ss->ss_unsol_rxid_hash);
+	ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
+	tmp_delay = FCOE_SEC2TICK(1) / 2;
+	last_clock = CURRENT_CLOCK;
+
+	/*
+	 * If nobody reqeusts to terminate the watchdog, we will work forever
+	 */
+	while (!(ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG)) {
+		/*
+		 * We handle all asynchronous events serially
+		 */
+		fcoei_process_events(ss);
+
+		/*
+		 * To avoid to check timing too freqently, we check
+		 * if we need skip timing stuff.
+		 */
+		start_clock = CURRENT_CLOCK;
+		if ((start_clock - last_clock) < tmp_delay) {
+			goto end_timing;
+		} else {
+			last_clock = start_clock;
+		}
+
+		/*
+		 * It's time to do timeout checking of solicited exchanges
+		 */
+		if (ss->ss_sol_cnt == (&ss->ss_sol_cnt1)) {
+			if (ss->ss_sol_cnt2 == 0) {
+				ss->ss_sol_cnt = &ss->ss_sol_cnt2;
+			} else {
+				mod_hash_walk(ss->ss_sol_oxid_hash,
+				    fcoei_xch_check, ss);
+			}
+		} else {
+			if (ss->ss_sol_cnt1 == 0) {
+				ss->ss_sol_cnt = &ss->ss_sol_cnt1;
+			} else {
+				mod_hash_walk(ss->ss_sol_oxid_hash,
+				    fcoei_xch_check, ss);
+			}
+		}
+
+		/*
+		 * It's time to do timeout checking of unsolicited exchange
+		 */
+		if (ss->ss_unsol_cnt == (&ss->ss_unsol_cnt1)) {
+			if (ss->ss_unsol_cnt2 == 0) {
+				ss->ss_unsol_cnt = &ss->ss_unsol_cnt2;
+			} else {
+				mod_hash_walk(ss->ss_unsol_rxid_hash,
+				    fcoei_xch_check, ss);
+			}
+		} else {
+			if (ss->ss_unsol_cnt1 == 0) {
+				ss->ss_unsol_cnt = &ss->ss_unsol_cnt1;
+			} else {
+				mod_hash_walk(ss->ss_unsol_rxid_hash,
+				    fcoei_xch_check, ss);
+			}
+		}
+
+		/*
+		 * Check if there are exchanges which are ready to complete
+		 */
+		fcoei_handle_comp_xch_list(ss);
+
+	end_timing:
+		/*
+		 * Wait for next cycle
+		 */
+		mutex_enter(&ss->ss_watchdog_mutex);
+		ss->ss_flags |= SS_FLAG_WATCHDOG_IDLE;
+		if (!list_is_empty(&ss->ss_event_list)) {
+			goto skip_wait;
+		}
+
+		(void) cv_timedwait(&ss->ss_watchdog_cv,
+		    &ss->ss_watchdog_mutex, CURRENT_CLOCK +
+		    (clock_t)tmp_delay);
+	skip_wait:
+		ss->ss_flags &= ~SS_FLAG_WATCHDOG_IDLE;
+		mutex_exit(&ss->ss_watchdog_mutex);
+	}
+
+	/*
+	 * Do clear work before exit
+	 */
+	fcoei_clear_watchdog_jobs(ss);
+
+	/*
+	 * Watchdog has stopped
+	 */
+	ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
+}
+
+static void
+fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss)
+{
+	fcoei_event_t 		*ae;
+	fcoe_frame_t		*frm;
+
+	mutex_enter(&ss->ss_watchdog_mutex);
+	while (!list_is_empty(&ss->ss_event_list)) {
+		ae = (fcoei_event_t *)list_head(&ss->ss_event_list);
+		list_remove(&ss->ss_event_list, ae);
+		switch (ae->ae_type) {
+		case AE_EVENT_SOL_FRAME:
+			frm = (fcoe_frame_t *)ae->ae_obj;
+			frm->frm_eport->eport_release_frame(frm);
+			break;
+
+		case AE_EVENT_UNSOL_FRAME:
+			frm = (fcoe_frame_t *)ae->ae_obj;
+			frm->frm_eport->eport_free_netb(frm->frm_netb);
+			frm->frm_eport->eport_release_frame(frm);
+			break;
+
+		case AE_EVENT_PORT:
+			atomic_add_32(&ss->ss_port_event_counter, -1);
+			/* FALLTHROUGH */
+
+		case AE_EVENT_RESET:
+			kmem_free(ae, sizeof (fcoei_event_t));
+			break;
+
+		case AE_EVENT_EXCHANGE:
+			/* FALLTHROUGH */
+
+		default:
+			break;
+		}
+	}
+
+	mod_hash_clear(ss->ss_unsol_rxid_hash);
+	mod_hash_clear(ss->ss_sol_oxid_hash);
+
+	while (!list_is_empty(&ss->ss_comp_xch_list)) {
+		list_remove_head(&ss->ss_comp_xch_list);
+	}
+	mutex_exit(&ss->ss_watchdog_mutex);
+}
+
+/*
+ * fcoei_process_events
+ *	Process the events one by one
+ *
+ * Input:
+ *	ss = the soft state that will be processed
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	N/A
+ */
+static void
+fcoei_process_events(fcoei_soft_state_t *ss)
+{
+	fcoei_event_t	*ae = NULL;
+
+	/*
+	 * It's the only place to delete node from ss_event_list, so we needn't
+	 * hold mutex to check if the list is empty.
+	 */
+	ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
+	while (list_is_empty(&ss->ss_event_list) == B_FALSE) {
+		mutex_enter(&ss->ss_watchdog_mutex);
+		ae = (fcoei_event_t *)list_remove_head(&ss->ss_event_list);
+		mutex_exit(&ss->ss_watchdog_mutex);
+
+		switch (ae->ae_type) {
+		case AE_EVENT_SOL_FRAME:
+			fcoei_handle_sol_frame_done((fcoe_frame_t *)ae->ae_obj);
+			break;
+
+		case AE_EVENT_UNSOL_FRAME:
+			fcoei_process_unsol_frame((fcoe_frame_t *)ae->ae_obj);
+			break;
+
+		case AE_EVENT_EXCHANGE:
+			fcoei_process_event_exchange(ae);
+			break;
+
+		case AE_EVENT_PORT:
+			fcoei_process_event_port(ae);
+			break;
+
+		case AE_EVENT_RESET:
+			fcoei_process_event_reset(ae);
+			break;
+
+		default:
+			FCOEI_LOG(__FUNCTION__, "unsupported events");
+		}
+
+	}
+}
+
+/*
+ * fcoei_handle_tmout_xch_list
+ *	Complete every exchange in the timed-out xch list of the soft state
+ *
+ * Input:
+ *	ss = the soft state that need be handled
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	When mod_hash_walk is in progress, we can't change the hashtable.
+ *	This is post-walk handling of exchange timing
+ */
+void
+fcoei_handle_comp_xch_list(fcoei_soft_state_t *ss)
+{
+	fcoei_exchange_t	*xch	  = NULL;
+
+	while ((xch = list_remove_head(&ss->ss_comp_xch_list)) != NULL) {
+		fcoei_complete_xch(xch, NULL, xch->xch_fpkt->pkt_state,
+		    xch->xch_fpkt->pkt_reason);
+	}
+}
+
+/*
+ * fcoei_xch_check
+ *	Check if the exchange timed out or link is down
+ *
+ * Input:
+ *	key = rxid of the unsolicited exchange
+ *	val = the unsolicited exchange
+ *	arg = the soft state
+ *
+ * Return:
+ *	MH_WALK_CONTINUE = continue to walk
+ *
+ * Comment:
+ *	We need send ABTS for timed-out for solicited exchange
+ *	If it's solicited FLOGI, we need set SS_FLAG_FLOGI_FAILED
+ *	If the link is down, we think it has timed out too.
+ */
+static uint32_t
+fcoei_xch_check(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
+{
+	fcoei_exchange_t	*xch = (fcoei_exchange_t *)val;
+
+	ASSERT(xch->xch_ss == arg);
+	if ((xch->xch_end_tick < CURRENT_CLOCK) &&
+	    (xch->xch_ss->ss_link_state != FC_STATE_OFFLINE)) {
+		if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
+			ASSERT(xch->xch_oxid == CMHK(key));
+			/*
+			 * It's solicited exchange
+			 */
+			fcoei_abts_exchange(xch);
+			if (LA_ELS_FLOGI == ((ls_code_t *)(void *)
+			    xch->xch_fpkt->pkt_cmd)->ls_code) {
+				/*
+				 * It's solicited FLOGI
+				 */
+				xch->xch_ss->ss_flags |= SS_FLAG_FLOGI_FAILED;
+			}
+		}
+
+		FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x  timed out",
+		    xch->xch_oxid, xch->xch_rxid);
+		xch->xch_flags |= XCH_FLAG_TMOUT;
+		xch->xch_fpkt->pkt_state = FC_PKT_TIMEOUT;
+		xch->xch_fpkt->pkt_reason = FC_REASON_ABORTED;
+		list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
+	} else if (xch->xch_ss->ss_link_state == FC_STATE_OFFLINE) {
+		FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x  offline complete",
+		    xch->xch_oxid, xch->xch_rxid);
+		xch->xch_flags |= XCH_FLAG_TMOUT;
+		xch->xch_fpkt->pkt_state = FC_PKT_PORT_OFFLINE;
+		xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
+		list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
+	}
+
+	return (MH_WALK_CONTINUE);
+}
+
+/*
+ * fcoei_init_ifm
+ *	initialize fcoei_frame
+ *
+ * Input:
+ *	frm = the frame that ifm need link to
+ *	xch = the exchange that ifm need link to
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	For solicited frames, it's called after FC frame header initialization
+ *	For unsolicited frames, it's called just after the frame enters fcoei
+ */
+void
+fcoei_init_ifm(fcoe_frame_t *frm, fcoei_exchange_t *xch)
+{
+	FRM2IFM(frm)->ifm_frm = frm;
+	FRM2IFM(frm)->ifm_xch = xch;
+	FRM2IFM(frm)->ifm_rctl = FRM_R_CTL(frm);
+}
+
+/*
+ * fcoei_trigger_fp_attach
+ *	Trigger fp_attach for this fcoei port
+ *
+ * Input:
+ *	arg = the soft state that fp will attach
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	N/A
+ */
+static void
+fcoei_trigger_fp_attach(void * arg)
+{
+	fcoei_soft_state_t	*ss    = (fcoei_soft_state_t *)arg;
+	dev_info_t		*child = NULL;
+	int			 rval  = NDI_FAILURE;
+
+	ndi_devi_alloc_sleep(ss->ss_dip, "fp", DEVI_PSEUDO_NODEID, &child);
+	if (child == NULL) {
+		FCOEI_LOG(__FUNCTION__, "can't alloc dev_info");
+		return;
+	}
+
+	/*
+	 * fp/fctl need this property
+	 */
+	if (ddi_prop_update_string(DDI_DEV_T_NONE, child,
+	    "bus-addr", "0,0") != DDI_PROP_SUCCESS) {
+		FCOEI_LOG(__FUNCTION__, "update bus-addr failed");
+		(void) ndi_devi_free(child);
+		return;
+	}
+
+	/*
+	 * If it's physical HBA, fp.conf will register the property.
+	 * fcoei is one software HBA, so we need register it manually
+	 */
+	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
+	    "port", 0) != DDI_PROP_SUCCESS) {
+		FCOEI_LOG(__FUNCTION__, "update port failed");
+		(void) ndi_devi_free(child);
+		return;
+	}
+
+	/*
+	 * It will call fp_attach eventually
+	 */
+	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
+	ss->ss_flags &= ~SS_FLAG_TRIGGER_FP_ATTACH;
+	if (rval != NDI_SUCCESS) {
+		FCOEI_LOG(__FUNCTION__, "devi_online: %d", rval);
+	} else {
+		FCOEI_LOG(__FUNCTION__, "triggered successfully");
+	}
+}
+
+/*
+ * fcoei_abts_exchange
+ *	Send ABTS to abort solicited exchange
+ *
+ * Input:
+ *	xch = the exchange that will be aborted
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	ABTS frame uses the same oxid as the exchange
+ */
+static void
+fcoei_abts_exchange(fcoei_exchange_t *xch)
+{
+	fc_packet_t	*fpkt = xch->xch_fpkt;
+	fcoe_frame_t	*frm  = NULL;
+
+	/*
+	 * BLS_ABTS doesn't contain any other payload except FCFH
+	 */
+	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
+	    FCFH_SIZE, NULL);
+	if (frm == NULL) {
+		FCOEI_LOG(__FUNCTION__, "can't alloc frame: %p", xch);
+		return;
+	}
+
+	FFM_R_CTL(0x81, frm);
+	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
+	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
+	FFM_F_CTL(0x090000, frm);
+	FFM_SEQ_ID(0x01, frm);
+	FFM_OXID(xch->xch_oxid, frm);
+	FFM_RXID(xch->xch_rxid, frm);
+	fcoei_init_ifm(frm, xch);
+	xch->xch_ss->ss_eport->eport_tx_frame(frm);
+}
+
+/*
+ * fcoei_complete_xch
+ *	Complete the exchange
+ *
+ * Input:
+ *	xch = the exchange that will be completed
+ *	frm = newly-allocated frame that has not been submitted
+ *	pkt_state = LV fpkt state
+ *	pkt_reason = LV fpkt reason
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	N/A
+ */
+void
+fcoei_complete_xch(fcoei_exchange_t *xch, fcoe_frame_t *frm,
+    uint8_t pkt_state, uint8_t pkt_reason)
+{
+	mod_hash_val_t val;
+
+	if (pkt_state != FC_PKT_SUCCESS) {
+		FCOEI_LOG(__FUNCTION__, "FHDR: %x/%x/%x, %x/%x/%x",
+		    xch->xch_fpkt->pkt_cmd_fhdr.r_ctl,
+		    xch->xch_fpkt->pkt_cmd_fhdr.f_ctl,
+		    xch->xch_fpkt->pkt_cmd_fhdr.type,
+		    xch->xch_fpkt->pkt_resp_fhdr.r_ctl,
+		    xch->xch_fpkt->pkt_resp_fhdr.f_ctl,
+		    xch->xch_fpkt->pkt_resp_fhdr.type);
+		FCOEI_LOG(__FUNCTION__, "%p/%p/%x/%x",
+		    xch, frm, pkt_state, pkt_reason);
+	}
+
+	if (frm != NULL) {
+		/*
+		 * It's newly-allocated frame , which we haven't sent out
+		 */
+		xch->xch_ss->ss_eport->eport_free_netb(frm->frm_netb);
+		xch->xch_ss->ss_eport->eport_release_frame(frm);
+		FCOEI_LOG(__FUNCTION__, "xch: %p, not submitted", xch);
+	}
+
+	/*
+	 * If xch is in hash table, we need remove it
+	 */
+	if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
+		mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
+		    FMHK(xch->xch_oxid), &val);
+		ASSERT((fcoei_exchange_t *)val == xch);
+		xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
+	} else if (xch->xch_flags & XCH_FLAG_IN_UNSOL_HASH) {
+		mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
+		    FMHK(xch->xch_rxid), &val);
+		ASSERT((fcoei_exchange_t *)val == xch);
+		xch->xch_flags &= ~XCH_FLAG_IN_UNSOL_HASH;
+	} else {
+		FCOEI_LOG(__FUNCTION__, "xch not in any hash: %p", xch);
+	}
+
+	xch->xch_fpkt->pkt_state = pkt_state;
+	xch->xch_fpkt->pkt_reason = pkt_reason;
+	if (xch->xch_fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
+		FCOEI_LOG(__FUNCTION__, "polled xch is done: %p", xch);
+		sema_v(&xch->xch_sema);
+	} else {
+		xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.conf	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,24 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.h	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,371 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef	_FCOEI_H
+#define	_FCOEI_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifdef	_KERNEL
+
+/*
+ * FCOEI logging
+ */
+extern int fcoei_use_ext_log;
+extern void *fcoei_state;
+
+#define	FCOEI_EXT_LOG(log_ident, ...)				\
+	{							\
+		if (fcoei_use_ext_log) {			\
+			fcoe_trace(log_ident, __VA_ARGS__);	\
+		}						\
+	}
+
+#define	FCOEI_LOG(log_ident, ...)		\
+	fcoe_trace(log_ident, __VA_ARGS__)
+
+/*
+ * IOCTL supporting stuff
+ */
+#define	FCOEI_IOCTL_FLAG_MASK		0xFF
+#define	FCOEI_IOCTL_FLAG_IDLE		0x00
+#define	FCOEI_IOCTL_FLAG_OPEN		0x01
+#define	FCOEI_IOCTL_FLAG_EXCL		0x02
+
+/*
+ * define common constants
+ */
+#define	FCOEI_MAX_OPEN_XCHS	2048
+#define	FCOEI_SOL_HASH_SIZE	2048
+#define	FCOEI_UNSOL_HASH_SIZE	128
+#define	FCOEI_VERSION		"20090729-1.00"
+#define	FCOEI_NAME_VERSION	"SunFC FCoEI v" FCOEI_VERSION
+
+/*
+ * define RNID Management Info
+ */
+#define	FCOEI_RNID_HBA	0x7
+#define	FCOEI_RNID_IPV4	0x1
+#define	FCOEI_RNID_IPV6	0x2
+
+typedef enum event_type {
+	AE_EVENT_NONE = 0,
+	AE_EVENT_EXCHANGE,
+	AE_EVENT_SOL_FRAME,
+	AE_EVENT_UNSOL_FRAME,
+	AE_EVENT_PORT,
+	AE_EVENT_ABORT,
+	AE_EVENT_RESET,
+} event_type_e;
+
+typedef struct fcoei_event {
+	list_node_t	 ae_node;
+	event_type_e	 ae_type;
+
+	/*
+	 * event specific
+	 */
+	uint64_t	 ae_specific;
+
+	/*
+	 * event related object
+	 */
+	void		*ae_obj;
+} fcoei_event_t;
+
+typedef struct fcoei_soft_state {
+	dev_info_t		*ss_dip;
+	uint32_t		 ss_flags;
+	uint32_t		 ss_fcp_data_payload_size;
+	list_t			 ss_comp_xch_list;
+
+	/*
+	 * common data structure (fc_local_port_t) between leadville and fcoei
+	 */
+	void			*ss_port;
+
+	/*
+	 * common data structure between fcoei and fcoe module
+	 */
+	fcoe_port_t		*ss_eport;
+
+	mod_hash_t		*ss_sol_oxid_hash;
+	mod_hash_t		*ss_unsol_rxid_hash;
+	uint16_t		 ss_next_sol_oxid;
+	uint16_t		 ss_next_unsol_rxid;
+
+	/*
+	 * We will use ss_taskq to dispatch watchdog and other tasks
+	 */
+	ddi_taskq_t		*ss_taskq;
+
+	kcondvar_t		 ss_watchdog_cv;
+	kmutex_t		 ss_watchdog_mutex;
+
+	/*
+	 * current port state, speed. see fctl.h
+	 */
+	uint16_t		 ss_link_state;
+	uint16_t		 ss_link_speed;
+
+	/*
+	 * # of unprocessed port/link change
+	 */
+	uint32_t		 ss_port_event_counter;
+	list_t			 ss_event_list;
+
+	/*
+	 * solicited and unsolicited exchanges timing checking
+	 */
+	uint32_t		 ss_sol_cnt1;
+	uint32_t		 ss_sol_cnt2;
+	uint32_t		*ss_sol_cnt;
+	uint32_t		 ss_unsol_cnt1;
+	uint32_t		 ss_unsol_cnt2;
+	uint32_t		*ss_unsol_cnt;
+
+	/*
+	 * ioctl related stuff
+	 */
+	uint32_t		 ss_ioctl_flags;
+	kmutex_t		 ss_ioctl_mutex;
+
+	/*
+	 * fp-defined routines that fcoei will call
+	 */
+	fc_fca_bind_info_t	 ss_bind_info;
+
+	/*
+	 * fcoei-defined plogi response that fp will use
+	 */
+	la_els_logi_t		 ss_els_logi;
+
+	/*
+	 * fcoei-defined routines that fp will call
+	 */
+	fc_fca_tran_t		 ss_fca_tran;
+
+	/*
+	 * Direct p2p information, and ss's fcid will be stored here
+	 */
+	fc_fca_p2p_info_t	ss_p2p_info;
+
+	/*
+	 * RNID Management Information
+	 */
+	fc_rnid_t			ss_rnid;
+} fcoei_soft_state_t;
+
+#define	SS_FLAG_LV_NONE			0x0000
+#define	SS_FLAG_LV_BOUND		0x0001
+#define	SS_FLAG_PORT_DISABLED		0x0002
+#define	SS_FLAG_TERMINATE_WATCHDOG	0x0004
+#define	SS_FLAG_WATCHDOG_RUNNING	0x0008
+#define	SS_FLAG_WATCHDOG_IDLE		0x0010
+#define	SS_FLAG_TRIGGER_FP_ATTACH	0x0020
+#define	SS_FLAG_FLOGI_FAILED		0x0040
+
+/*
+ * fcoei_frame - corresponding data structure to fcoe_frame/fc_frame
+ */
+typedef struct fcoei_frame {
+	fcoei_event_t		 ifm_ae;
+	fcoe_frame_t		*ifm_frm;
+	uint32_t		 ifm_flags;
+	struct fcoei_exchange	*ifm_xch;
+
+	/*
+	 * will be used after the relevant frame mblk was released by ETH layer
+	 */
+	uint8_t			 ifm_rctl;
+} fcoei_frame_t;
+
+#define	IFM_FLAG_NONE		0x0000
+#define	IFM_FLAG_FREE_NETB	0x0001
+
+/*
+ * fcoei_exchange - corresponding data structure to leadville fc_packet
+ */
+typedef struct fcoei_exchange {
+	list_node_t		 xch_comp_node;
+	fcoei_event_t		 xch_ae;
+	uint32_t		 xch_flags;
+	fcoei_soft_state_t	*xch_ss;
+	clock_t			 xch_start_tick;
+	clock_t			 xch_end_tick;
+	int			 xch_resid;
+	ksema_t			 xch_sema;
+
+	/*
+	 * current cnt for timing check, when the exchange is created
+	 */
+	uint32_t		*xch_cnt;
+
+	/*
+	 * leadville fc_packet will not maintain oxid/rxid,
+	 * so fcoei exchange  need do it
+	 */
+	uint16_t		 xch_oxid;
+	uint16_t		 xch_rxid;
+
+	/*
+	 * to link leadville's stuff
+	 */
+	fc_packet_t		*xch_fpkt;
+	fc_unsol_buf_t		*xch_ub;
+} fcoei_exchange_t;
+
+#define	XCH_FLAG_NONE		0x00000000
+#define	XCH_FLAG_TMOUT		0x00000001
+#define	XCH_FLAG_ABORT		0x00000002
+#define	XCH_FLAG_IN_SOL_HASH	0x00000004
+#define	XCH_FLAG_IN_UNSOL_HASH	0x00000008
+
+typedef struct fcoei_walk_arg
+{
+	fcoei_exchange_t	*wa_xch;
+	uint16_t		 wa_oxid;
+} fcoei_walk_arg_t;
+
+/*
+ * Define conversion and calculation macros
+ */
+#define	FRM2IFM(x_frm)	((fcoei_frame_t *)(x_frm)->frm_client_private)
+#define	FRM2SS(x_frm)							\
+	((fcoei_soft_state_t *)(x_frm)->frm_eport->eport_client_private)
+
+#define	PORT2SS(x_port)	((fcoei_soft_state_t *)(x_port)->port_fca_private)
+#define	EPORT2SS(x_eport)					\
+	((fcoei_soft_state_t *)(x_eport)->eport_client_private)
+
+#define	FPKT2XCH(x_fpkt)	((fcoei_exchange_t *)x_fpkt->pkt_fca_private)
+#define	FRM2FPKT(x_fpkt)	(FRM2IFM(frm)->ifm_xch->xch_fpkt)
+
+#define	HANDLE2SS(x_handle)	((fcoei_soft_state_t *)fca_handle)
+
+#define	FPLD			frm->frm_payload
+
+#define	FCOEI_FRM2FHDR(x_frm, x_fhdr)				\
+	{							\
+		(x_fhdr)->r_ctl = FRM_R_CTL(x_frm);		\
+		(x_fhdr)->d_id = FRM_D_ID(x_frm);		\
+		(x_fhdr)->s_id = FRM_S_ID(x_frm);		\
+		(x_fhdr)->type = FRM_TYPE(x_frm);		\
+		(x_fhdr)->f_ctl = FRM_F_CTL(x_frm);		\
+		(x_fhdr)->seq_id = FRM_SEQ_ID(x_frm);		\
+		(x_fhdr)->df_ctl = FRM_DF_CTL(x_frm);		\
+		(x_fhdr)->seq_cnt = FRM_SEQ_CNT(x_frm);		\
+		(x_fhdr)->ox_id = FRM_OXID(x_frm);		\
+		(x_fhdr)->rx_id = FRM_RXID(x_frm);		\
+		(x_fhdr)->ro = FRM_PARAM(x_frm);		\
+	}
+
+#define	FCOEI_PARTIAL_FHDR2FRM(x_fhdr, x_frm)		\
+	{						\
+		FFM_R_CTL((x_fhdr)->r_ctl, x_frm);	\
+		FFM_D_ID((x_fhdr)->d_id, x_frm);	\
+		FFM_S_ID((x_fhdr)->s_id, x_frm);	\
+		FFM_TYPE((x_fhdr)->type, x_frm);	\
+		FFM_F_CTL((x_fhdr)->f_ctl, x_frm);	\
+	}
+
+#define	PRT_FRM_HDR(x_p, x_f)						\
+	{								\
+		FCOEI_LOG(x_p, "rctl/%x, fctl/%x, type/%x, oxid/%x",	\
+			FCOE_B2V_1((x_f)->frm_hdr->hdr_r_ctl),		\
+			FCOE_B2V_3((x_f)->frm_hdr->hdr_f_ctl),		\
+			FCOE_B2V_1((x_f)->frm_hdr->hdr_type),		\
+			FCOE_B2V_2((x_f)->frm_hdr->hdr_oxid));		\
+	}
+
+#define	FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp)				\
+	{								\
+		do {							\
+			if (++xch->xch_ss->ss_next_sol_oxid == 0xFFFF) { \
+				++xch->xch_ss->ss_next_sol_oxid;	\
+			}						\
+		} while (mod_hash_find(xch->xch_ss->ss_sol_oxid_hash,	\
+		    (mod_hash_key_t)(intptr_t)xch->xch_ss->ss_next_sol_oxid, \
+		    (mod_hash_val_t)&xch_tmp) == 0);	\
+		xch->xch_oxid = xch->xch_ss->ss_next_sol_oxid;		\
+		xch->xch_rxid = 0xFFFF;					\
+		(void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash,	\
+		    FMHK(xch->xch_oxid), (mod_hash_val_t)xch); \
+		xch->xch_flags |= XCH_FLAG_IN_SOL_HASH;			\
+	}
+
+#define	FCOEI_SET_UNSOL_FRM_RXID(frm, xch_tmp)				\
+	{								\
+		do {							\
+			if (++FRM2SS(frm)->ss_next_unsol_rxid == 0xFFFF) { \
+				++FRM2SS(frm)->ss_next_unsol_rxid;	\
+			}						\
+		} while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash,	\
+		    (mod_hash_key_t)(intptr_t)FRM2SS(frm)->ss_next_unsol_rxid, \
+		    (mod_hash_val_t)&xch_tmp) == 0);	\
+		FFM_RXID(FRM2SS(frm)->ss_next_unsol_rxid, frm);	\
+	}
+
+#define	FCOEI_INIT_UNSOL_ID_HASH(xch)					\
+	{								\
+		xch->xch_oxid = fpkt->pkt_cmd_fhdr.ox_id;		\
+		xch->xch_rxid = fpkt->pkt_cmd_fhdr.rx_id;		\
+		(void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash,	\
+		    FMHK(xch->xch_rxid), (mod_hash_val_t)xch); 		\
+		xch->xch_flags |= XCH_FLAG_IN_UNSOL_HASH;		\
+	}
+
+/*
+ * Common functions defined in fcoei.c
+ */
+void fcoei_complete_xch(fcoei_exchange_t *xch, fcoe_frame_t *frm,
+    uint8_t pkt_state, uint8_t pkt_reason);
+void fcoei_init_ifm(fcoe_frame_t *frm, fcoei_exchange_t *xch);
+void fcoei_handle_comp_xch_list(fcoei_soft_state_t *ss);
+
+/*
+ * Common functions defined in fcoei_lv.c
+ */
+void fcoei_init_fcatran_vectors(fc_fca_tran_t *fcatran);
+void fcoei_process_event_exchange(fcoei_event_t *ae);
+void fcoei_process_event_reset(fcoei_event_t *ae);
+
+/*
+ * Common functions defined in fcoei_eth.c
+ */
+void fcoei_init_ect_vectors(fcoe_client_t *ect);
+void fcoei_process_unsol_frame(fcoe_frame_t *frm);
+void fcoei_handle_sol_frame_done(fcoe_frame_t *frm);
+void fcoei_process_event_port(fcoei_event_t *ae);
+void fcoei_port_event(fcoe_port_t *eport, uint32_t event);
+
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _FCOEI_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,1390 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * The following notice accompanied the original version of this file:
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file defines interface functions between fcoe and fcoei driver.
+ */
+
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/stat.h>
+#include <sys/pci.h>
+#include <sys/sunddi.h>
+#include <sys/modctl.h>
+#include <sys/file.h>
+#include <sys/cred.h>
+#include <sys/byteorder.h>
+#include <sys/atomic.h>
+#include <sys/scsi/scsi.h>
+#include <sys/mac_client.h>
+#include <sys/modhash.h>
+
+/*
+ * LEADVILLE header files
+ */
+#include <sys/fibre-channel/fc.h>
+#include <sys/fibre-channel/impl/fc_fcaif.h>
+
+/*
+ * COMSTAR header files
+ */
+#include <sys/stmf_defines.h>
+
+/*
+ * FCOE header files
+ */
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoei.h>
+
+/*
+ * Forward declaration of internal functions
+ */
+static void fcoei_process_unsol_els_req(fcoe_frame_t *frm);
+static void fcoei_process_sol_els_rsp(fcoe_frame_t *frm);
+static void fcoei_process_unsol_abts_req(fcoe_frame_t *frame);
+static void fcoei_process_sol_abts_acc(fcoe_frame_t *frame);
+static void fcoei_process_sol_abts_rjt(fcoe_frame_t *frame);
+static void fcoei_process_sol_ct_rsp(fcoe_frame_t *frame);
+static void fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frame);
+static void fcoei_process_sol_fcp_resp(fcoe_frame_t *frm);
+
+static void fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size);
+static void fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch,
+    int size);
+
+/*
+ * fcoei_rx_frame
+ *	Unsolicited frame is received
+ *
+ * Input:
+ *	frame = unsolicited frame that is received
+ *
+ * Return:
+ *	N/A
+ *
+ * Comment:
+ *	N/A
+ */
+static void
+fcoei_rx_frame(fcoe_frame_t *frm)
+{
+	if (!(FRM2SS(frm)->ss_flags & SS_FLAG_LV_BOUND)) {
+		/*
+		 * Release the frame and netb
+		 */
+		FCOEI_LOG(__FUNCTION__, "not bound now");
+		frm->frm_eport->eport_free_netb(frm->frm_netb);
+		frm->frm_eport->eport_release_frame(frm);
+		return;
+	}
+
+	FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_UNSOL_FRAME;
+	FRM2IFM(frm)->ifm_ae.ae_obj = frm;
+
+	mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
+	list_insert_tail(&FRM2SS(frm)->ss_event_list, &FRM2IFM(frm)->ifm_ae);
+	if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
+		cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
+	}
+	mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
+}
+
+/*
+ * fcoei_release_sol_frame
+ *	Release the solicited frame that has just been sent out
+ *
+ * Input:
+ *	frame = solicited frame that has been sent out
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	After FCOE sends solicited frames out, it will call this to notify
+ *	FCOEI of the completion.
+ */
+static void
+fcoei_release_sol_frame(fcoe_frame_t *frm)
+{
+	/*
+	 * For request-type frames, it's safe to be handled out of
+	 * watchdog, because it needn't update anything
+	 */
+	switch (FRM2IFM(frm)->ifm_rctl) {
+	case R_CTL_SOLICITED_DATA:
+	case R_CTL_COMMAND:
+	case R_CTL_ELS_REQ:
+	case R_CTL_UNSOL_CONTROL:
+	case R_CTL_LS_ABTS:
+		FRM2SS(frm)->ss_eport->eport_release_frame(frm);
+		break;
+
+	default:
+		FRM2IFM(frm)->ifm_ae.ae_type = AE_EVENT_SOL_FRAME;
+		FRM2IFM(frm)->ifm_ae.ae_obj = frm;
+
+		mutex_enter(&FRM2SS(frm)->ss_watchdog_mutex);
+		list_insert_tail(&FRM2SS(frm)->ss_event_list,
+		    &FRM2IFM(frm)->ifm_ae);
+		if (FRM2SS(frm)->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
+			cv_signal(&FRM2SS(frm)->ss_watchdog_cv);
+		}
+		mutex_exit(&FRM2SS(frm)->ss_watchdog_mutex);
+		break;
+	}
+}
+
+/*
+ * fcoei_process_unsol_xfer_rdy
+ *	XFER_RDY is received
+ *
+ * Input:
+ *	frm = XFER_RDY frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_process_unsol_xfer_rdy(fcoe_frame_t *frm)
+{
+	uint16_t		 sol_oxid;
+	fcoei_exchange_t	*xch;
+	int			 rcv_buf_size;
+	int			 offset;
+	int			 left_size;
+	int			 data_size;
+	int			 frm_num;
+	int			 idx;
+	fcoe_frame_t		*nfrm;
+
+	sol_oxid = FRM_OXID(frm);
+	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
+	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
+		return;
+	}
+
+	/*
+	 * rcv_buf_size is the total size of data that should be transferred
+	 * in this sequence.
+	 * offset is based on the exchange not the sequence.
+	 */
+	xch->xch_rxid = FRM_RXID(frm);
+	rcv_buf_size = FCOE_B2V_4(frm->frm_payload + 4);
+	offset = FCOE_B2V_4(frm->frm_payload);
+	ASSERT(xch->xch_resid >= rcv_buf_size);
+
+	/*
+	 * Local variables initialization
+	 */
+	left_size = rcv_buf_size;
+	data_size = FRM2SS(frm)->ss_fcp_data_payload_size;
+	frm_num = (rcv_buf_size + data_size - 1) / data_size;
+
+	for (idx = 0; idx < frm_num - 1; idx++) {
+		/*
+		 * The first (frm_num -1) frames are always full
+		 */
+		nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
+		    FRM2SS(frm)->ss_eport, data_size + FCFH_SIZE, NULL);
+		if (nfrm == NULL) {
+			FCOEI_LOG(__FUNCTION__, "can't alloc frame");
+			return;
+		}
+
+		/*
+		 * Copy the data payload that will  be transferred
+		 */
+		bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
+		    nfrm->frm_payload, nfrm->frm_payload_size);
+
+		FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
+		FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
+		FFM_F_CTL(0x010008, nfrm);
+		FFM_OXID(xch->xch_oxid, nfrm);
+		FFM_RXID(xch->xch_rxid, nfrm);
+		FFM_S_ID(FRM_D_ID(frm), nfrm);
+		FFM_D_ID(FRM_S_ID(frm), nfrm);
+		FFM_SEQ_CNT(idx, nfrm);
+		FFM_PARAM(offset, nfrm);
+		fcoei_init_ifm(nfrm, xch);
+
+		/*
+		 * Submit the frame
+		 */
+		xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
+
+		/*
+		 * Update offset and left_size
+		 */
+		offset += data_size;
+		left_size -= data_size;
+	}
+
+	/*
+	 * Send the last data frame of this sequence
+	 */
+	data_size = left_size;
+	nfrm = xch->xch_ss->ss_eport->eport_alloc_frame(
+	    xch->xch_ss->ss_eport, data_size + FCFH_SIZE, NULL);
+	if (nfrm != NULL) {
+		fcoei_init_ifm(nfrm, xch);
+	} else {
+		ASSERT(0);
+		return;
+	}
+
+	/*
+	 * Copy the data payload that will be transferred
+	 */
+	bcopy(offset + (uint8_t *)xch->xch_fpkt->pkt_data,
+	    nfrm->frm_payload, nfrm->frm_payload_size);
+
+	/*
+	 * Set ifm_rctl for fcoei_handle_sol_frame_done
+	 */
+	FRM2IFM(nfrm)->ifm_rctl = R_CTL_SOLICITED_DATA;
+
+	/*
+	 * FFM
+	 */
+	FFM_R_CTL(R_CTL_SOLICITED_DATA, nfrm);
+	FFM_TYPE(FC_TYPE_SCSI_FCP, nfrm);
+	FFM_F_CTL(0x090008, nfrm);
+	FFM_OXID(xch->xch_oxid, nfrm);
+	FFM_RXID(xch->xch_rxid, nfrm);
+	FFM_S_ID(FRM_D_ID(frm), nfrm);
+	FFM_D_ID(FRM_S_ID(frm), nfrm);
+	FFM_SEQ_CNT(idx, nfrm);
+	FFM_PARAM(offset, nfrm);
+
+	/*
+	 * Submit the frame
+	 */
+	xch->xch_ss->ss_eport->eport_tx_frame(nfrm);
+
+	/*
+	 * Sequence is a transaction, so we need only update
+	 * xch_remained_bytes in the end.
+	 */
+	xch->xch_resid -= rcv_buf_size;
+}
+
+/*
+ * fcoei_process_unsol_els_req
+ *	els req frame is received
+ *
+ * Input:
+ *	frm = ELS request frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	We will not create exchange data structure at this time,
+ *	and we should create unsolicited buffer, which will only
+ *	contain the exchange's request payload.
+ */
+static void
+fcoei_process_unsol_els_req(fcoe_frame_t *frm)
+{
+	fc_unsol_buf_t		*ub;
+	fc_rscn_t		*rscn;
+	uint32_t		 offset;
+	fcoei_exchange_t	*xch_tmp;
+
+	/*
+	 * Get the unsol rxid first
+	 */
+	FCOEI_SET_UNSOL_FRM_RXID(frm, xch_tmp);
+
+	/*
+	 * Do proper ub initialization
+	 */
+	ub = (fc_unsol_buf_t *)kmem_zalloc(sizeof (fc_unsol_buf_t), KM_SLEEP);
+	ub->ub_class = FC_TRAN_CLASS3;
+	ub->ub_bufsize = frm->frm_payload_size;
+	ub->ub_buffer = kmem_alloc(frm->frm_payload_size, KM_SLEEP);
+	ub->ub_port_handle = FRM2SS(frm);
+	ub->ub_token = (uint64_t)(long)ub;
+
+	/*
+	 * header conversion
+	 * Caution: ub_buffer is big endian, but ub_frame should be host-format
+	 * RSCN is one exception.
+	 */
+	FCOEI_FRM2FHDR(frm, &ub->ub_frame);
+
+	/*
+	 * If it's FLOGI, and our FLOGI failed last time,
+	 * then we post online event
+	 */
+	if ((FRM2SS(frm)->ss_flags & SS_FLAG_FLOGI_FAILED) &&
+	    (frm->frm_payload[0] == LA_ELS_FLOGI)) {
+		frm->frm_eport->eport_flags |=
+		    EPORT_FLAG_IS_DIRECT_P2P;
+		FRM2SS(frm)->ss_bind_info.port_statec_cb(FRM2SS(frm)->ss_port,
+		    FC_STATE_ONLINE);
+	}
+
+	switch (frm->frm_payload[0]) {
+	case LA_ELS_RSCN:
+		/*
+		 * Only RSCN need byte swapping
+		 */
+		rscn = (fc_rscn_t *)(void *)ub->ub_buffer;
+		rscn->rscn_code = frm->frm_payload[0];
+		rscn->rscn_len = frm->frm_payload[1];
+		rscn->rscn_payload_len =
+		    FCOE_B2V_2(frm->frm_payload + 2);
+
+		offset = 4;
+		for (int i = 0; i < rscn->rscn_payload_len - 4; i += 4) {
+			*(uint32_t *)((intptr_t)(uint8_t *)ub->ub_buffer +
+			    offset) = FCOE_B2V_4(frm->frm_payload + offset);
+			offset += 4;
+		}
+		break;
+
+	default:
+		bcopy(frm->frm_payload, ub->ub_buffer, frm->frm_payload_size);
+		break;
+	}
+
+	/*
+	 * Pass this unsol ELS up to Leadville
+	 */
+	FRM2SS(frm)->ss_bind_info.port_unsol_cb(FRM2SS(frm)->ss_port, ub, 0);
+}
+
+/*
+ * fcoei_search_abort_xch
+ *	Find the exchange that should be aborted
+ *
+ * Input:
+ *	key = oxid of the exchange
+ *	val = the exchange
+ *	arg = the soft state
+ *
+ * Returns:
+ *	MH_WALK_TERMINATE = found it, terminate the walk
+ *	MH_WALK_CONTINUE = not found, continue the walk
+ *
+ * Comments:
+ *	N/A
+ */
+static uint32_t
+fcoei_search_abort_xch(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
+{
+	fcoei_walk_arg_t	*wa = (fcoei_walk_arg_t *)arg;
+	fcoei_exchange_t	*xch = (fcoei_exchange_t *)val;
+
+	if (xch->xch_oxid == wa->wa_oxid) {
+		wa->wa_xch = xch;
+		ASSERT(xch->xch_oxid == CMHK(key));
+		return (MH_WALK_TERMINATE);
+	}
+
+	return (MH_WALK_CONTINUE);
+}
+
+/*
+ * fcoei_process_unsol_abts_req
+ *	ABTS request is received
+ *
+ * Input:
+ *	frm = ABTS request frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	The remote side wants to abort one unsolicited exchange.
+ */
+static void
+fcoei_process_unsol_abts_req(fcoe_frame_t *frm)
+{
+	fcoei_exchange_t	*xch = NULL;
+	fcoe_frame_t		*nfrm;
+	int			 payload_size;
+	fcoei_walk_arg_t	 walk_arg;
+
+	/*
+	 * According to spec, the responder could want to ABTS xch too
+	 */
+	if (FRM_SENDER_IS_XCH_RESPONDER(frm)) {
+		uint16_t sol_oxid = FRM_OXID(frm);
+		(void) mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
+		    FMHK(sol_oxid), (mod_hash_val_t *)&xch);
+	} else {
+		/*
+		 * it's a unsolicited exchange, and we need find it out from
+		 * unsolicited hash table. But at this time, RXID in frame could
+		 * still be 0xFFFF in most cases, so we need do exaustive search
+		 */
+		walk_arg.wa_xch = NULL;
+		walk_arg.wa_oxid = FRM_OXID(frm);
+		mod_hash_walk(FRM2SS(frm)->ss_unsol_rxid_hash,
+		    fcoei_search_abort_xch, &walk_arg);
+		xch = walk_arg.wa_xch;
+	}
+
+	if (xch == NULL) {
+		payload_size = 4;
+		nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
+		    FRM2SS(frm)->ss_eport,
+		    payload_size + FCFH_SIZE, NULL);
+		if (nfrm == NULL) {
+			FCOEI_LOG(__FUNCTION__, "can't alloc frame");
+			return;
+		}
+
+		bzero(nfrm->frm_payload, nfrm->frm_payload_size);
+		nfrm->frm_payload[1] = 0x05;
+		nfrm->frm_payload[3] = 0xAA;
+		FFM_R_CTL(R_CTL_LS_BA_RJT, nfrm);
+		fcoei_init_ifm(nfrm, xch);
+	} else {
+		/*
+		 * We should complete the exchange with frm as NULL,
+		 * and we don't care its success or failure
+		 */
+		fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE, FC_REASON_ABTX);
+
+		/*
+		 * Construct ABTS ACC frame
+		 */
+		payload_size = 12;
+		nfrm = FRM2SS(frm)->ss_eport->eport_alloc_frame(
+		    FRM2SS(frm)->ss_eport, payload_size + FCFH_SIZE, NULL);
+		if (nfrm == NULL) {
+			FCOEI_LOG(__FUNCTION__, "can't alloc frame");
+			return;
+		}
+
+		bzero(nfrm->frm_payload, nfrm->frm_payload_size);
+		nfrm->frm_payload[4] = 0xFF & (xch->xch_oxid >> 8);
+		nfrm->frm_payload[5] = 0xFF & (xch->xch_oxid);
+		nfrm->frm_payload[6] = 0xFF & (xch->xch_rxid >> 8);
+		nfrm->frm_payload[7] = 0xFF & (xch->xch_rxid);
+		nfrm->frm_payload[10] = 0xFF;
+		nfrm->frm_payload[11] = 0xFF;
+
+		FFM_R_CTL(R_CTL_LS_BA_ACC, nfrm);
+		fcoei_init_ifm(nfrm, xch);
+	}
+
+	FFM_D_ID(FRM_S_ID(frm), nfrm);
+	FFM_S_ID(FRM_D_ID(frm), nfrm);
+	FFM_TYPE(FRM_TYPE(frm), nfrm);
+	FFM_F_CTL(FRM_F_CTL(frm), nfrm);
+	FFM_OXID(FRM_OXID(frm), nfrm);
+	FFM_RXID(FRM_RXID(frm), nfrm);
+	FRM2SS(frm)->ss_eport->eport_tx_frame(nfrm);
+}
+
+/*
+ * fcoei_process_sol_fcp_resp
+ *	FCP response is received
+ *
+ * Input:
+ *	frm = FCP response frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_process_sol_fcp_resp(fcoe_frame_t *frm)
+{
+	uint16_t		 sol_oxid;
+	uint32_t		 actual_size;
+	fcoei_exchange_t	*xch  = NULL;
+	fc_packet_t		*fpkt = NULL;
+	mod_hash_val_t		 val;
+	uint32_t		 i_fcp_status;
+
+	/*
+	 * Firstly, we search the related exchange
+	 */
+	sol_oxid = FRM_OXID(frm);
+	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
+	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
+		PRT_FRM_HDR(__FUNCTION__, frm);
+		FCOEI_LOG(__FUNCTION__, "can't find the corresponding xch: "
+		    "oxid/%x %lu - %lu", sol_oxid,
+		    CURRENT_CLOCK, frm->frm_clock);
+		return;
+	} else {
+		fpkt = xch->xch_fpkt;
+	}
+
+	/*
+	 * Decide the actual response length
+	 */
+	actual_size = fpkt->pkt_rsplen;
+	if (actual_size > frm->frm_payload_size) {
+		actual_size = frm->frm_payload_size;
+	}
+
+	/*
+	 * Update the exchange and hash table
+	 */
+	mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash,
+	    FMHK(xch->xch_oxid), &val);
+	ASSERT((fcoei_exchange_t *)val == xch);
+	xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
+
+	/*
+	 * Upate fpkt related elements
+	 */
+	FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
+
+	/*
+	 * we should set pkt_reason and pkt_state carefully
+	 */
+	fpkt->pkt_state = FC_PKT_SUCCESS;
+	fpkt->pkt_reason = 0;
+
+	/*
+	 * First we zero the first 12 byte of dest
+	 */
+	bzero(xch->xch_fpkt->pkt_resp, 12);
+	i_fcp_status = BE_IN32(frm->frm_payload + 8);
+	if (i_fcp_status != 0) {
+		fcoei_fill_fcp_resp(frm->frm_payload,
+		    (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
+	}
+
+	/*
+	 * Update pkt_resp_resid
+	 */
+	fpkt->pkt_data_resid = xch->xch_resid;
+	if ((xch->xch_resid != 0) && ((xch->xch_resid % 0x200) == 0) &&
+	    ((xch->xch_fpkt->pkt_datalen % 0x200) == 0) &&
+	    (i_fcp_status == 0)) {
+		FCOEI_LOG(__FUNCTION__, "frame lost no pause ? %x/%x",
+		    xch->xch_resid, xch->xch_fpkt->pkt_datalen);
+		fpkt->pkt_state = FC_PKT_LOCAL_RJT;
+		fpkt->pkt_reason = FC_REASON_UNDERRUN;
+	}
+
+	/*
+	 * Notify LV it's over
+	 */
+	if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
+		FCOEI_LOG(__FUNCTION__, "BEFORE WAKEUP: %p-%p", fpkt, xch);
+		sema_v(&xch->xch_sema);
+		FCOEI_LOG(__FUNCTION__, "AFTERE WAKEUP: %p-%p", fpkt, xch);
+	} else {
+		xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
+	}
+}
+
+/*
+ * fcoei_process_sol_els_rsp
+ *	ELS response is received
+ *
+ * Input:
+ *	frm = ELS response frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_process_sol_els_rsp(fcoe_frame_t *frm)
+{
+	uint16_t		 sol_oxid    = 0;
+	uint32_t		 actual_size = 0;
+	fcoei_exchange_t	*xch;
+	fc_packet_t		*fpkt;
+
+	/*
+	 * Look for the related exchange
+	 */
+	xch = NULL;
+	fpkt = NULL;
+	sol_oxid = FRM_OXID(frm);
+	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
+	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
+		PRT_FRM_HDR(__FUNCTION__, frm);
+		FCOEI_LOG(__FUNCTION__, "can't find the "
+		    "corresponding xch: oxid/%x", sol_oxid);
+		return;
+	}
+
+	xch->xch_rxid = FRM_RXID(frm);
+	fpkt = xch->xch_fpkt;
+
+	/*
+	 * Decide the actual response length
+	 */
+	actual_size = frm->frm_payload_size;
+	if (actual_size > fpkt->pkt_rsplen) {
+		FCOEI_LOG(__FUNCTION__, "pkt_rsplen is smaller"
+		    "0x(%x - %x)", actual_size, fpkt->pkt_rsplen);
+		actual_size = fpkt->pkt_rsplen;
+	}
+
+	/*
+	 * Upate fpkt related elements
+	 */
+	FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
+	fcoei_fill_els_fpkt_resp(frm, xch, actual_size);
+
+	/*
+	 * we should set pkt_reason and pkt_state carefully now
+	 * Need to analyze pkt_reason according to the response.
+	 * Leave it untouched now.
+	 */
+	if (((ls_code_t *)(void *)xch->xch_fpkt->pkt_resp)->ls_code ==
+	    LA_ELS_RJT) {
+		fcoei_complete_xch(xch, NULL, FC_PKT_FABRIC_RJT,
+		    FC_REASON_INVALID_PARAM);
+	} else {
+		fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
+	}
+}
+
+/*
+ * fcoei_process_sol_ct_rsp
+ *	CT response is received
+ *
+ * Input:
+ *	frm = CT response frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_process_sol_ct_rsp(fcoe_frame_t *frm)
+{
+	uint16_t		 sol_oxid    = 0;
+	uint32_t		 actual_size = 0;
+	fcoei_exchange_t	*xch;
+	fc_packet_t		*fpkt;
+
+	/*
+	 * Look for the related exchange
+	 */
+	xch = NULL;
+	fpkt = NULL;
+	sol_oxid = FRM_OXID(frm);
+	if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
+	    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
+		FCOEI_LOG(__FUNCTION__, "can't find the "
+		    "corresponding xch: oxid/%x", sol_oxid);
+		return;
+	}
+
+	xch->xch_rxid = FRM_RXID(frm);
+	fpkt = xch->xch_fpkt;
+
+	/*
+	 * Decide the actual response length
+	 */
+	actual_size = fpkt->pkt_rsplen;
+	if (actual_size > frm->frm_payload_size) {
+		FCOEI_LOG(__FUNCTION__, "payload is smaller"
+		    "0x(%x - %x)", actual_size, frm->frm_payload_size);
+		actual_size = frm->frm_payload_size;
+	}
+
+	/*
+	 * Update fpkt related elements
+	 * Caution: we needn't do byte swapping for CT response
+	 */
+	FCOEI_FRM2FHDR(frm, &fpkt->pkt_resp_fhdr);
+	bcopy(FPLD, (uint8_t *)xch->xch_fpkt->pkt_resp, actual_size);
+
+	/*
+	 * Complete it with frm as NULL
+	 */
+	fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
+}
+
+/*
+ * fcoei_process_sol_abts_acc
+ *	ABTS accpet is received
+ *
+ * Input:
+ *	frm = ABTS accept frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	We will always finish the abortion of solicited exchanges,
+ *	so we will not depend on the response from the remote side.
+ *	We just log one message.
+ */
+static void
+fcoei_process_sol_abts_acc(fcoe_frame_t *frm)
+{
+	FCOEI_LOG(__FUNCTION__, "the remote side has agreed to "
+	    "abort the exchange: oxid-%x, rxid-%x",
+	    FCOE_B2V_2(frm->frm_payload + 4),
+	    FCOE_B2V_2(frm->frm_payload + 6));
+}
+
+/*
+ * fcoei_process_sol_abts_rjt
+ *	ABTS reject is received
+ *
+ * Input:
+ *	frm = ABTS reject frame
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	We will alwayas finish the abortion of solicited exchanges,
+ *	so we will not depend on the response from the remote side.
+ *	We just log one message.
+ */
+static void
+fcoei_process_sol_abts_rjt(fcoe_frame_t *frm)
+{
+	FCOEI_LOG(__FUNCTION__, "the remote side rejected "
+	    "our request to abort one exchange.: %p", frm);
+}
+
+/*
+ * fcoei_fill_els_fpkt_resp
+ *	Fill fpkt ELS response in host format according frm payload
+ *
+ * Input:
+ *	src = frm payload in link format
+ *	dest = fpkt ELS response in host format
+ *	size = Maximum conversion size
+ *	els_op = ELS opcode
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	fpkt->pkt_resp must be mapped to one data structure, and it's
+ *	different from the content in the raw frame
+ */
+static void
+fcoei_fill_els_fpkt_resp(fcoe_frame_t *frm, fcoei_exchange_t *xch, int size)
+{
+	uint8_t			*src	   = frm->frm_payload;
+	uint8_t			*dest	   = (uint8_t *)xch->xch_fpkt->pkt_resp;
+	ls_code_t		*els_code  = (ls_code_t *)(void *)dest;
+	la_els_logi_t		*els_logi  = (la_els_logi_t *)(void *)dest;
+	la_els_adisc_t		*els_adisc = (la_els_adisc_t *)(void *)dest;
+	la_els_rls_acc_t	*els_rls;
+	la_els_rnid_acc_t	*els_rnid;
+	struct fcp_prli_acc	*prli_acc;
+	int			 offset;
+
+	els_code->ls_code = FCOE_B2V_1(src);
+	if (els_code->ls_code == LA_ELS_RJT) {
+		FCOEI_LOG(__FUNCTION__, "size :%d", size);
+		return;
+	}
+
+	switch (((ls_code_t *)(void *)xch->xch_fpkt->pkt_cmd)->ls_code) {
+	case LA_ELS_FLOGI:
+		bcopy((char *)frm->frm_hdr - 22,
+		    frm->frm_eport->eport_efh_dst, ETHERADDRL);
+		if (frm->frm_payload[8] & 0x10) {
+			/*
+			 * We are in fabric p2p mode
+			 */
+			uint8_t src_addr[ETHERADDRL];
+			frm->frm_eport->eport_flags &=
+			    ~EPORT_FLAG_IS_DIRECT_P2P;
+			FCOE_SET_DEFAULT_OUI(src_addr);
+			bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3);
+			frm->frm_eport->eport_set_mac_address(
+			    frm->frm_eport, src_addr, 1);
+		} else {
+			/*
+			 * We are in direct p2p mode
+			 */
+			frm->frm_eport->eport_flags |=
+			    EPORT_FLAG_IS_DIRECT_P2P;
+		}
+
+		if (!(FRM2SS(frm)->ss_eport->eport_flags &
+		    EPORT_FLAG_IS_DIRECT_P2P)) {
+			FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
+		}
+
+		/* FALLTHROUGH */
+
+	case LA_ELS_PLOGI:
+		if (FRM2SS(frm)->ss_eport->eport_flags &
+		    EPORT_FLAG_IS_DIRECT_P2P) {
+			FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_D_ID(frm);
+			FRM2SS(frm)->ss_p2p_info.d_id = FRM_S_ID(frm);
+		}
+
+		offset = offsetof(la_els_logi_t, common_service);
+		els_logi->common_service.fcph_version = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->common_service.btob_credit = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->common_service.cmn_features = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->common_service.rx_bufsize = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->common_service.conc_sequences = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->common_service.relative_offset = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->common_service.e_d_tov = FCOE_B2V_4(src +
+		    offset);
+
+		/*
+		 * port/node WWN
+		 */
+		offset = offsetof(la_els_logi_t, nport_ww_name);
+		bcopy(src + offset, &els_logi->nport_ww_name, 8);
+		offset = offsetof(la_els_logi_t, node_ww_name);
+		bcopy(src + offset, &els_logi->node_ww_name, 8);
+
+		/*
+		 * class_3
+		 */
+		offset = offsetof(la_els_logi_t, class_3);
+		els_logi->class_3.class_opt = FCOE_B2V_2(src + offset);
+		offset += 2;
+		els_logi->class_3.initiator_ctl = FCOE_B2V_2(src + offset);
+		offset += 2;
+		els_logi->class_3.recipient_ctl = FCOE_B2V_2(src + offset);
+		offset += 2;
+		els_logi->class_3.rcv_size = FCOE_B2V_2(src + offset);
+		offset += 2;
+		els_logi->class_3.conc_sequences = FCOE_B2V_2(src + offset);
+		offset += 2;
+		els_logi->class_3.n_port_e_to_e_credit = FCOE_B2V_2(src +
+		    offset);
+		offset += 2;
+		els_logi->class_3.open_seq_per_xchng = FCOE_B2V_2(src + offset);
+
+		break;
+
+	case LA_ELS_PRLI:
+		/*
+		 * PRLI service parameter response page
+		 *
+		 * fcp_prli_acc doesn't include ls_code, don't use offsetof
+		 */
+		offset = 4;
+		prli_acc = (struct fcp_prli_acc *)(void *)(dest + offset);
+		prli_acc->type = FCOE_B2V_1(src + offset);
+		/*
+		 * Type code extension
+		 */
+		offset += 1;
+		/*
+		 * PRLI response flags
+		 */
+		offset += 1;
+		prli_acc->orig_process_assoc_valid =
+		    (FCOE_B2V_2(src + offset) & BIT_15) ? 1 : 0;
+		prli_acc->resp_process_assoc_valid =
+		    (FCOE_B2V_2(src + offset) & BIT_14) ? 1 : 0;
+		prli_acc->image_pair_established =
+		    (FCOE_B2V_2(src + offset) & BIT_13) ? 1 : 0;
+		prli_acc->accept_response_code =
+		    FCOE_B2V_2(src + offset) & 0x0F00;
+		/*
+		 * process associator
+		 */
+		offset += 2;
+		prli_acc->orig_process_associator = FCOE_B2V_4(src + offset);
+		offset += 4;
+		prli_acc->resp_process_associator = FCOE_B2V_4(src + offset);
+		/*
+		 * FC-4 type
+		 */
+		offset += 4;
+		prli_acc->initiator_fn =
+		    (FCOE_B2V_4(src + offset) & BIT_5) ? 1 : 0;
+		prli_acc->target_fn =
+		    (FCOE_B2V_4(src + offset) & BIT_4) ? 1 : 0;
+		prli_acc->cmd_data_mixed =
+		    (FCOE_B2V_4(src + offset) & BIT_3) ? 1 : 0;
+		prli_acc->data_resp_mixed =
+		    (FCOE_B2V_4(src + offset) & BIT_2) ? 1 : 0;
+		prli_acc->read_xfer_rdy_disabled =
+		    (FCOE_B2V_4(src + offset) & BIT_1) ? 1 : 0;
+		prli_acc->write_xfer_rdy_disabled =
+		    (FCOE_B2V_4(src + offset) & BIT_0) ? 1 : 0;
+
+		break;
+
+	case LA_ELS_LOGO:
+		/*
+		 * could only be LS_ACC, no additional information
+		 */
+		els_code->ls_code = FCOE_B2V_1(src);
+		break;
+
+	case LA_ELS_SCR:
+		/*
+		 * LS_ACC/LS_RJT, no additional information
+		 */
+		els_code->ls_code = FCOE_B2V_1(src);
+		break;
+
+	case LA_ELS_ADISC:
+		offset = 5;
+		els_adisc->hard_addr.hard_addr = FCOE_B2V_3(src + offset);
+		offset = offsetof(la_els_adisc_t, port_wwn);
+		bcopy(src + offset, &els_adisc->port_wwn, 8);
+		offset = offsetof(la_els_adisc_t, node_wwn);
+		bcopy(src + offset, &els_adisc->node_wwn, 8);
+		offset += 9;
+		els_adisc->nport_id.port_id = FCOE_B2V_3(src + offset);
+		break;
+	case LA_ELS_RLS:
+		els_rls = (la_els_rls_acc_t *)(void *)dest;
+		els_rls->ls_code.ls_code = FCOE_B2V_1(src);
+		offset = 4;
+		els_rls->rls_link_params.rls_link_fail =
+		    FCOE_B2V_4(src + offset);
+		offset = 8;
+		els_rls->rls_link_params.rls_sync_loss =
+		    FCOE_B2V_4(src + offset);
+		offset = 12;
+		els_rls->rls_link_params.rls_sig_loss =
+		    FCOE_B2V_4(src + offset);
+		offset = 16;
+		els_rls->rls_link_params.rls_prim_seq_err =
+		    FCOE_B2V_4(src + offset);
+		offset = 20;
+		els_rls->rls_link_params.rls_invalid_word =
+		    FCOE_B2V_4(src + offset);
+		offset = 24;
+		els_rls->rls_link_params.rls_invalid_crc =
+		    FCOE_B2V_4(src + offset);
+		break;
+	case LA_ELS_RNID:
+		els_rnid = (la_els_rnid_acc_t *)(void *)dest;
+		els_rnid->ls_code.ls_code = FCOE_B2V_1(src);
+		offset = 4;
+		bcopy(src + offset, &els_rnid->hdr.data_format, 1);
+		offset = 5;
+		bcopy(src + offset, &els_rnid->hdr.cmn_len, 1);
+		offset = 7;
+		bcopy(src + offset, &els_rnid->hdr.specific_len, 1);
+		offset = 8;
+		bcopy(src + offset, els_rnid->data, FCIO_RNID_MAX_DATA_LEN);
+		break;
+	default:
+		FCOEI_LOG(__FUNCTION__, "unsupported R_CTL");
+		break;
+	}
+}
+
+/*
+ * fcoei_fill_fcp_resp
+ *	Fill fpkt FCP response in host format according to frm payload
+ *
+ * Input:
+ *	src - frm payload in link format
+ *	dest - fpkt FCP response in host format
+ *	size - Maximum conversion size
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	This is called only for SCSI response with non good status
+ */
+static void
+fcoei_fill_fcp_resp(uint8_t *src, uint8_t *dest, int size)
+{
+	fcp_rsp_t	*fcp_rsp_iu = (fcp_rsp_t *)(void *)dest;
+	int		 offset;
+
+	/*
+	 * set fcp_status
+	 */
+	offset = offsetof(fcp_rsp_t, fcp_u);
+	offset += 2;
+	fcp_rsp_iu->fcp_u.fcp_status.resid_under =
+	    (FCOE_B2V_1(src + offset) & BIT_3) ? 1 : 0;
+	fcp_rsp_iu->fcp_u.fcp_status.resid_over =
+	    (FCOE_B2V_1(src + offset) & BIT_2) ? 1 : 0;
+	fcp_rsp_iu->fcp_u.fcp_status.sense_len_set =
+	    (FCOE_B2V_1(src + offset) & BIT_1) ? 1 : 0;
+	fcp_rsp_iu->fcp_u.fcp_status.rsp_len_set =
+	    (FCOE_B2V_1(src + offset) & BIT_0) ? 1 : 0;
+	offset += 1;
+	fcp_rsp_iu->fcp_u.fcp_status.scsi_status = FCOE_B2V_1(src + offset);
+	/*
+	 * fcp_resid/fcp_sense_len/fcp_response_len
+	 */
+	offset = offsetof(fcp_rsp_t, fcp_resid);
+	fcp_rsp_iu->fcp_resid = FCOE_B2V_4(src + offset);
+	offset = offsetof(fcp_rsp_t, fcp_sense_len);
+	fcp_rsp_iu->fcp_sense_len = FCOE_B2V_4(src + offset);
+	offset = offsetof(fcp_rsp_t, fcp_response_len);
+	fcp_rsp_iu->fcp_response_len = FCOE_B2V_4(src + offset);
+	/*
+	 * sense or response
+	 */
+	offset += 4;
+	if (fcp_rsp_iu->fcp_sense_len) {
+		if ((offset + fcp_rsp_iu->fcp_sense_len) > size) {
+			FCOEI_LOG(__FUNCTION__, "buffer too small - sens");
+			return;
+		}
+		bcopy(src + offset, dest + offset, fcp_rsp_iu->fcp_sense_len);
+		offset += fcp_rsp_iu->fcp_sense_len;
+	}
+
+	if (fcp_rsp_iu->fcp_response_len) {
+		if ((offset + fcp_rsp_iu->fcp_response_len) > size) {
+			FCOEI_LOG(__FUNCTION__, "buffer too small - resp");
+			return;
+		}
+		bcopy(src + offset, dest + offset,
+		    fcp_rsp_iu->fcp_response_len);
+	}
+}
+
+void
+fcoei_init_ect_vectors(fcoe_client_t *ect)
+{
+	ect->ect_rx_frame	   = fcoei_rx_frame;
+	ect->ect_port_event	   = fcoei_port_event;
+	ect->ect_release_sol_frame = fcoei_release_sol_frame;
+}
+
+/*
+ * fcoei_process_unsol_frame
+ *	Unsolicited frame is received
+ *
+ * Input:
+ *	frame = unsolicited frame that is received
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	watchdog will call this to process unsolicited frames that we
+ *	just received fcoei_process_xx is used to handle different
+ *	unsolicited frames
+ */
+void
+fcoei_process_unsol_frame(fcoe_frame_t *frm)
+{
+	fcoei_exchange_t	*xch;
+	uint16_t		 sol_oxid;
+
+	switch (FRM_R_CTL(frm)) {
+	case R_CTL_SOLICITED_DATA:
+		/*
+		 * READ data phase frame
+		 * Find the associated exchange
+		 */
+		sol_oxid = FRM_OXID(frm);
+		if (mod_hash_find(FRM2SS(frm)->ss_sol_oxid_hash,
+		    FMHK(sol_oxid), (mod_hash_val_t *)&xch) != 0) {
+			PRT_FRM_HDR(__FUNCTION__, frm);
+			FCOEI_LOG(__FUNCTION__, "associated xch not found: "
+			    "oxid/%x %lu - %lu", sol_oxid,
+			    CURRENT_CLOCK, frm->frm_clock);
+			break;
+		}
+
+		/*
+		 * Copy data into fpkt data buffer, and update the counter
+		 */
+		bcopy(frm->frm_payload, (uint8_t *)xch->xch_fpkt->pkt_data +
+		    FRM_PARAM(frm), frm->frm_payload_size);
+		xch->xch_resid -= frm->frm_payload_size;
+		xch->xch_rxid = FRM_RXID(frm);
+		break;
+
+	case R_CTL_XFER_RDY:
+		fcoei_process_unsol_xfer_rdy(frm);
+		break;
+
+	case R_CTL_STATUS:
+		fcoei_process_sol_fcp_resp(frm);
+		break;
+
+	case R_CTL_ELS_REQ:
+		fcoei_process_unsol_els_req(frm);
+		break;
+
+	case R_CTL_LS_ABTS:
+		fcoei_process_unsol_abts_req(frm);
+		break;
+
+	case R_CTL_ELS_RSP:
+		fcoei_process_sol_els_rsp(frm);
+		break;
+
+	case R_CTL_SOLICITED_CONTROL:
+		fcoei_process_sol_ct_rsp(frm);
+		break;
+
+	case R_CTL_LS_BA_ACC:
+		fcoei_process_sol_abts_acc(frm);
+		break;
+
+	case R_CTL_LS_BA_RJT:
+		fcoei_process_sol_abts_rjt(frm);
+		break;
+
+	default:
+		/*
+		 * Unsupported frame
+		 */
+		PRT_FRM_HDR("Unsupported unsol frame: ", frm);
+	}
+
+	/*
+	 * Release the frame and netb
+	 */
+	frm->frm_eport->eport_free_netb(frm->frm_netb);
+	frm->frm_eport->eport_release_frame(frm);
+}
+
+/*
+ * fcoei_handle_sol_frame_done
+ *	solicited frame is just sent out
+ *
+ * Input:
+ *	frame = solicited frame that has been sent out
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	watchdog will call this to handle solicited frames that FCOEI
+ *	has sent out Non-request frame post handling
+ */
+void
+fcoei_handle_sol_frame_done(fcoe_frame_t *frm)
+{
+	/*
+	 * the corresponding xch could be NULL at this time
+	 */
+	fcoei_exchange_t	*xch  = FRM2IFM(frm)->ifm_xch;
+
+	switch (FRM2IFM(frm)->ifm_rctl) {
+	case R_CTL_ELS_RSP:
+		/*
+		 * Complete it with frm as NULL
+		 */
+		fcoei_complete_xch(xch, NULL, FC_PKT_SUCCESS, 0);
+		break;
+
+	case R_CTL_LS_BA_ACC:
+		FCOEI_LOG(__FUNCTION__,  "BA_ACC out: xch-%p, frm-%p",
+		    xch, frm);
+		PRT_FRM_HDR("LS_BA_ACC", frm);
+		break;
+
+	case R_CTL_LS_BA_RJT:
+		FCOEI_LOG(__FUNCTION__,  "BA_RJT out: xch-%p, frm-%p",
+		    xch, frm);
+		PRT_FRM_HDR("LS_BA_RJT", frm);
+		break;
+
+	default:
+		/*
+		 * Unsupported frame
+		 */
+		PRT_FRM_HDR("Unsupported sol frame: ", frm);
+	}
+
+	/*
+	 * We should release only the frame, and we don't care its netb
+	 */
+	FRM2SS(frm)->ss_eport->eport_release_frame(frm);
+}
+
+/*
+ * fcoei_port_event
+ *	link/port state changed
+ *
+ * Input:
+ *	eport = to indicate which port has changed
+ *	event = what change
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	refer fctl.h for ss_link_state value
+ */
+void
+fcoei_port_event(fcoe_port_t *eport, uint32_t event)
+{
+	fcoei_event_t	*ae;
+
+	if (!(EPORT2SS(eport)->ss_flags & SS_FLAG_LV_BOUND)) {
+		FCOEI_LOG(__FUNCTION__, "not bound now");
+		return;
+	}
+
+	mutex_enter(&EPORT2SS(eport)->ss_watchdog_mutex);
+	switch (event) {
+	case FCOE_NOTIFY_EPORT_LINK_DOWN:
+		EPORT2SS(eport)->ss_link_state = FC_STATE_OFFLINE;
+		cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link down",
+		    eport->eport_portwwn[0], eport->eport_portwwn[1],
+		    eport->eport_portwwn[2], eport->eport_portwwn[3],
+		    eport->eport_portwwn[4], eport->eport_portwwn[5],
+		    eport->eport_portwwn[6], eport->eport_portwwn[7]);
+		break;
+
+	case FCOE_NOTIFY_EPORT_LINK_UP:
+		if (eport->eport_mtu >= 2200) {
+			EPORT2SS(eport)->ss_fcp_data_payload_size =
+			    FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE;
+		} else {
+			FCOEI_LOG(__FUNCTION__, "fcoei: MTU is not big enough. "
+			    "we will use 1K frames in FCP data phase.");
+			EPORT2SS(eport)->ss_fcp_data_payload_size =
+			    FCOE_MIN_FCP_DATA_PAYLOAD_SIZE;
+		}
+
+		cmn_err(CE_NOTE, "%02x%02x%02x%02x%02x%02x%02x%02x Link up",
+		    eport->eport_portwwn[0], eport->eport_portwwn[1],
+		    eport->eport_portwwn[2], eport->eport_portwwn[3],
+		    eport->eport_portwwn[4], eport->eport_portwwn[5],
+		    eport->eport_portwwn[6], eport->eport_portwwn[7]);
+		EPORT2SS(eport)->ss_link_state = FC_STATE_ONLINE;
+		break;
+
+	default:
+		FCOEI_LOG(__FUNCTION__, "unsupported event");
+		mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
+
+		return;
+	}
+
+	EPORT2SS(eport)->ss_port_event_counter++;
+	ae = (fcoei_event_t *)kmem_zalloc(sizeof (fcoei_event_t), KM_SLEEP);
+	ae->ae_type = AE_EVENT_PORT;
+	ae->ae_obj = EPORT2SS(eport);
+	ae->ae_specific = EPORT2SS(eport)->ss_link_state;
+	list_insert_tail(&EPORT2SS(eport)->ss_event_list, ae);
+	mutex_exit(&EPORT2SS(eport)->ss_watchdog_mutex);
+}
+
+/*
+ * fcoei_process_event_port
+ *	link/port state changed
+ *
+ * Input:
+ *	ae = link fcoei_event
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	asynchronous events from FCOE
+ */
+void
+fcoei_process_event_port(fcoei_event_t *ae)
+{
+	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)ae->ae_obj;
+
+	if (ss->ss_eport->eport_link_speed == FCOE_PORT_SPEED_1G) {
+		ae->ae_specific |= FC_STATE_1GBIT_SPEED;
+	} else if (ss->ss_eport->eport_link_speed ==
+	    FCOE_PORT_SPEED_10G) {
+		ae->ae_specific |= FC_STATE_10GBIT_SPEED;
+	}
+
+	if (ss->ss_flags & SS_FLAG_LV_BOUND) {
+		ss->ss_bind_info.port_statec_cb(ss->ss_port,
+		    (uint32_t)ae->ae_specific);
+	} else {
+		FCOEI_LOG(__FUNCTION__, "ss %p not bound now", ss);
+	}
+
+	atomic_add_32(&ss->ss_port_event_counter, -1);
+	kmem_free(ae, sizeof (fcoei_event_t));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_lv.c	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,2065 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file defines interfaces between FCOE and LEADVILLE
+ */
+
+/*
+ * Driver kernel header files
+ */
+#include <sys/conf.h>
+#include <sys/ddi.h>
+#include <sys/stat.h>
+#include <sys/pci.h>
+#include <sys/sunddi.h>
+#include <sys/modctl.h>
+#include <sys/file.h>
+#include <sys/cred.h>
+#include <sys/byteorder.h>
+#include <sys/atomic.h>
+#include <sys/scsi/scsi.h>
+#include <sys/mac_client.h>
+#include <sys/modhash.h>
+
+/*
+ * LEADVILLE header files
+ */
+#include <sys/fibre-channel/fc.h>
+#include <sys/fibre-channel/impl/fc_fcaif.h>
+
+/*
+ * COMSTAR head files (BIT_* macro)
+ */
+#include <sys/stmf_defines.h>
+
+/*
+ * FCOE header files
+ */
+#include <sys/fcoe/fcoe_common.h>
+
+/*
+ * Driver's own header files
+ */
+#include <fcoei.h>
+
+/*
+ * forward declaration of static functions
+ */
+static void fcoei_port_enabled(void *arg);
+
+static void fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
+    fc_fca_port_info_t *port_info);
+
+static void fcoei_initiate_ct_req(fcoei_exchange_t *xch);
+static void fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch);
+static void fcoei_initiate_els_req(fcoei_exchange_t *xch);
+static void fcoei_initiate_els_resp(fcoei_exchange_t *xch);
+
+static void fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
+
+static void fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
+static void fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
+
+static void fcoei_logo_peer(void *arg);
+static void fcoei_fpkt_comp(fc_packet_t *fpkt);
+
+static uint32_t
+fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
+
+
+/*
+ * fcoei_bind_port
+ *	Bind LV port instance with fcoei soft state
+ *
+ * Input:
+ *	dip = dev info of fcoei soft state
+ *	port_info = fcoei specific parameters about LV port
+ *	bind_info = LV specific parameters about fcoei soft state
+ *
+ * Returns:
+ *	The pointer to fcoei soft state
+ *
+ * Comments:
+ *	Unpon the completion of this call, the port must be offline.
+ *	fcoei_port_enabled could trigger it to online
+ */
+static void *
+fcoei_bind_port(dev_info_t *dip, fc_fca_port_info_t *port_info,
+    fc_fca_bind_info_t *bind_info)
+{
+	fcoei_soft_state_t	*ss;
+
+	/*
+	 * get state info based on the dip
+	 */
+	ss = (fcoei_soft_state_t *)
+	    ddi_get_soft_state(fcoei_state, ddi_get_instance(dip));
+	if (!ss) {
+		FCOEI_LOG(__FUNCTION__, "ss is NULL");
+		return (NULL);
+	}
+
+	/*
+	 * make sure this port isn't bound
+	 */
+	if (ss->ss_flags & SS_FLAG_LV_BOUND) {
+		port_info->pi_error = FC_ALREADY;
+		FCOEI_LOG(__FUNCTION__, "ss has been bound");
+		return (NULL);
+	}
+
+	if (bind_info->port_num) {
+		/*
+		 * make sure request is in bounds
+		 */
+		port_info->pi_error = FC_OUTOFBOUNDS;
+		FCOEI_LOG(__FUNCTION__, "port_num is not 0");
+		return (NULL);
+	}
+
+	/*
+	 * stash the ss_bind_info supplied by the FC Transport
+	 */
+	bcopy(bind_info, &ss->ss_bind_info, sizeof (fc_fca_bind_info_t));
+	ss->ss_port = bind_info->port_handle;
+
+	/*
+	 * RNID parameter
+	 */
+	port_info->pi_rnid_params.status = FC_FAILURE;
+
+	/*
+	 * populate T11 FC-HBA details
+	 */
+	fcoei_populate_hba_fru_details(ss, port_info);
+
+	/*
+	 * set port's current state, and it is always offline before binding
+	 *
+	 * We hack pi_port_state to tell LV if it's NODMA_FCA
+	 */
+	port_info->pi_port_state = FC_STATE_FCA_IS_NODMA;
+
+	/*
+	 * copy login param
+	 */
+	bcopy(&ss->ss_els_logi, &port_info->pi_login_params,
+	    sizeof (la_els_logi_t));
+
+	/*
+	 * Mark it as bound
+	 */
+	atomic_or_32(&ss->ss_flags, SS_FLAG_LV_BOUND);
+
+	/*
+	 * Let fcoe to report the link status
+	 */
+	fcoei_port_enabled((void *)ss);
+
+	FCOEI_LOG(__FUNCTION__, "Exit fcoei_bind_port: %p", ss);
+	return (ss);
+}
+
+/*
+ * fcoei_unbind_port
+ *	Un-bind the fcoei port
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	Clear binding flag
+ */
+static void
+fcoei_unbind_port(void *fca_handle)
+{
+	fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
+
+	atomic_and_32(&ss->ss_flags, ~SS_FLAG_LV_BOUND);
+	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, NULL);
+	FCOEI_LOG(__FUNCTION__, "Exit fcoei_unbind_port: %p", ss);
+}
+
+/*
+ * fcoei_init_pkt
+ *	Initialize fcoei related part of fc_packet
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	fpkt = The pointer to fc_packet
+ *	sleep = This call can sleep or not
+ *
+ * Returns:
+ *	FC_SUCCESS - Initialization completed successfully
+ *
+ * Comments:
+ *	Link the exchange elements with proper objects
+ */
+static int
+fcoei_init_pkt(void *fca_handle, fc_packet_t *fpkt, int sleep)
+{
+	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)fca_handle;
+	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
+
+	ASSERT(sleep + 1);
+	xch->xch_ss = ss;
+	xch->xch_fpkt = fpkt;
+	xch->xch_flags = 0;
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_un_init_pkt
+ *	Uninitialize fcoei related part of fc_packet
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	fpkt = The pointer to fc_packet
+ *
+ * Returns:
+ *	FC_SUCCESS - Uninitialize successfully
+ *
+ * Comments:
+ *	Very simple, just return successfully
+ */
+static int
+fcoei_un_init_pkt(void *fca_handle, fc_packet_t *fpkt)
+{
+	ASSERT(fca_handle && fpkt);
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_get_cap
+ *	Export FCA hardware and software capability.
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	cap = pointer to the capability string
+ *	ptr = buffer pointer for returning capability
+ *
+ * Returns:
+ *	FC_CAP_ERROR - no such capability
+ *	FC_CAP_FOUND - the capability was returned and cannot be set
+ *
+ * Comments:
+ *	FC_CAP_UNSOL_BUF is one important capability, it will affect the
+ *	implementation of fcoei_ub_alloc/free.
+ */
+static int
+fcoei_get_cap(void * fca_handle, char *cap, void *ptr)
+{
+	fcoei_soft_state_t	*ss   = (fcoei_soft_state_t *)fca_handle;
+	uint32_t		*rptr = (uint32_t *)ptr;
+	int			 rval = FC_CAP_FOUND;
+
+	ASSERT(fca_handle);
+	FCOEI_LOG(__FUNCTION__, "cap: %s", cap);
+	if (strcmp(cap, FC_NODE_WWN) == 0) {
+		bcopy(&ss->ss_els_logi.node_ww_name.raw_wwn[0], ptr, 8);
+	} else if (strcmp(cap, FC_LOGIN_PARAMS) == 0) {
+		bcopy((void *)&ss->ss_els_logi, ptr, sizeof (la_els_logi_t));
+	} else if (strcmp(cap, FC_CAP_UNSOL_BUF) == 0) {
+		*rptr = (uint32_t)0;
+	} else if (strcmp(cap, FC_CAP_NOSTREAM_ON_UNALIGN_BUF) == 0) {
+		*rptr = (uint32_t)FC_ALLOW_STREAMING;
+	} else if (strcmp(cap, FC_CAP_PAYLOAD_SIZE) == 0) {
+		*rptr = (uint32_t)2136;
+	} else if (strcmp(cap, FC_CAP_POST_RESET_BEHAVIOR) == 0) {
+		*rptr = FC_RESET_RETURN_ALL;
+	} else if (strcmp(cap, FC_CAP_FCP_DMA) == 0) {
+		*rptr = FC_NO_DVMA_SPACE;
+	} else {
+		rval = FC_CAP_ERROR;
+		FCOEI_LOG(__FUNCTION__, "not supported");
+	}
+
+	return (rval);
+}
+
+/*
+ * fcoei_set_cap
+ *	Allow the FC Transport to set FCA capabilities if possible
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	cap = pointer to the capabilities string.
+ *	ptr = buffer pointer for capability.
+ *
+ * Returns:
+ *	FC_CAP_ERROR - no such capability
+ *
+ * Comments:
+ *	Currently, all capabilities can't be changed.
+ */
+static int
+fcoei_set_cap(void * fca_handle, char *cap, void *ptr)
+{
+	FCOEI_LOG(__FUNCTION__, "cap: %s, %p, %p", cap, fca_handle, ptr);
+	return (FC_CAP_ERROR);
+}
+
+/*
+ * fcoei_getmap
+ *	Get lilp map
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	mapbuf = the buffer to store lilp map
+ *
+ * Returns:
+ *	FC_FAILURE - Can't get the lilp map
+ *
+ * Comments:
+ *	fcoei can't work in loop topology, so it should never get called
+ */
+static int
+fcoei_getmap(void * fca_handle, fc_lilpmap_t *mapbuf)
+{
+	FCOEI_LOG(__FUNCTION__, "not: %p-%p", fca_handle, mapbuf);
+	return (FC_FAILURE);
+}
+
+/*
+ * fcoei_ub_alloc
+ *	Pre-allocate unsolicited buffers at the request of LV
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	tokens = token array for each buffer.
+ *	size = number of tokens
+ *	count = the acutual number of allocated unsolicited buffers
+ *	type = unsolicited buffer type
+ *
+ * Returns:
+ *	FC_SUCCESS - The requested buffers have been freeed
+ *
+ * Comments:
+ *	fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
+ */
+static int
+fcoei_ub_alloc(void * fca_handle, uint64_t tokens[], uint32_t size,
+    uint32_t *count, uint32_t type)
+{
+	FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x-%p-%x", fca_handle, tokens,
+	    size, count, type);
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_ub_free
+ *	Free the pre-allocated unsolicited buffers at the request of LV
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	count = number of buffers.
+ *	tokens = token array for each buffer.
+ *
+ * Returns:
+ *	FC_SUCCESS - The requested buffers have been freeed
+ *
+ * Comments:
+ *	fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
+ */
+static int
+fcoei_ub_free(void * fca_handle, uint32_t count, uint64_t tokens[])
+{
+	FCOEI_EXT_LOG(__FUNCTION__, "not: %p-%x-%p", fca_handle, count, tokens);
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_ub_release
+ *	Release unsolicited buffers from FC Transport to FCA for future use
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	count = number of buffers.
+ *	tokens = token array for each buffer.
+ *
+ * Returns:
+ *	FC_SUCCESS - The requested buffers have been released.
+ *	FC_FAILURE - The requested buffers have not been released.
+ *
+ * Comments:
+ *	It will always succeed. It has nothing to do with fcoei_ub_alloc/free.
+ */
+static int
+fcoei_ub_release(void * fca_handle, uint32_t count, uint64_t tokens[])
+{
+	fc_unsol_buf_t *ub = *((fc_unsol_buf_t **)tokens);
+
+	if (count != 1) {
+		FCOEI_LOG(__FUNCTION__, "count is not 1: %p", fca_handle);
+		return (FC_FAILURE);
+	}
+
+	kmem_free(ub->ub_buffer, ub->ub_bufsize);
+	kmem_free(ub, sizeof (fc_unsol_buf_t));
+	FCOEI_EXT_LOG(__FUNCTION__, "ub is freeed");
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_abort
+ *	Direct FCA driver to abort an outstanding exchange associated with a
+ *	specified fc_packet_t struct
+ *
+ * Input:
+ *	fca_handle - fcoei soft state set in fcoei_bind_port
+ *	fpkt - A pointer to the fc_packet_t for the exchange to be aborted.
+ *	flags - Set to KM_SLEEP if the function may sleep, or KM_NOSLEEP if
+ *		the function may not sleep.
+ *
+ * Returns:
+ *	FC_ABORTED - The specified exchange was successfully aborted.
+ *	FC_ABORTING - The specified exchange is being aborted.
+ *	FC_ABORT_FAILED - The specified exchange could not be aborted.
+ *	FC_TRANSPORT_ERROR - A transport error occurred while attempting to
+ *		abort the specified exchange.
+ *	FC_BADEXCHANGE - The specified exchange does not exist.
+ *
+ * Comments:
+ *	After the exchange is aborted, the FCA driver must update the relevant
+ *	fields in the fc_packet_t struct as per normal exchange completion and
+ *	call the pkt_comp function to return the fc_packet_t struct to the FC
+ *	Transport.
+ *	When an exchange is successfully aborted, the FCA driver must set the
+ *	pkt_reason field in the fc_packet_t to FC_REASON_ABORTED and the
+ *	pkt_state field in the fc_packet_t to FC_PKT_LOCAL_RJT before returning
+ *	the fc_packet_t to the FC Transport.
+ *
+ *	Unfortunately, LV doesn't conform to the spec. It will take all these
+ *	legal return value as failure to abort.
+ */
+static int
+fcoei_abort(void * fca_handle, fc_packet_t *fpkt, int flags)
+{
+	FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x", fca_handle, fpkt, flags);
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_reset
+ *	Reset link or hardware
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	cmd = reset type command
+ *
+ * Returns:
+ *	FC_SUCCESS - Reset has completed successfully
+ *	FC_FAILURE - Reset has failed
+ *
+ * Comments:
+ *	N/A
+ */
+static int
+fcoei_reset(void * fca_handle, uint32_t cmd)
+{
+	int			 rval = FC_SUCCESS;
+	fcoei_soft_state_t	*ss   = (fcoei_soft_state_t *)fca_handle;
+	fcoei_event_t *ae;
+
+	switch (cmd) {
+	case FC_FCA_LINK_RESET:
+		if (ss->ss_link_state != FC_STATE_ONLINE) {
+			FCOEI_LOG(__FUNCTION__, "not online now: ss-%p", ss);
+			rval = FC_FAILURE;
+			break;
+		}
+
+		/*
+		 * This is linkreset phase I
+		 */
+		fcoei_logo_peer(ss);
+		delay(FCOE_SEC2TICK(1) / 10);
+		ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
+		fcoei_port_event(ss->ss_eport, FCOE_NOTIFY_EPORT_LINK_DOWN);
+
+		/*
+		 * Perpare linkreset phase II
+		 */
+		ae = kmem_zalloc(sizeof (*ae), KM_SLEEP);
+		ae->ae_type = AE_EVENT_RESET;
+		ae->ae_obj = ss;
+
+		mutex_enter(&ss->ss_watchdog_mutex);
+		list_insert_tail(&ss->ss_event_list, ae);
+		mutex_exit(&ss->ss_watchdog_mutex);
+		break;
+
+	case FC_FCA_RESET:
+		break;
+
+	case FC_FCA_CORE:
+		break;
+
+	case FC_FCA_RESET_CORE:
+		break;
+
+	default:
+		rval = FC_FAILURE;
+		FCOEI_LOG(__FUNCTION__, "cmd-%x not supported", cmd);
+		break;
+	}
+
+	return (rval);
+}
+
+/*
+ * fcoei_port_manage
+ *	Perform various port management operations at the request of LV
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	pm = the pointer to the struct specifying the port management operation
+ *
+ * Returns:
+ *	FC_SUCCESS - The request completed successfully
+ *	FC_FAILURE - The request did not complete successfully
+ *
+ * Comments:
+ *	N/A
+ */
+static int
+fcoei_port_manage(void * fca_handle, fc_fca_pm_t *pm)
+{
+	int	rval = FC_FAILURE;
+	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)fca_handle;
+
+	if (fca_handle == NULL || pm == NULL) {
+		return (rval);
+	}
+
+	FCOEI_LOG(__FUNCTION__, "code0x%x, %p", pm->pm_cmd_code, fca_handle);
+	switch (pm->pm_cmd_code) {
+
+	case FC_PORT_GET_NODE_ID:
+	{
+		if (pm->pm_data_len < sizeof (fc_rnid_t)) {
+			rval = FC_NOMEM;
+			break;
+		}
+		ss->ss_rnid.port_id = ss->ss_p2p_info.fca_d_id;
+		bcopy((void *)&ss->ss_rnid,
+		    pm->pm_data_buf, sizeof (fc_rnid_t));
+		rval = FC_SUCCESS;
+		break;
+	}
+
+	case FC_PORT_SET_NODE_ID:
+	{
+		if (pm->pm_data_len < sizeof (fc_rnid_t)) {
+			rval = FC_NOMEM;
+			break;
+		}
+		bcopy(pm->pm_data_buf,
+		    (void *)&ss->ss_rnid, sizeof (fc_rnid_t));
+		rval = FC_SUCCESS;
+		break;
+	}
+
+	default:
+		FCOEI_LOG(__FUNCTION__, "unsupported cmd-%x", pm->pm_cmd_code);
+		rval = FC_INVALID_REQUEST;
+		break;
+	}
+
+	return (rval);
+}
+
+/*
+ * fcoei_get_device
+ *	Get fcoei remote port with FCID of d_id
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	d_id = 24-bit FCID of remote port
+ *
+ * Returns:
+ *	The pointer to fcoei remote port
+ *
+ * Comments:
+ *	fcoei has no remote port device
+ */
+static void *
+fcoei_get_device(void *fca_handle, fc_portid_t d_id)
+{
+	FCOEI_EXT_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, d_id);
+	return (NULL);
+}
+
+/*
+ * fcoei_notify
+ *	Notify the change of target device
+ *
+ * Input:
+ *	fca_handle = fcoei soft state set in fcoei_bind_port
+ *	cmd = detailed cmd
+ *
+ * Returns:
+ *	FC_SUCCESS - Notification completed successfully
+ *
+ * Comments:
+ *	It's only needed to support non-COMSTAR FC target, so it should
+ *	never get called.
+ */
+static int
+fcoei_notify(void *fca_handle, uint32_t cmd)
+{
+	FCOEI_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, cmd);
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_transport
+ *	Submit FCP/CT requests
+ *
+ * Input:
+ *	fca_handle - fcoei soft state set in fcoei_bind_port
+ *	fpkt - LV fc_packet
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static int
+fcoei_transport(void *fca_handle, fc_packet_t *fpkt)
+{
+	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)fca_handle;
+	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
+	uint16_t		 pkt_tran_flags = fpkt->pkt_tran_flags;
+
+	xch->xch_start_tick = ddi_get_lbolt();
+	xch->xch_end_tick = xch->xch_start_tick +
+	    FCOE_SEC2TICK(fpkt->pkt_timeout);
+	xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
+	xch->xch_ae.ae_obj = xch;
+
+	if (pkt_tran_flags & FC_TRAN_NO_INTR) {
+		FCOEI_LOG(__FUNCTION__, "AaA polling: %p-%p", fpkt, xch);
+		sema_init(&xch->xch_sema, 0, NULL, SEMA_DRIVER, NULL);
+	}
+
+	mutex_enter(&ss->ss_watchdog_mutex);
+	list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
+	if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
+		cv_signal(&ss->ss_watchdog_cv);
+	}
+	mutex_exit(&ss->ss_watchdog_mutex);
+
+	if (pkt_tran_flags & FC_TRAN_NO_INTR) {
+		FCOEI_LOG(__FUNCTION__, "BaB polling: %p-%p", fpkt, xch);
+		sema_p(&xch->xch_sema);
+		sema_destroy(&xch->xch_sema);
+		FCOEI_LOG(__FUNCTION__, "after polling: %p-%p", fpkt, xch);
+	}
+
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_els_send
+ *	Submit ELS request or response
+ *
+ * Input:
+ *	fca_handle - fcoei soft state set in fcoei_bind_port
+ *	fpkt = LV fc_packet
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static int
+fcoei_els_send(void *fca_handle, fc_packet_t *fpkt)
+{
+	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)fca_handle;
+	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
+
+	if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
+		FCOEI_LOG(__FUNCTION__, "ELS poll mode is not supported");
+		return (FC_BADPACKET);
+	}
+
+	xch->xch_start_tick = ddi_get_lbolt();
+	xch->xch_end_tick = xch->xch_start_tick +
+	    FCOE_SEC2TICK(fpkt->pkt_timeout);
+	xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
+	xch->xch_ae.ae_obj = xch;
+
+	/*
+	 * LV could release ub after this call, so we must save the ub type
+	 * for later use
+	 */
+	if (fpkt->pkt_cmd_fhdr.r_ctl == R_CTL_ELS_RSP) {
+		((uint8_t *)&fpkt->pkt_fca_rsvd1)[0] =
+		    ((fc_unsol_buf_t *)fpkt->pkt_ub_resp_token)->ub_buffer[0];
+	}
+
+	mutex_enter(&ss->ss_watchdog_mutex);
+	list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
+	if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
+		cv_signal(&ss->ss_watchdog_cv);
+	}
+	mutex_exit(&ss->ss_watchdog_mutex);
+
+	return (FC_SUCCESS);
+}
+
+/*
+ * fcoei_populate_hba_fru_details
+ *	Fill detailed information about HBA
+ *
+ * Input:
+ *	ss - fcoei soft state
+ *	port_info = fc_fca_port_info_t that need be updated
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
+    fc_fca_port_info_t *port_info)
+{
+	fca_port_attrs_t *port_attrs = &(port_info->pi_attrs);
+	int	instance;
+
+	ASSERT(ss != NULL);
+	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
+	    "Sun Microsystems, Inc.");
+	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
+	    "%s", FCOEI_NAME_VERSION);
+	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
+	    "%s", FCOEI_VERSION);
+	(void) strcpy(port_attrs->serial_number, "N/A");
+	(void) strcpy(port_attrs->hardware_version, "N/A");
+	(void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
+	(void) strcpy(port_attrs->model_description, "N/A");
+	(void) strcpy(port_attrs->firmware_version, "N/A");
+	(void) strcpy(port_attrs->option_rom_version, "N/A");
+
+	port_attrs->vendor_specific_id = 0xFC0E;
+	port_attrs->max_frame_size = FCOE_MAX_FC_FRAME_SIZE;
+	port_attrs->supported_cos = 0x10000000;
+	port_attrs->supported_speed = FC_HBA_PORTSPEED_1GBIT |
+	    FC_HBA_PORTSPEED_10GBIT;
+	instance = ddi_get_instance(ss->ss_dip);
+	port_attrs->hba_fru_details.high =
+	    (short)((instance & 0xffff0000) >> 16);
+	port_attrs->hba_fru_details.low =
+	    (short)(instance & 0x0000ffff);
+}
+
+/*
+ * fcoei_port_enabled
+ *	Notify fcoe that the port has been enabled
+ *
+ * Input:
+ *	arg = the related soft state
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	Only after this, fcoe will report the link status to us
+ */
+static void
+fcoei_port_enabled(void *arg)
+{
+	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)arg;
+
+	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, NULL);
+}
+
+
+/*
+ * fcoei_initiate_ct_req
+ *	Fill and submit CT request
+ *
+ * Input:
+ *	xch - the exchange that will be initiated
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_initiate_ct_req(fcoei_exchange_t *xch)
+{
+	fc_packet_t	*fpkt	 = xch->xch_fpkt;
+	fc_ct_header_t	*ct	 = (fc_ct_header_t *)(void *)fpkt->pkt_cmd;
+	uint8_t		*bp	 = (uint8_t *)fpkt->pkt_cmd;
+	fcoe_frame_t	*frm;
+	int		 offset;
+	int		 idx;
+	uint32_t	 cmd_len = fpkt->pkt_cmdlen;
+
+	/*
+	 * Ensure it's 4-byte aligned
+	 */
+	cmd_len = P2ROUNDUP(cmd_len, 4);
+
+	/*
+	 * Allocate CT request frame
+	 */
+	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
+	    cmd_len + FCFH_SIZE, NULL);
+	if (frm == NULL) {
+		FCOEI_LOG(__FUNCTION__, "failed to alloc: %p", xch);
+		return;
+	}
+
+	bzero(frm->frm_payload, cmd_len);
+	xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
+	atomic_add_32(xch->xch_cnt, 1);
+
+	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
+	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
+	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
+	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
+	FFM_F_CTL(fpkt->pkt_cmd_fhdr.f_ctl, frm);
+	FFM_OXID(xch->xch_oxid, frm);
+	FFM_RXID(xch->xch_rxid, frm);
+	fcoei_init_ifm(frm, xch);
+
+	/*
+	 * CT header (FC payload)
+	 */
+	offset = 0;
+	FCOE_V2B_1(ct->ct_rev, FPLD + offset);
+
+	offset = 1;
+	FCOE_V2B_3(ct->ct_inid, FPLD + offset);
+
+	offset = 4;
+	FCOE_V2B_1(ct->ct_fcstype, FPLD + offset);
+
+	offset = 5;
+	FCOE_V2B_1(ct->ct_fcssubtype, FPLD + offset);
+
+	offset = 6;
+	FCOE_V2B_1(ct->ct_options, FPLD + offset);
+
+	offset = 8;
+	FCOE_V2B_2(ct->ct_cmdrsp, FPLD + offset);
+
+	offset = 10;
+	FCOE_V2B_2(ct->ct_aiusize, FPLD + offset);
+
+	offset = 13;
+	FCOE_V2B_1(ct->ct_reason, FPLD + offset);
+
+	offset = 14;
+	FCOE_V2B_1(ct->ct_expln, FPLD + offset);
+
+	offset = 15;
+	FCOE_V2B_1(ct->ct_vendor, FPLD + offset);
+
+	/*
+	 * CT payload (FC payload)
+	 */
+	switch (ct->ct_fcstype) {
+	case FCSTYPE_DIRECTORY:
+		switch (ct->ct_cmdrsp) {
+		case NS_GA_NXT:
+		case NS_GPN_ID:
+		case NS_GNN_ID:
+		case NS_GCS_ID:
+		case NS_GFT_ID:
+		case NS_GSPN_ID:
+		case NS_GPT_ID:
+		case NS_GID_FT:
+		case NS_GID_PT:
+		case NS_DA_ID:
+			offset = 16;
+			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
+			    FPLD + offset);
+			break;
+
+		case NS_GID_PN:
+			offset = 16;
+			bcopy(bp + offset, FPLD + offset, 8);
+			break;
+
+		case NS_RNN_ID:
+		case NS_RPN_ID:
+			offset = 16;
+			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
+			    FPLD + offset);
+
+			offset = 20;
+			bcopy(bp + offset, FPLD + offset, 8);
+			break;
+
+		case NS_RSPN_ID:
+			offset = 16;
+			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
+			    FPLD + offset);
+
+			offset = 20;
+			bcopy(bp + offset, FPLD + offset, bp[20] + 1);
+			break;
+
+		case NS_RSNN_NN:
+			offset = 16;
+			bcopy(bp + offset, FPLD + offset, 8);
+
+			offset = 24;
+			bcopy(bp + offset, FPLD + offset, bp[24] + 1);
+			break;
+
+		case NS_RFT_ID:
+			offset = 16;
+			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
+			    FPLD + offset);
+
+			/*
+			 * fp use bcopy to copy fp_fc4_types,
+			 * we need to swap order for each integer
+			 */
+			offset = 20;
+			for (idx = 0; idx < 8; idx++) {
+				FCOE_V2B_4(
+				    ((uint32_t *)(intptr_t)(bp + offset))[0],
+				    FPLD + offset);
+				offset += 4;
+			}
+			break;
+
+		case NS_RCS_ID:
+		case NS_RPT_ID:
+			offset = 16;
+			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
+			    FPLD + offset);
+
+			offset = 20;
+			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
+			    FPLD + offset);
+			break;
+
+		case NS_RIP_NN:
+			offset = 16;
+			bcopy(bp + offset, FPLD + offset, 24);
+			break;
+
+		default:
+			fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
+			    FC_REASON_CMD_UNSUPPORTED);
+			break;
+		}
+		break; /* FCSTYPE_DIRECTORY */
+
+	case FCSTYPE_MGMTSERVICE:
+		switch (ct->ct_cmdrsp) {
+		case MS_GIEL:
+			FCOEI_LOG(__FUNCTION__,
+			    "MS_GIEL ct_fcstype %x, ct_cmdrsp: %x",
+			    ct->ct_fcstype, ct->ct_cmdrsp);
+			break;
+
+		default:
+			fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
+			    FC_REASON_CMD_UNSUPPORTED);
+			break;
+		}
+		break; /* FCSTYPE_MGMTSERVICE */
+
+	default:
+		fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
+		    FC_REASON_CMD_UNSUPPORTED);
+		break;
+	}
+	xch->xch_ss->ss_eport->eport_tx_frame(frm);
+}
+
+/*
+ * fcoei_initiate_fcp_cmd
+ *	Submit FCP command
+ *
+ * Input:
+ *	xch - the exchange to be submitted
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch)
+{
+	fc_packet_t	*fpkt = xch->xch_fpkt;
+	fcoe_frame_t	*frm;
+	fcp_cmd_t	*fcp_cmd_iu = (fcp_cmd_t *)(void *)fpkt->pkt_cmd;
+	int		 offset = 0;
+
+	ASSERT((fpkt->pkt_cmdlen % 4) == 0);
+	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
+	    fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
+	if (!frm) {
+		ASSERT(0);
+	} else {
+		fcoei_init_ifm(frm, xch);
+		bzero(frm->frm_payload, fpkt->pkt_cmdlen);
+	}
+
+	/*
+	 * This will affect timing check
+	 */
+	xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
+	atomic_add_32(xch->xch_cnt, 1);
+
+	/*
+	 * Set exchange residual bytes
+	 */
+	xch->xch_resid = (int)fpkt->pkt_datalen;
+
+	/*
+	 * Fill FCP command IU
+	 *
+	 * fcp_ent_addr
+	 */
+	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_0,
+	    frm->frm_payload + offset);
+	offset += 2;
+	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_1,
+	    frm->frm_payload + offset);
+	offset += 2;
+	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_2,
+	    frm->frm_payload + offset);
+	offset += 2;
+	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_3,
+	    frm->frm_payload + offset);
+	/*
+	 * fcp_cntl
+	 */
+	offset = offsetof(fcp_cmd_t, fcp_cntl);
+	frm->frm_payload[offset] = 0;
+
+	offset += 1;
+	frm->frm_payload[offset] = fcp_cmd_iu->fcp_cntl.cntl_qtype & 0x07;
+	offset += 1;
+	frm->frm_payload[offset] =
+	    (fcp_cmd_iu->fcp_cntl.cntl_kill_tsk * BIT_7) |
+	    (fcp_cmd_iu->fcp_cntl.cntl_clr_aca * BIT_6) |
+	    (fcp_cmd_iu->fcp_cntl.cntl_reset_tgt * BIT_5) |
+	    (fcp_cmd_iu->fcp_cntl.cntl_reset_lun * BIT_4) |
+	    (fcp_cmd_iu->fcp_cntl.cntl_clr_tsk * BIT_2) |
+	    (fcp_cmd_iu->fcp_cntl.cntl_abort_tsk * BIT_1);
+	offset += 1;
+	frm->frm_payload[offset] =
+	    (fcp_cmd_iu->fcp_cntl.cntl_read_data * BIT_1) |
+	    (fcp_cmd_iu->fcp_cntl.cntl_write_data * BIT_0);
+	/*
+	 * fcp_cdb
+	 */
+	offset = offsetof(fcp_cmd_t, fcp_cdb);
+	bcopy(fcp_cmd_iu->fcp_cdb, frm->frm_payload + offset, FCP_CDB_SIZE);
+	/*
+	 * fcp_data_len
+	 */
+	offset += FCP_CDB_SIZE;
+	FCOE_V2B_4(fcp_cmd_iu->fcp_data_len, frm->frm_payload + offset);
+
+	/*
+	 * FC frame header
+	 */
+	FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
+
+	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
+	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
+	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
+	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
+	FFM_F_CTL(0x290000, frm);
+	FFM_OXID(xch->xch_oxid, frm);
+	FFM_RXID(xch->xch_rxid, frm);
+
+	xch->xch_ss->ss_eport->eport_tx_frame(frm);
+}
+
+/*
+ * fcoei_initiate_els_req
+ *	Initiate ELS request
+ *
+ * Input:
+ *	xch = the exchange that will be initiated
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_initiate_els_req(fcoei_exchange_t *xch)
+{
+	fc_packet_t	*fpkt = xch->xch_fpkt;
+	fcoe_frame_t	*frm;
+	ls_code_t	*els_code;
+
+	ASSERT((fpkt->pkt_cmdlen % 4) == 0);
+	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
+	    fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
+	if (!frm) {
+		ASSERT(0);
+	} else {
+		fcoei_init_ifm(frm, xch);
+		bzero(frm->frm_payload, fpkt->pkt_cmdlen);
+	}
+
+	/*
+	 * This will affect timing check
+	 */
+	xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
+	atomic_add_32(xch->xch_cnt, 1);
+
+	els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
+	switch (els_code->ls_code) {
+	case LA_ELS_FLOGI:
+		/*
+		 * For FLOGI, we expect response within E_D_TOV
+		 */
+		xch->xch_start_tick = ddi_get_lbolt();
+		xch->xch_end_tick = xch->xch_start_tick +
+		    FCOE_SEC2TICK(2);
+		xch->xch_ss->ss_flags &= ~SS_FLAG_FLOGI_FAILED;
+		/* FALLTHROUGH */
+
+	case LA_ELS_PLOGI:
+		fcoei_fill_els_logi_cmd(fpkt, frm);
+		break;
+
+	case LA_ELS_PRLI:
+		fcoei_fill_els_prli_cmd(fpkt, frm);
+		break;
+
+	case LA_ELS_SCR:
+		fcoei_fill_els_scr_cmd(fpkt, frm);
+		break;
+
+	case LA_ELS_LINIT:
+		fcoei_fill_els_linit_cmd(fpkt, frm);
+		break;
+
+	case LA_ELS_ADISC:
+		fcoei_fill_els_adisc_cmd(fpkt, frm);
+		break;
+
+	case LA_ELS_LOGO:
+		/*
+		 * For LOGO, we expect response within E_D_TOV
+		 */
+		xch->xch_start_tick = ddi_get_lbolt();
+		xch->xch_end_tick = xch->xch_start_tick +
+		    FCOE_SEC2TICK(2);
+		fcoei_fill_els_logo_cmd(fpkt, frm);
+		break;
+	case LA_ELS_RLS:
+		fcoei_fill_els_rls_cmd(fpkt, frm);
+		break;
+	case LA_ELS_RNID:
+		fcoei_fill_els_rnid_cmd(fpkt, frm);
+		break;
+	default:
+		fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
+		    FC_REASON_CMD_UNSUPPORTED);
+		return;
+	}
+
+	/*
+	 * set ifm_rtcl
+	 */
+	FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
+
+	/*
+	 * FCPH
+	 */
+	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
+	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
+	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
+	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
+	FFM_F_CTL(0x290000, frm);
+	FFM_OXID(xch->xch_oxid, frm);
+	FFM_RXID(xch->xch_rxid, frm);
+
+	xch->xch_ss->ss_eport->eport_tx_frame(frm);
+}
+
+/*
+ * fcoei_initiate_els_resp
+ *	Originate ELS response
+ *
+ * Input:
+ *	xch = the associated exchange
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_initiate_els_resp(fcoei_exchange_t *xch)
+{
+	fc_packet_t	*fpkt = xch->xch_fpkt;
+	fcoe_frame_t	*frm;
+
+	ASSERT((fpkt->pkt_cmdlen % 4) == 0);
+	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
+	    fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
+	if (!frm) {
+		ASSERT(0);
+	} else {
+		fcoei_init_ifm(frm, xch);
+		bzero(frm->frm_payload, fpkt->pkt_cmdlen);
+	}
+
+	/*
+	 * This will affect timing check
+	 */
+	xch->xch_cnt = xch->xch_ss->ss_unsol_cnt;
+	atomic_add_32(xch->xch_cnt, 1);
+
+	/*
+	 * Set ifm_rctl
+	 */
+	FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
+
+	/*
+	 * FCPH
+	 */
+	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
+	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
+	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
+	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
+	FFM_F_CTL(0x980000, frm);
+	FFM_OXID(xch->xch_oxid, frm);
+	FFM_RXID(xch->xch_rxid, frm);
+
+	switch (((uint8_t *)&fpkt->pkt_fca_rsvd1)[0]) {
+	case LA_ELS_FLOGI:
+		fcoei_fill_els_logi_resp(fpkt, frm);
+		break;
+
+	case LA_ELS_PLOGI:
+		if (FRM2SS(frm)->ss_eport->eport_flags &
+		    EPORT_FLAG_IS_DIRECT_P2P) {
+			FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_S_ID(frm);
+			FRM2SS(frm)->ss_p2p_info.d_id = FRM_D_ID(frm);
+		}
+
+		fcoei_fill_els_logi_resp(fpkt, frm);
+		break;
+
+	case LA_ELS_PRLI:
+		fcoei_fill_els_prli_resp(fpkt, frm);
+		break;
+
+	case LA_ELS_ADISC:
+		fcoei_fill_els_adisc_resp(fpkt, frm);
+		break;
+
+	case LA_ELS_LOGO:
+		fcoei_fill_els_logo_resp(fpkt, frm);
+		break;
+	case LA_ELS_RSCN:
+		fcoei_fill_els_acc_resp(fpkt, frm);
+		break;
+
+	default:
+		fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
+		    FC_REASON_CMD_UNSUPPORTED);
+		return;
+	}
+
+	xch->xch_ss->ss_eport->eport_tx_frame(frm);
+}
+
+/*
+ * fcoei_fill_els_logi_cmd
+ *	Fill SCR (state change register) command frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing LOGI response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_logi_t	*els_logi = (la_els_logi_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	/*
+	 * fill ls_code
+	 */
+	offset = 0;
+	FCOE_V2B_1(els_logi->ls_code.ls_code, FPLD + offset);
+
+	/*
+	 * fill common service parameters
+	 */
+	offset = 4;
+	FCOE_V2B_2(els_logi->common_service.fcph_version, FPLD + offset);
+
+	offset = 6;
+	FCOE_V2B_2(els_logi->common_service.btob_credit, FPLD + offset);
+
+	offset = 8;
+	FCOE_V2B_2(els_logi->common_service.cmn_features, FPLD + offset);
+
+	offset = 10;
+	FCOE_V2B_2(els_logi->common_service.rx_bufsize, FPLD + offset);
+
+	offset = 12;
+	FCOE_V2B_2(els_logi->common_service.conc_sequences, FPLD + offset);
+
+	offset = 14;
+	FCOE_V2B_2(els_logi->common_service.relative_offset, FPLD + offset);
+
+	offset = 16;
+	FCOE_V2B_4(els_logi->common_service.e_d_tov, FPLD + offset);
+
+	/*
+	 * port/node wwn
+	 */
+	offset = 20;
+	bcopy(&els_logi->nport_ww_name, FPLD + offset, 8);
+
+	offset = 28;
+	bcopy(&els_logi->node_ww_name, FPLD + offset, 8);
+
+	/*
+	 * class_3
+	 */
+	offset = 68;
+	FCOE_V2B_2(els_logi->class_3.class_opt, FPLD + offset);
+
+	offset = 70;
+	FCOE_V2B_2(els_logi->class_3.initiator_ctl, FPLD + offset);
+
+	offset = 72;
+	FCOE_V2B_2(els_logi->class_3.recipient_ctl, FPLD + offset);
+
+	offset = 74;
+	FCOE_V2B_2(els_logi->class_3.rcv_size, FPLD + offset);
+
+	offset = 76;
+	FCOE_V2B_2(els_logi->class_3.conc_sequences, FPLD + offset);
+
+	offset = 78;
+	FCOE_V2B_2(els_logi->class_3.n_port_e_to_e_credit, FPLD + offset);
+
+	offset = 80;
+	FCOE_V2B_2(els_logi->class_3.open_seq_per_xchng, FPLD + offset);
+	/*
+	 * needn't touch other fields
+	 */
+}
+
+/*
+ * fcoei_fill_prli_cmd
+ *	Fill PRLI command frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing PRLI response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	int		 offset	    = 0;
+	la_els_prli_t	*els_prli   = (la_els_prli_t *)(void *)fpkt->pkt_cmd;
+	struct fcp_prli *fcp_spp    =
+	    (struct fcp_prli *)(void *)els_prli->service_params;
+
+	/*
+	 * fill basic PRLI fields
+	 */
+	offset = 0;
+	FCOE_V2B_1(els_prli->ls_code, FPLD + offset);
+
+	offset = 1;
+	FCOE_V2B_1(els_prli->page_length, FPLD + offset);
+
+	offset = 2;
+	FCOE_V2B_2(els_prli->payload_length, FPLD + offset);
+
+	/*
+	 * fill FCP service parameters page
+	 */
+	offset = 4;
+	FCOE_V2B_1(fcp_spp->type, FPLD + offset);
+
+	/*
+	 * PRLI flags, only 3 bits are valid
+	 */
+	offset = 6;
+	FCOE_V2B_2((fcp_spp->orig_process_assoc_valid * BIT_15) |
+	    (fcp_spp->resp_process_assoc_valid * BIT_14) |
+	    (fcp_spp->establish_image_pair * BIT_13), FPLD + offset);
+
+	/*
+	 * process associator
+	 */
+	offset = 8;
+	FCOE_V2B_4(fcp_spp->orig_process_associator, FPLD + offset);
+
+	offset = 12;
+	FCOE_V2B_4(fcp_spp->resp_process_associator, FPLD + offset);
+
+	/*
+	 * FC-4 type
+	 */
+	offset = 16;
+	FCOE_V2B_4((fcp_spp->retry * BIT_8) |
+	    (fcp_spp->confirmed_compl_allowed * BIT_7) |
+	    (fcp_spp->data_overlay_allowed * BIT_6) |
+	    (fcp_spp->initiator_fn * BIT_5) | (fcp_spp->target_fn * BIT_4) |
+	    (fcp_spp->read_xfer_rdy_disabled * BIT_1) |
+	    (fcp_spp->write_xfer_rdy_disabled * BIT_0), FPLD + offset);
+}
+
+/*
+ * fcoei_fill_els_scr_cmd
+ *	Fill SCR (state change register) command frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing SCR command
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	fc_scr_req_t	*els_scr = (fc_scr_req_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	offset = 0;
+	FCOE_V2B_1(els_scr->ls_code.ls_code, FPLD + offset);
+
+	offset = 7;
+	FCOE_V2B_1(els_scr->scr_func, FPLD + offset);
+}
+
+/*
+ * fcoei_fill_els_adisc_cmd
+ *	Fill ADISC command frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing ADISC command
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_adisc_t	*els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	offset = 0;
+	FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
+
+	offset = 5;
+	FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
+
+	offset = 8;
+	bcopy(&els_adisc->port_wwn, FPLD + offset, 8);
+
+	offset = 16;
+	bcopy(&els_adisc->node_wwn, FPLD + offset, 8);
+
+	offset = 25;
+	FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
+}
+
+/*
+ * fcoei_fill_els_linit_cmd
+ *	Fill LINIT command frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing LINIT command
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	ASSERT(fpkt && frm);
+}
+
+/*
+ * fcoei_fill_els_logo_cmd
+ *	Fill LOGO command frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing LOGO command
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_logo_t	*els_logo   = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	offset = 0;
+	FCOE_V2B_1(els_logo->ls_code.ls_code, FPLD + offset);
+
+	offset = 5;
+	FCOE_V2B_3(els_logo->nport_id.port_id, FPLD + offset);
+
+	offset = 8;
+	bcopy(&els_logo->nport_ww_name, FPLD + offset, 8);
+}
+
+static void
+fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_rls_t	*els_rls = (la_els_rls_t *)(void *)fpkt->pkt_cmd;
+	int		offset;
+
+	offset = 0;
+	FCOE_V2B_1(els_rls->ls_code.ls_code, FPLD + offset);
+
+	offset = 5;
+	FCOE_V2B_3(els_rls->rls_portid.port_id, FPLD + offset);
+}
+
+static void
+fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_rnid_t *els_rnid = (la_els_rnid_t *)(void *)fpkt->pkt_cmd;
+	int		offset;
+
+	offset = 0;
+	FCOE_V2B_1(els_rnid->ls_code.ls_code, FPLD + offset);
+
+	offset = 4;
+	bcopy(&els_rnid->data_format, FPLD + offset, 1);
+}
+/*
+ * fcoei_fill_els_acc_resp
+ *	Fill ELS ACC response frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing ELS ACC response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	ls_code_t	*els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	offset = 0;
+	FCOE_V2B_1(els_code->ls_code, FPLD + offset);
+
+	offset = 1;
+	FCOE_V2B_3(els_code->mbz, FPLD + offset);
+}
+
+/*
+ * fcoei_fill_els_rjt_resp
+ *	Fill ELS RJT response frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containg ELS RJT response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_rjt_t	*els_rjt = (la_els_rjt_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	offset = 0; /* reset ls code */
+	FCOE_V2B_1(els_rjt->ls_code.ls_code, FPLD + offset);
+
+	offset = 5; /* reason code */
+	FCOE_V2B_1(els_rjt->action, FPLD + offset);
+
+	offset = 6; /* reason explanation */
+	FCOE_V2B_1(els_rjt->reason, FPLD + offset);
+
+	offset = 7; /* vendor unique */
+	FCOE_V2B_1(els_rjt->vu, FPLD + offset);
+}
+
+/*
+ * fcoei_fill_els_adisc_resp
+ *	Fill ADISC response frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing ADISC response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	la_els_adisc_t	*els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
+	int		 offset;
+
+	if (els_adisc->ls_code.ls_code == LA_ELS_RJT) {
+		fcoei_fill_els_rjt_resp(fpkt, frm);
+	} else {
+		offset = 0;
+		FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
+
+		offset = 5;
+		FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
+
+		offset = 8;
+		bcopy(&els_adisc->port_wwn, FPLD + offset, FC_WWN_SIZE);
+
+		offset = 16;
+		bcopy(&els_adisc->node_wwn, FPLD + offset, FC_WWN_SIZE);
+
+		offset = 25;
+		FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
+	}
+}
+
+/*
+ * fcoei_fill_els_logi_resp
+ *	Fill FLOGI/PLOGI response frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing LOGI response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	ls_code_t	*els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
+
+	if (els_code->ls_code == LA_ELS_RJT) {
+		fcoei_fill_els_rjt_resp(fpkt, frm);
+	} else {
+		fcoei_fill_els_logi_cmd(fpkt, frm);
+	}
+}
+
+/*
+ * fcoei_fill_els_prli_resp
+ *	Fill PRLI response frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing PRLI response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	ls_code_t	*els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
+
+	if (els_code->ls_code == LA_ELS_RJT) {
+		fcoei_fill_els_rjt_resp(fpkt, frm);
+	} else {
+		fcoei_fill_els_prli_cmd(fpkt, frm);
+	}
+}
+
+/*
+ * fcoei_fill_els_logo_resp
+ *	Fill LOGO response frame
+ *
+ * Input:
+ *	fpkt = LV fc_packet
+ *	frm = Unsolicited frame containing LOGO response
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
+{
+	ls_code_t	*els_code   = (ls_code_t *)(void *)fpkt->pkt_cmd;
+
+	if (els_code->ls_code == LA_ELS_RJT) {
+		fcoei_fill_els_rjt_resp(fpkt, frm);
+	} else {
+		fcoei_fill_els_acc_resp(fpkt, frm);
+	}
+}
+
+/*
+ * fcoei_logo_peer
+ *	Send LOGO to the peer to emulate link offline event
+ *
+ * Input:
+ *	arg - fcoei soft state set in fcoei_bind_port
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+static void
+fcoei_logo_peer(void *arg)
+{
+	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)arg;
+	fc_packet_t		*fpkt;
+	fcoei_exchange_t	*xch;
+	la_els_logo_t		*els_logo;
+
+	/*
+	 * Allocate space for exchange
+	 */
+	xch = kmem_zalloc(sizeof (*xch), KM_SLEEP);
+
+	/*
+	 * Allocate space for fc_packet
+	 */
+	fpkt = kmem_zalloc(sizeof (fc_packet_t), KM_SLEEP);
+	fpkt->pkt_cmdlen = 20;
+	fpkt->pkt_cmd = kmem_zalloc(fpkt->pkt_cmdlen, KM_SLEEP);
+	fpkt->pkt_rsplen = 20;
+	fpkt->pkt_resp = kmem_zalloc(fpkt->pkt_rsplen, KM_SLEEP);
+
+	/*
+	 * Link them together
+	 */
+	fpkt->pkt_fca_private = xch;
+	(void) fcoei_init_pkt(ss, fpkt, 0);
+
+	/*
+	 * Initialize FC frame header
+	 */
+	if (ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P) {
+		fpkt->pkt_cmd_fhdr.d_id = ss->ss_p2p_info.d_id;
+	} else {
+		fpkt->pkt_cmd_fhdr.d_id = 0xFFFFFE;
+	}
+
+	fpkt->pkt_cmd_fhdr.s_id = ss->ss_p2p_info.fca_d_id;
+	fpkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
+	fpkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
+	fpkt->pkt_cmd_fhdr.f_ctl = 0x290000;
+	fpkt->pkt_timeout = 1;
+
+	/*
+	 * Initialize LOGO payload
+	 */
+	els_logo = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
+	els_logo->ls_code.ls_code = LA_ELS_LOGO;
+	els_logo->nport_id.port_id = ss->ss_p2p_info.fca_d_id;
+	bcopy(ss->ss_eport->eport_portwwn, &els_logo->nport_ww_name, 8);
+
+	/*
+	 * Set the completion function
+	 */
+	fpkt->pkt_comp = fcoei_fpkt_comp;
+	if (fcoei_transport(ss, fpkt) != FC_SUCCESS) {
+		FCOEI_LOG(__FUNCTION__, "fcoei_transport LOGO failed");
+		fcoei_fpkt_comp(fpkt);
+	}
+}
+
+/*
+ * fcoei_fpkt_comp
+ *	internal exchange completion
+ *
+ * Input:
+ *	fpkt - fc_packet_t to be completed
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *
+ */
+static void
+fcoei_fpkt_comp(fc_packet_t *fpkt)
+{
+	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
+
+	FCOEI_LOG(__FUNCTION__, "internal exchange is completed: %p", xch);
+
+	(void) fcoei_un_init_pkt(xch->xch_ss, xch->xch_fpkt);
+	kmem_free(xch->xch_fpkt->pkt_cmd, xch->xch_fpkt->pkt_cmdlen);
+	kmem_free(xch->xch_fpkt->pkt_resp, xch->xch_fpkt->pkt_rsplen);
+	kmem_free(xch->xch_fpkt, sizeof (fc_packet_t));
+	kmem_free(xch, sizeof (fcoei_exchange_t));
+}
+
+/*
+ * fcoei_xch_abort
+ *	Prepare to abort the exchange
+ *
+ * Input:
+ *	key = oxid/rxid of the exchange
+ *	val = the exchange
+ *	arg = the soft state
+ *
+ * Returns:
+ *	MH_WALK_CONTINUE = continue to walk
+ *
+ * Comments:
+ *	N/A
+ */
+static uint32_t
+fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
+{
+	fcoei_exchange_t	*xch = (fcoei_exchange_t *)val;
+
+	ASSERT(arg == xch->xch_ss);
+	ASSERT(CMHK(key) != 0xFFFF);
+	xch->xch_flags |= XCH_FLAG_ABORT;
+	xch->xch_fpkt->pkt_state = FC_PKT_LOCAL_RJT;
+	xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
+	list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
+	return (MH_WALK_CONTINUE);
+}
+
+/*
+ * fcoei_init_fcatran_vectors
+ *	Initialize fc_fca_tran vectors that are defined in this file
+ *
+ * Input:
+ *	fcatran - fc_fca_tran of the soft state
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+void
+fcoei_init_fcatran_vectors(fc_fca_tran_t *fcatran)
+{
+	fcatran->fca_bind_port	 = fcoei_bind_port;
+	fcatran->fca_unbind_port = fcoei_unbind_port;
+	fcatran->fca_init_pkt	 = fcoei_init_pkt;
+	fcatran->fca_un_init_pkt = fcoei_un_init_pkt;
+	fcatran->fca_els_send	 = fcoei_els_send;
+	fcatran->fca_get_cap	 = fcoei_get_cap;
+	fcatran->fca_set_cap	 = fcoei_set_cap;
+	fcatran->fca_getmap	 = fcoei_getmap;
+	fcatran->fca_transport	 = fcoei_transport;
+	fcatran->fca_ub_alloc	 = fcoei_ub_alloc;
+	fcatran->fca_ub_free	 = fcoei_ub_free;
+	fcatran->fca_ub_release	 = fcoei_ub_release;
+	fcatran->fca_abort	 = fcoei_abort;
+	fcatran->fca_reset	 = fcoei_reset;
+	fcatran->fca_port_manage = fcoei_port_manage;
+	fcatran->fca_get_device	 = fcoei_get_device;
+	fcatran->fca_notify	 = fcoei_notify;
+}
+
+/*
+ * fcoei_process_event_reset
+ *	link reset phase II
+ *
+ * Input:
+ *	arg - fcoei soft state set in fcoei_bind_port
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *
+ */
+void
+fcoei_process_event_reset(fcoei_event_t *ae)
+{
+	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)ae->ae_obj;
+
+	ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
+	kmem_free(ae, sizeof (*ae));
+
+	mod_hash_walk(ss->ss_sol_oxid_hash, fcoei_xch_abort, ss);
+	mod_hash_walk(ss->ss_unsol_rxid_hash, fcoei_xch_abort, ss);
+	fcoei_handle_comp_xch_list(ss);
+
+	/*
+	 * Notify LV that the link is up now
+	 */
+	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0);
+}
+
+/*
+ * fcoei_process_event_exchange
+ *	Process exchange in the single thread context
+ *
+ * Input:
+ *	ae = the exchange event
+ *
+ * Returns:
+ *	N/A
+ *
+ * Comments:
+ *	N/A
+ */
+void
+fcoei_process_event_exchange(fcoei_event_t *ae)
+{
+	fcoei_exchange_t	*xch  = (fcoei_exchange_t *)ae->ae_obj;
+	fcoei_exchange_t	*xch_tmp;
+	fc_packet_t		*fpkt = xch->xch_fpkt;
+
+	/*
+	 * These 4 elements need reset, pkt_state & pkt_reason will be set
+	 */
+	fpkt->pkt_action = 0;
+	fpkt->pkt_expln = 0;
+	fpkt->pkt_data_resid = 0;
+	fpkt->pkt_resp_resid = 0;
+
+	/*
+	 * port state sanity checking
+	 */
+	if ((xch->xch_ss->ss_link_state != FC_STATE_ONLINE) ||
+	    xch->xch_ss->ss_port_event_counter) {
+		/*
+		 * LV will retry it after one second
+		 */
+		fcoei_complete_xch(xch, NULL, FC_PKT_PORT_OFFLINE,
+		    FC_REASON_OFFLINE);
+		return;
+	}
+
+	switch (fpkt->pkt_cmd_fhdr.r_ctl) {
+	case R_CTL_COMMAND:
+		FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
+		fcoei_initiate_fcp_cmd(xch);
+		break;
+
+	case R_CTL_ELS_REQ:
+		FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
+		fcoei_initiate_els_req(xch);
+		break;
+
+	case R_CTL_UNSOL_CONTROL:
+		FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
+		fcoei_initiate_ct_req(xch);
+		break;
+
+	case R_CTL_ELS_RSP:
+		/*
+		 * Caution: in leadville, it still uses pkt_cmd_fhdr
+		 * oxid & rxid have been decided when we get unsolicited frames.
+		 * pkt_cmd_fhdr has contained the right oxid and rxid now.
+		 */
+		FCOEI_INIT_UNSOL_ID_HASH(xch);
+		fcoei_initiate_els_resp(xch);
+		break;
+
+	default:
+		fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE,
+		    FC_REASON_CMD_UNSUPPORTED);
+	}
+}
--- a/usr/src/uts/common/io/fibre-channel/impl/fctl.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fibre-channel/impl/fctl.c	Wed Aug 05 17:14:23 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Fibre channel Transport Library (fctl)
@@ -30,48 +30,48 @@
  *		Internal functions begin with fctl_
  *
  * Fibre channel packet layout:
- *        +---------------------+<--------+
- *        |                     |         |
- *        | ULP Packet private  |         |
- *        |                     |         |
- *        +---------------------+         |
- *        |                     |---------+
- *        |  struct  fc_packet  |---------+
- *        |                     |         |
- *        +---------------------+<--------+
- *        |                     |
- *        | FCA Packet private  |
- *        |                     |
- *        +---------------------+
+ *	  +---------------------+<--------+
+ *	  |			|	  |
+ *	  | ULP Packet private	|	  |
+ *	  |			|	  |
+ *	  +---------------------+	  |
+ *	  |			|---------+
+ *	  |  struct  fc_packet	|---------+
+ *	  |			|	  |
+ *	  +---------------------+<--------+
+ *	  |			|
+ *	  | FCA Packet private	|
+ *	  |			|
+ *	  +---------------------+
  *
- * So you  loved  the  ascii  art ?  It's  strongly  desirable  to  cache
+ * So you  loved  the  ascii  art ?  It's  strongly  desirable	to  cache
  * allocate the entire packet in one common  place.  So we define a set a
- * of rules.  In a  contiguous  block of memory,  the top  portion of the
- * block points to ulp packet  private  area, next follows the  fc_packet
+ * of rules.  In a  contiguous	block of memory,  the top  portion of the
+ * block points to ulp packet  private	area, next follows the	fc_packet
  * structure used  extensively by all the consumers and what follows this
- * is the FCA packet private.  Note that given a packet  structure, it is
- * possible  to get to the  ULP  and  FCA  Packet  private  fields  using
+ * is the FCA packet private.  Note that given a packet	 structure, it is
+ * possible  to get to the  ULP	 and  FCA  Packet  private  fields  using
  * ulp_private and fca_private fields (which hold pointers) respectively.
  *
  * It should be noted with a grain of salt that ULP Packet  private  size
  * varies  between two different  ULP types, So this poses a challenge to
- * compute the correct  size of the whole block on a per port basis.  The
+ * compute the correct	size of the whole block on a per port basis.  The
  * transport  layer  doesn't have a problem in dealing with  FCA   packet
  * private  sizes as it is the sole  manager of ports  underneath.  Since
  * it's not a good idea to cache allocate  different  sizes of memory for
  * different ULPs and have the ability to choose from one of these caches
  * based on ULP type during every packet  allocation,  the transport some
- * what  wisely (?)  hands off this job of cache  allocation  to the ULPs
+ * what	 wisely (?)  hands off this job of cache  allocation  to the ULPs
  * themselves.
  *
  * That means FCAs need to make their  packet  private size  known to the
- * transport   to  pass  it  up  to  the   ULPs.  This  is  done   during
+ * transport   to  pass	 it  up	 to  the   ULPs.  This	is  done   during
  * fc_fca_attach().  And the transport passes this size up to ULPs during
  * fc_ulp_port_attach() of each ULP.
  *
- * This  leaves  us with  another  possible  question;  How  are  packets
- * allocated for ELS's started by the transport  itself ?  Well, the port
- * driver  during  attach  time, cache  allocates  on a per port basis to
+ * This	 leaves	 us with  another  possible  question;	How  are  packets
+ * allocated for ELS's started by the transport	 itself ?  Well, the port
+ * driver  during  attach  time, cache	allocates  on a per port basis to
  * handle ELSs too.
  */
 
@@ -103,8 +103,8 @@
 int did_table_size = D_ID_HASH_TABLE_SIZE;
 int pwwn_table_size = PWWN_HASH_TABLE_SIZE;
 
-static fc_ulp_module_t 	*fctl_ulp_modules;
-static fc_fca_port_t 	*fctl_fca_portlist;
+static fc_ulp_module_t	*fctl_ulp_modules;
+static fc_fca_port_t	*fctl_fca_portlist;
 static fc_ulp_list_t	*fctl_ulp_list;
 
 static char fctl_greeting[] =
@@ -127,7 +127,7 @@
 
 /*
  * fctl_port_lock protects the linked list of local port structures
- * (fctl_fca_portlist).  When walking the list, this lock must be obtained
+ * (fctl_fca_portlist).	 When walking the list, this lock must be obtained
  * prior to any local port locks.
  */
 
@@ -149,10 +149,9 @@
     ulp_ports::port_dstate))
 #endif /* lint */
 
-#define	FCTL_VERSION		"1.69"
+#define	FCTL_VERSION		"20090729-1.70"
 #define	FCTL_NAME_VERSION	"SunFC Transport v" FCTL_VERSION
 
-
 char *fctl_version = FCTL_NAME_VERSION;
 
 extern struct mod_ops mod_miscops;
@@ -201,51 +200,51 @@
 struct kmem_cache *fctl_job_cache;
 
 static fc_errmap_t fc_errlist [] = {
-	{ FC_FAILURE, 		"Operation failed" 			},
-	{ FC_SUCCESS, 		"Operation success" 			},
-	{ FC_CAP_ERROR, 	"Capability error" 			},
-	{ FC_CAP_FOUND, 	"Capability found" 			},
-	{ FC_CAP_SETTABLE, 	"Capability settable" 			},
-	{ FC_UNBOUND, 		"Port not bound" 			},
-	{ FC_NOMEM, 		"No memory" 				},
-	{ FC_BADPACKET, 	"Bad packet" 				},
-	{ FC_OFFLINE, 		"Port offline" 				},
-	{ FC_OLDPORT, 		"Old Port" 				},
-	{ FC_NO_MAP, 		"No map available" 			},
-	{ FC_TRANSPORT_ERROR, 	"Transport error" 			},
-	{ FC_ELS_FREJECT, 	"ELS Frejected" 			},
-	{ FC_ELS_PREJECT, 	"ELS PRejected" 			},
-	{ FC_ELS_BAD, 		"Bad ELS request" 			},
-	{ FC_ELS_MALFORMED, 	"Malformed ELS request" 		},
-	{ FC_TOOMANY, 		"Too many commands" 			},
-	{ FC_UB_BADTOKEN, 	"Bad Unsolicited buffer token" 		},
-	{ FC_UB_ERROR, 		"Unsolicited buffer error" 		},
-	{ FC_UB_BUSY, 		"Unsolicited buffer busy" 		},
-	{ FC_BADULP, 		"Bad ULP" 				},
-	{ FC_BADTYPE, 		"Bad Type" 				},
-	{ FC_UNCLAIMED, 	"Not Claimed" 				},
-	{ FC_ULP_SAMEMODULE, 	"Same ULP Module" 			},
-	{ FC_ULP_SAMETYPE, 	"Same ULP Type" 			},
-	{ FC_ABORTED, 		"Command Aborted" 			},
-	{ FC_ABORT_FAILED, 	"Abort Failed" 				},
-	{ FC_BADEXCHANGE, 	"Bad Exchange" 				},
-	{ FC_BADWWN, 		"Bad World Wide Name" 			},
-	{ FC_BADDEV, 		"Bad Device" 				},
-	{ FC_BADCMD, 		"Bad Command" 				},
-	{ FC_BADOBJECT, 	"Bad Object" 				},
-	{ FC_BADPORT, 		"Bad Port" 				},
-	{ FC_NOTTHISPORT, 	"Not on this Port" 			},
-	{ FC_PREJECT, 		"Operation Prejected" 			},
-	{ FC_FREJECT, 		"Operation Frejected" 			},
-	{ FC_PBUSY, 		"Operation Pbusyed" 			},
-	{ FC_FBUSY, 		"Operation Fbusyed" 			},
-	{ FC_ALREADY, 		"Already done" 				},
-	{ FC_LOGINREQ, 		"PLOGI Required" 			},
-	{ FC_RESETFAIL, 	"Reset operation failed" 		},
-	{ FC_INVALID_REQUEST, 	"Invalid Request" 			},
-	{ FC_OUTOFBOUNDS, 	"Out of Bounds" 			},
-	{ FC_TRAN_BUSY, 	"Command transport Busy" 		},
-	{ FC_STATEC_BUSY, 	"State change Busy" 			},
+	{ FC_FAILURE,		"Operation failed"			},
+	{ FC_SUCCESS,		"Operation success"			},
+	{ FC_CAP_ERROR,		"Capability error"			},
+	{ FC_CAP_FOUND,		"Capability found"			},
+	{ FC_CAP_SETTABLE,	"Capability settable"			},
+	{ FC_UNBOUND,		"Port not bound"			},
+	{ FC_NOMEM,		"No memory"				},
+	{ FC_BADPACKET,		"Bad packet"				},
+	{ FC_OFFLINE,		"Port offline"				},
+	{ FC_OLDPORT,		"Old Port"				},
+	{ FC_NO_MAP,		"No map available"			},
+	{ FC_TRANSPORT_ERROR,	"Transport error"			},
+	{ FC_ELS_FREJECT,	"ELS Frejected"				},
+	{ FC_ELS_PREJECT,	"ELS PRejected"				},
+	{ FC_ELS_BAD,		"Bad ELS request"			},
+	{ FC_ELS_MALFORMED,	"Malformed ELS request"			},
+	{ FC_TOOMANY,		"Too many commands"			},
+	{ FC_UB_BADTOKEN,	"Bad Unsolicited buffer token"		},
+	{ FC_UB_ERROR,		"Unsolicited buffer error"		},
+	{ FC_UB_BUSY,		"Unsolicited buffer busy"		},
+	{ FC_BADULP,		"Bad ULP"				},
+	{ FC_BADTYPE,		"Bad Type"				},
+	{ FC_UNCLAIMED,		"Not Claimed"				},
+	{ FC_ULP_SAMEMODULE,	"Same ULP Module"			},
+	{ FC_ULP_SAMETYPE,	"Same ULP Type"				},
+	{ FC_ABORTED,		"Command Aborted"			},
+	{ FC_ABORT_FAILED,	"Abort Failed"				},
+	{ FC_BADEXCHANGE,	"Bad Exchange"				},
+	{ FC_BADWWN,		"Bad World Wide Name"			},
+	{ FC_BADDEV,		"Bad Device"				},
+	{ FC_BADCMD,		"Bad Command"				},
+	{ FC_BADOBJECT,		"Bad Object"				},
+	{ FC_BADPORT,		"Bad Port"				},
+	{ FC_NOTTHISPORT,	"Not on this Port"			},
+	{ FC_PREJECT,		"Operation Prejected"			},
+	{ FC_FREJECT,		"Operation Frejected"			},
+	{ FC_PBUSY,		"Operation Pbusyed"			},
+	{ FC_FBUSY,		"Operation Fbusyed"			},
+	{ FC_ALREADY,		"Already done"				},
+	{ FC_LOGINREQ,		"PLOGI Required"			},
+	{ FC_RESETFAIL,		"Reset operation failed"		},
+	{ FC_INVALID_REQUEST,	"Invalid Request"			},
+	{ FC_OUTOFBOUNDS,	"Out of Bounds"				},
+	{ FC_TRAN_BUSY,		"Command transport Busy"		},
+	{ FC_STATEC_BUSY,	"State change Busy"			},
 	{ FC_DEVICE_BUSY,	"Port driver is working on this device"	}
 };
 
@@ -256,7 +255,7 @@
 };
 
 fc_pkt_reason_t general_reasons [] = {
-	{ FC_REASON_HW_ERROR,		"Hardware Error" 		},
+	{ FC_REASON_HW_ERROR,		"Hardware Error"		},
 	{ FC_REASON_SEQ_TIMEOUT,	"Sequence Timeout"		},
 	{ FC_REASON_ABORTED,		"Aborted"			},
 	{ FC_REASON_ABORT_FAILED,	"Abort Failed"			},
@@ -292,7 +291,7 @@
 	{ FC_REASON_PERM_UNAVAILABLE,	"Permamnently Unavailable"	},
 	{ FC_REASON_CLASS_NOT_SUPP,	"Class Not Supported",		},
 	{ FC_REASON_DELIMTER_USAGE_ERROR,
-					"Delimeter Usage Error"		},
+	    "Delimeter Usage Error"		},
 	{ FC_REASON_TYPE_NOT_SUPP,	"Type Not Supported"		},
 	{ FC_REASON_INVALID_LINK_CTRL,	"Invalid Link Control"		},
 	{ FC_REASON_INVALID_R_CTL,	"Invalid R_CTL"			},
@@ -307,13 +306,13 @@
 	{ FC_REASON_PROTOCOL_ERROR,	"Protocol Error"		},
 	{ FC_REASON_INCORRECT_LENGTH,	"Incorrect Length"		},
 	{ FC_REASON_UNEXPECTED_ACK,	"Unexpected Ack"		},
-	{ FC_REASON_UNEXPECTED_LR,	"Unexpected Link reset" 	},
+	{ FC_REASON_UNEXPECTED_LR,	"Unexpected Link reset"		},
 	{ FC_REASON_LOGIN_REQUIRED,	"Login Required"		},
 	{ FC_REASON_EXCESSIVE_SEQS,	"Excessive Sequences"
-					" Attempted"			},
+	    " Attempted"			},
 	{ FC_REASON_EXCH_UNABLE,	"Exchange incapable"		},
 	{ FC_REASON_ESH_NOT_SUPP,	"Expiration Security Header "
-					"Not Supported"			},
+	    "Not Supported"			},
 	{ FC_REASON_NO_FABRIC_PATH,	"No Fabric Path"		},
 	{ FC_REASON_VENDOR_UNIQUE,	"Vendor Unique"			},
 	{ FC_REASON_INVALID,		NULL				}
@@ -384,10 +383,10 @@
 		NULL
 	},
 	{	FC_PKT_REMOTE_STOP,
-		"Remote Stop",
-		remote_stop_reasons,
-		NULL,
-		NULL
+	    "Remote Stop",
+	    remote_stop_reasons,
+	    NULL,
+	    NULL
 	},
 	{
 		FC_PKT_LOCAL_RJT,
@@ -608,9 +607,9 @@
  *		FC_SUCCESS
  *		FC_FAILURE
  *
- *   fc_ulp_add  prints  a warning message if there is  already a
+ *   fc_ulp_add	 prints	 a warning message if there is	already a
  *   similar ULP type  attached and this is unlikely to change as
- *   we trudge along.  Further, this  function  returns a failure
+ *   we trudge along.  Further, this  function	returns a failure
  *   code if the same  module  attempts to add more than once for
  *   the same FC-4 type.
  */
@@ -619,9 +618,9 @@
 {
 	fc_ulp_module_t *mod;
 	fc_ulp_module_t *prev;
-	job_request_t 	*job;
+	job_request_t	*job;
 	fc_ulp_list_t	*new;
-	fc_fca_port_t 	*fca_port;
+	fc_fca_port_t	*fca_port;
 	int		ntry = 0;
 
 	ASSERT(ulp_info != NULL);
@@ -653,8 +652,8 @@
 	while (rw_tryenter(&fctl_ulp_lock, RW_WRITER) == 0) {
 		delay(drv_usectohz(1000000));
 		if (ntry++ > FC_ULP_ADD_RETRY_COUNT) {
-			fc_ulp_list_t   *list;
-			fc_ulp_list_t   *last;
+			fc_ulp_list_t	*list;
+			fc_ulp_list_t	*last;
 			mutex_enter(&fctl_ulp_list_mutex);
 			for (last = NULL, list = fctl_ulp_list; list != NULL;
 			    list = list->ulp_next) {
@@ -712,7 +711,6 @@
 	mutex_enter(&fctl_port_lock);
 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
 	    fca_port = fca_port->port_next) {
-
 		job = fctl_alloc_job(JOB_ATTACH_ULP, JOB_TYPE_FCTL_ASYNC,
 		    NULL, NULL, KM_SLEEP);
 
@@ -816,7 +814,7 @@
  * The caller is required to ensure that pkt_pd is populated with the
  * handle that it was given when the transport notified it about the
  * device this packet is associated with.  If there is no associated
- * device, pkt_pd must be set to NULL.  A non-NULL pkt_pd will cause an
+ * device, pkt_pd must be set to NULL.	A non-NULL pkt_pd will cause an
  * increment of the reference count for said pd.  When the packet is freed,
  * the reference count will be decremented.  This reference count, in
  * combination with the PD_GIVEN_TO_ULPS flag guarantees that the pd
@@ -1037,11 +1035,11 @@
 fc_ulp_login(opaque_t port_handle, fc_packet_t **ulp_pkt, uint32_t listlen)
 {
 	int			rval = FC_SUCCESS;
-	int 			job_flags;
+	int			job_flags;
 	uint32_t		count;
 	fc_packet_t		**tmp_array;
-	job_request_t 		*job;
-	fc_local_port_t 	*port = port_handle;
+	job_request_t		*job;
+	fc_local_port_t		*port = port_handle;
 	fc_ulp_rscn_info_t	*rscnp =
 	    (fc_ulp_rscn_info_t *)(ulp_pkt[0])->pkt_ulp_rscn_infop;
 
@@ -1153,9 +1151,9 @@
 fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
     int create)
 {
-	fc_local_port_t 	*port;
+	fc_local_port_t		*port;
 	job_request_t		*job;
-	fc_remote_port_t 	*pd;
+	fc_remote_port_t	*pd;
 
 	port = port_handle;
 	pd = fctl_get_remote_port_by_pwwn(port, pwwn);
@@ -1174,7 +1172,7 @@
 	mutex_enter(&port->fp_mutex);
 	if (FC_IS_TOP_SWITCH(port->fp_topology) && create) {
 		uint32_t	d_id;
-		fctl_ns_req_t 	*ns_cmd;
+		fctl_ns_req_t	*ns_cmd;
 
 		mutex_exit(&port->fp_mutex);
 
@@ -1272,7 +1270,7 @@
 int
 fc_ulp_port_ns(opaque_t port_handle, opaque_t pd, fc_ns_cmd_t *ns_req)
 {
-	int 		rval;
+	int		rval;
 	int		fabric;
 	job_request_t	*job;
 	fctl_ns_req_t	*ns_cmd;
@@ -1357,7 +1355,7 @@
 fc_ulp_transport(opaque_t port_handle, fc_packet_t *pkt)
 {
 	int			rval;
-	fc_local_port_t 	*port;
+	fc_local_port_t		*port;
 	fc_remote_port_t	*pd, *newpd;
 	fc_ulp_rscn_info_t	*rscnp =
 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
@@ -1480,7 +1478,7 @@
 fc_ulp_issue_els(opaque_t port_handle, fc_packet_t *pkt)
 {
 	int			rval;
-	fc_local_port_t 	*port = port_handle;
+	fc_local_port_t		*port = port_handle;
 	fc_remote_port_t	*pd;
 	fc_ulp_rscn_info_t	*rscnp =
 	    (fc_ulp_rscn_info_t *)pkt->pkt_ulp_rscn_infop;
@@ -1723,7 +1721,7 @@
 fc_ulp_get_port_handle(int port_instance)
 {
 	opaque_t	port_handle = NULL;
-	fc_fca_port_t 	*cur;
+	fc_fca_port_t	*cur;
 
 	mutex_enter(&fctl_port_lock);
 	for (cur = fctl_fca_portlist; cur; cur = cur->port_next) {
@@ -1805,7 +1803,7 @@
 {
 	fc_local_port_t		*port = port_handle;
 	fc_remote_node_t	*node;
-	fc_remote_port_t 	*pd;
+	fc_remote_port_t	*pd;
 
 	pd = fctl_get_remote_port_by_pwwn(port, bytes);
 	if (pd == NULL) {
@@ -1905,7 +1903,7 @@
 
 /*
  * fc_fca_init
- * 		Overload the FCA bus_ops vector in its dev_ops with
+ *		Overload the FCA bus_ops vector in its dev_ops with
  *		fctl_fca_busops to handle all the INITchilds for "sf"
  *		in one common place.
  *
@@ -2077,8 +2075,8 @@
 	*str = '\0';
 }
 
-#define	FC_ATOB(x)	(((x) >= '0' && (x) <= '9') ? ((x) - '0') :\
-			((x) >= 'a' && (x) <= 'f') ?\
+#define	FC_ATOB(x)	(((x) >= '0' && (x) <= '9') ? ((x) - '0') :	\
+			((x) >= 'a' && (x) <= 'f') ?			\
 			((x) - 'a' + 10) : ((x) - 'A' + 10))
 
 void
@@ -2101,7 +2099,7 @@
  */
 static int
 fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
-	ddi_ctl_enum_t op, void *arg, void *result)
+    ddi_ctl_enum_t op, void *arg, void *result)
 {
 	switch (op) {
 	case DDI_CTLOPS_REPORTDEV:
@@ -2133,11 +2131,11 @@
 static int
 fctl_initchild(dev_info_t *fca_dip, dev_info_t *port_dip)
 {
-	int 		rval;
-	int 		port_no;
-	int 		port_len;
-	char 		name[20];
-	fc_fca_tran_t 	*tran;
+	int		rval;
+	int		port_no;
+	int		port_len;
+	char		name[20];
+	fc_fca_tran_t	*tran;
 	dev_info_t	*dip;
 	int		portprop;
 
@@ -2218,8 +2216,9 @@
 
 	for (dip = ddi_get_child(pdip); dip != NULL;
 	    dip = ddi_get_next_sibling(dip)) {
-		if (strcmp(cname, ddi_node_name(dip)) != 0)
+		if (strcmp(cname, ddi_node_name(dip)) != 0) {
 			continue;
+		}
 
 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
@@ -2232,8 +2231,9 @@
 				ddi_prop_free(addr);
 			}
 		} else {
-			if (strcmp(caddr, addr) == 0)
+			if (strcmp(caddr, addr) == 0) {
 				return (dip);
+			}
 		}
 	}
 
@@ -2308,7 +2308,7 @@
     dev_info_t *phydip, char *nname, char *pname, uint32_t *vindex)
 {
 	int rval = 0, devstrlen;
-	char    *devname, *cname, *caddr, *devstr;
+	char	*devname, *cname, *caddr, *devstr;
 	dev_info_t	*child = NULL;
 	int		portnum;
 
@@ -2425,9 +2425,9 @@
 void
 fctl_remove_port(fc_local_port_t *port)
 {
-	fc_ulp_module_t 	*mod;
-	fc_fca_port_t 		*prev;
-	fc_fca_port_t 		*list;
+	fc_ulp_module_t		*mod;
+	fc_fca_port_t		*prev;
+	fc_fca_port_t		*list;
 	fc_ulp_ports_t		*ulp_port;
 
 	rw_enter(&fctl_ulp_lock, RW_WRITER);
@@ -2477,8 +2477,8 @@
 	int			rval;
 	uint32_t		s_id;
 	uint32_t		state;
-	fc_ulp_module_t 	*mod;
-	fc_ulp_port_info_t 	info;
+	fc_ulp_module_t		*mod;
+	fc_ulp_port_info_t	info;
 	fc_ulp_ports_t		*ulp_port;
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
@@ -2531,14 +2531,22 @@
 	rw_enter(&fctl_mod_ports_lock, RW_WRITER);
 
 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
+		if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
+		    (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
+			/*
+			 * We don't support IP over FC on FCOE HBA
+			 */
+			continue;
+		}
+
 		if ((ulp_port = fctl_get_ulp_port(mod, port)) == NULL) {
 			ulp_port = fctl_add_ulp_port(mod, port, KM_SLEEP);
 			ASSERT(ulp_port != NULL);
 
 			mutex_enter(&ulp_port->port_mutex);
-			ulp_port->port_statec = (info.port_state &
+			ulp_port->port_statec = ((info.port_state &
 			    FC_STATE_ONLINE) ? FC_ULP_STATEC_ONLINE :
-			    FC_ULP_STATEC_OFFLINE;
+			    FC_ULP_STATEC_OFFLINE);
 			mutex_exit(&ulp_port->port_mutex);
 		}
 	}
@@ -2546,6 +2554,14 @@
 	rw_downgrade(&fctl_mod_ports_lock);
 
 	for (mod = fctl_ulp_modules; mod; mod = mod->mod_next) {
+		if ((port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) &&
+		    (mod->mod_info->ulp_type == FC_TYPE_IS8802_SNAP)) {
+			/*
+			 * We don't support IP over FC on FCOE HBA
+			 */
+			continue;
+		}
+
 		ulp_port = fctl_get_ulp_port(mod, port);
 		ASSERT(ulp_port != NULL);
 
@@ -2674,8 +2690,8 @@
     struct modlinkage *linkage)
 {
 	int			rval = FC_SUCCESS;
-	fc_ulp_module_t 	*mod;
-	fc_ulp_port_info_t 	info;
+	fc_ulp_module_t		*mod;
+	fc_ulp_port_info_t	info;
 	fc_ulp_ports_t		*ulp_port;
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
@@ -2727,36 +2743,36 @@
 
 static	void
 fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
-    fc_ulp_port_info_t 	*info)
+    fc_ulp_port_info_t	*info)
 {
 
-		if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
-		    (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
-			info->port_cmd_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcp_cmd_attr;
-			info->port_data_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcp_data_attr;
-			info->port_resp_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcp_rsp_attr;
-		} else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
-			info->port_cmd_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
-			info->port_data_dma_attr =
-			    port->fp_fca_tran->fca_dma_attr;
-			info->port_resp_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
-		} else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
-			info->port_cmd_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcip_cmd_attr;
-			info->port_data_dma_attr =
-			    port->fp_fca_tran->fca_dma_attr;
-			info->port_resp_dma_attr =
-			    port->fp_fca_tran->fca_dma_fcip_rsp_attr;
-		} else {
-			info->port_cmd_dma_attr = info->port_data_dma_attr =
-			    info->port_resp_dma_attr =
-			    port->fp_fca_tran->fca_dma_attr; /* default */
-		}
+	if ((strcmp(mod->mod_info->ulp_name, "fcp") == 0) ||
+	    (strcmp(mod->mod_info->ulp_name, "ltct") == 0)) {
+		info->port_cmd_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcp_cmd_attr;
+		info->port_data_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcp_data_attr;
+		info->port_resp_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcp_rsp_attr;
+	} else if (strcmp(mod->mod_info->ulp_name, "fcsm") == 0) {
+		info->port_cmd_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcsm_cmd_attr;
+		info->port_data_dma_attr =
+		    port->fp_fca_tran->fca_dma_attr;
+		info->port_resp_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcsm_rsp_attr;
+	} else if (strcmp(mod->mod_info->ulp_name, "fcip") == 0) {
+		info->port_cmd_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcip_cmd_attr;
+		info->port_data_dma_attr =
+		    port->fp_fca_tran->fca_dma_attr;
+		info->port_resp_dma_attr =
+		    port->fp_fca_tran->fca_dma_fcip_rsp_attr;
+	} else {
+		info->port_cmd_dma_attr = info->port_data_dma_attr =
+		    info->port_resp_dma_attr =
+		    port->fp_fca_tran->fca_dma_attr; /* default */
+	}
 }
 
 static int
@@ -2984,8 +3000,8 @@
 	uint32_t		new_state;
 	fc_local_port_t		*port;
 	fc_ulp_ports_t		*ulp_port;
-	fc_ulp_module_t 	*mod;
-	fc_port_clist_t 	*clist = (fc_port_clist_t *)arg;
+	fc_ulp_module_t		*mod;
+	fc_port_clist_t		*clist = (fc_port_clist_t *)arg;
 
 	ASSERT(clist != NULL);
 
@@ -3018,15 +3034,15 @@
 	 * sanity check for presence of OLD devices in the hash lists
 	 */
 	if (clist->clist_size) {
-		int 			count;
+		int			count;
 		fc_remote_port_t	*pd;
 
 		ASSERT(clist->clist_map != NULL);
 		for (count = 0; count < clist->clist_len; count++) {
 			if (clist->clist_map[count].map_state ==
 			    PORT_DEVICE_INVALID) {
-				la_wwn_t 	pwwn;
-				fc_portid_t 	d_id;
+				la_wwn_t	pwwn;
+				fc_portid_t	d_id;
 
 				pd = clist->clist_map[count].map_pd;
 				if (pd != NULL) {
@@ -3055,7 +3071,7 @@
 	 * Check for duplicate map entries
 	 */
 	if (clist->clist_size) {
-		int 			count;
+		int			count;
 		fc_remote_port_t	*pd1, *pd2;
 
 		ASSERT(clist->clist_map != NULL);
@@ -3142,7 +3158,7 @@
 	rw_exit(&fctl_ulp_lock);
 
 	if (clist->clist_size) {
-		int 			count;
+		int			count;
 		fc_remote_node_t	*node;
 		fc_remote_port_t	*pd;
 
@@ -3197,7 +3213,7 @@
 
 /*
  * Allocate an fc_remote_node_t struct to represent a remote node for the
- * given nwwn.  This will also add the nwwn to the global nwwn table.
+ * given nwwn.	This will also add the nwwn to the global nwwn table.
  *
  * Returns a pointer to the newly-allocated struct.  Returns NULL if
  * the kmem_zalloc fails or if the enlist_wwn attempt fails.
@@ -3264,9 +3280,9 @@
 int
 fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
 {
-	int 			index;
-	fctl_nwwn_elem_t 	*new;
-	fctl_nwwn_list_t 	*head;
+	int			index;
+	fctl_nwwn_elem_t	*new;
+	fctl_nwwn_list_t	*head;
 
 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
 
@@ -3302,10 +3318,10 @@
 void
 fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
 {
-	int 			index;
-	fctl_nwwn_list_t 	*head;
-	fctl_nwwn_elem_t 	*elem;
-	fctl_nwwn_elem_t 	*prev;
+	int			index;
+	fctl_nwwn_list_t	*head;
+	fctl_nwwn_elem_t	*elem;
+	fctl_nwwn_elem_t	*prev;
 
 	ASSERT(MUTEX_HELD(&fctl_nwwn_hash_mutex));
 	ASSERT(MUTEX_HELD(&rnodep->fd_mutex));
@@ -3355,10 +3371,10 @@
 fc_remote_node_t *
 fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
 {
-	int 			index;
-	fctl_nwwn_elem_t 	*elem;
+	int			index;
+	fctl_nwwn_elem_t	*elem;
 	fc_remote_node_t	*next;
-	fc_remote_node_t 	*rnodep = NULL;
+	fc_remote_node_t	*rnodep = NULL;
 
 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
 	    fctl_nwwn_table_size);
@@ -3395,10 +3411,10 @@
 fc_remote_node_t *
 fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
 {
-	int 			index;
-	fctl_nwwn_elem_t 	*elem;
+	int			index;
+	fctl_nwwn_elem_t	*elem;
 	fc_remote_node_t	*next;
-	fc_remote_node_t 	*rnodep = NULL;
+	fc_remote_node_t	*rnodep = NULL;
 
 	index = HASH_FUNC(WWN_HASH_KEY(node_wwn->raw_wwn),
 	    fctl_nwwn_table_size);
@@ -3428,7 +3444,7 @@
 
 /*
  * Allocate and initialize an fc_remote_port_t struct & returns a pointer to
- * the newly allocated struct.  Only fails if the kmem_zalloc() fails.
+ * the newly allocated struct.	Only fails if the kmem_zalloc() fails.
  */
 fc_remote_port_t *
 fctl_alloc_remote_port(fc_local_port_t *port, la_wwn_t *port_wwn,
@@ -3535,8 +3551,8 @@
     fc_remote_port_t *pd)
 {
 	int			rcount = 0;
-	fc_remote_port_t 	*last;
-	fc_remote_port_t 	*ports;
+	fc_remote_port_t	*last;
+	fc_remote_port_t	*ports;
 
 	ASSERT(!MUTEX_HELD(&rnodep->fd_mutex));
 	ASSERT(!MUTEX_HELD(&pd->pd_mutex));
@@ -3613,7 +3629,7 @@
 #ifdef	DEBUG
 	{
 		int			index;
-		fc_remote_port_t 	*tmp_pd;
+		fc_remote_port_t	*tmp_pd;
 		struct d_id_hash	*tmp_head;
 
 		/*
@@ -3663,9 +3679,9 @@
 fctl_delist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
 {
 	uint32_t		d_id;
-	struct d_id_hash 	*head;
-	fc_remote_port_t 	*pd_next;
-	fc_remote_port_t 	*last;
+	struct d_id_hash	*head;
+	fc_remote_port_t	*pd_next;
+	fc_remote_port_t	*last;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
@@ -3726,7 +3742,7 @@
 #ifdef	DEBUG
 	{
 		int			index;
-		fc_remote_port_t 	*tmp_pd;
+		fc_remote_port_t	*tmp_pd;
 		struct pwwn_hash	*tmp_head;
 
 		/*
@@ -3781,9 +3797,9 @@
 {
 	int			index;
 	la_wwn_t		pwwn;
-	struct pwwn_hash 	*head;
-	fc_remote_port_t 	*pd_next;
-	fc_remote_port_t 	*last;
+	struct pwwn_hash	*head;
+	fc_remote_port_t	*pd_next;
+	fc_remote_port_t	*last;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
 	ASSERT(MUTEX_HELD(&pd->pd_mutex));
@@ -3835,8 +3851,8 @@
 fc_remote_port_t *
 fctl_get_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
 {
-	struct d_id_hash 	*head;
-	fc_remote_port_t 	*pd;
+	struct d_id_hash	*head;
+	fc_remote_port_t	*pd;
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
 
@@ -3888,8 +3904,8 @@
 fc_remote_port_t *
 fctl_hold_remote_port_by_did(fc_local_port_t *port, uint32_t d_id)
 {
-	struct d_id_hash 	*head;
-	fc_remote_port_t 	*pd;
+	struct d_id_hash	*head;
+	fc_remote_port_t	*pd;
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
 
@@ -3929,8 +3945,8 @@
 fctl_get_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
 {
 	int			index;
-	struct pwwn_hash 	*head;
-	fc_remote_port_t 	*pd;
+	struct pwwn_hash	*head;
+	fc_remote_port_t	*pd;
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
 
@@ -3964,8 +3980,8 @@
 fctl_get_remote_port_by_pwwn_mutex_held(fc_local_port_t *port, la_wwn_t *pwwn)
 {
 	int			index;
-	struct pwwn_hash 	*head;
-	fc_remote_port_t 	*pd;
+	struct pwwn_hash	*head;
+	fc_remote_port_t	*pd;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
 
@@ -4002,8 +4018,8 @@
 fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
 {
 	int			index;
-	struct pwwn_hash 	*head;
-	fc_remote_port_t 	*pd;
+	struct pwwn_hash	*head;
+	fc_remote_port_t	*pd;
 
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
 
@@ -4043,15 +4059,15 @@
  * PD_ELS_IN_PROGRESS & PD_ELS_MARK settings in the pd_flags), then
  * fctl_destroy_remote_port_t() is called to deconstruct/free the given
  * fc_remote_port_t (which will also remove it from the d_id and pwwn tables
- * on the associated fc_local_port_t).  If the associated fc_remote_node_t is no
+ * on the associated fc_local_port_t).	If the associated fc_remote_node_t is no
  * longer in use, then it too is deconstructed/freed.
  */
 void
 fctl_release_remote_port(fc_remote_port_t *pd)
 {
 	int			remove = 0;
-	fc_remote_node_t 	*node;
-	fc_local_port_t 	*port;
+	fc_remote_node_t	*node;
+	fc_local_port_t		*port;
 
 	mutex_enter(&pd->pd_mutex);
 	port = pd->pd_port;
@@ -4099,9 +4115,9 @@
 	int			full_list;
 	int			initiator;
 	uint32_t		topology;
-	struct pwwn_hash 	*head;
-	fc_remote_port_t 	*pd;
-	fc_remote_port_t 	*old_pd;
+	struct pwwn_hash	*head;
+	fc_remote_port_t	*pd;
+	fc_remote_port_t	*old_pd;
 	fc_remote_port_t	*last_pd;
 	fc_portmap_t		*listptr;
 
@@ -4390,11 +4406,8 @@
 
 
 /*
- * Compare two WWNs. The NAA is omitted for comparison.
- *
- * Note particularly that the indentation used in this
- * function  isn't according to Sun recommendations. It
- * is indented to make reading a bit easy.
+ * Compare two WWNs.
+ * The NAA can't be omitted for comparison.
  *
  * Return Values:
  *   if src == dst return  0
@@ -4404,25 +4417,29 @@
 int
 fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst)
 {
-	la_wwn_t tmpsrc, tmpdst;
-
-	/*
-	 * Fibre Channel protocol is big endian, so compare
-	 * as big endian values
-	 */
-	tmpsrc.i_wwn[0] = BE_32(src->i_wwn[0]);
-	tmpsrc.i_wwn[1] = BE_32(src->i_wwn[1]);
-
-	tmpdst.i_wwn[0] = BE_32(dst->i_wwn[0]);
-	tmpdst.i_wwn[1] = BE_32(dst->i_wwn[1]);
-
-	return (
-	    (tmpsrc.w.nport_id == tmpdst.w.nport_id) ?
-		((tmpsrc.w.wwn_hi == tmpdst.w.wwn_hi) ?
-		    ((tmpsrc.w.wwn_lo == tmpdst.w.wwn_lo) ? 0 :
-		    (tmpsrc.w.wwn_lo > tmpdst.w.wwn_lo) ? 1 : -1) :
-		(tmpsrc.w.wwn_hi > tmpdst.w.wwn_hi) ? 1 : -1) :
-	    (tmpsrc.w.nport_id > tmpdst.w.nport_id) ? 1 : -1);
+	uint8_t *l, *r;
+	int i;
+	uint64_t wl, wr;
+
+	l = (uint8_t *)src;
+	r = (uint8_t *)dst;
+
+	for (i = 0, wl = 0; i < 8; i++) {
+		wl <<= 8;
+		wl |= l[i];
+	}
+	for (i = 0, wr = 0; i < 8; i++) {
+		wr <<= 8;
+		wr |= r[i];
+	}
+
+	if (wl > wr) {
+		return (1);
+	} else if (wl == wr) {
+		return (0);
+	} else {
+		return (-1);
+	}
 }
 
 
@@ -4499,7 +4516,7 @@
 {
 	int			invalid = 0;
 	fc_remote_node_t	*rnodep;
-	fc_remote_port_t 	*pd;
+	fc_remote_port_t	*pd;
 
 	rnodep = fctl_get_remote_node_by_nwwn(node_wwn);
 	if (rnodep) {
@@ -4526,7 +4543,7 @@
 
 	/*
 	 * See if there already is an fc_remote_port_t struct in existence
-	 * on the specified fc_local_port_t for the given pwwn.  If so, then
+	 * on the specified fc_local_port_t for the given pwwn.	 If so, then
 	 * grab a reference to it. The 'held' here just means that fp_mutex
 	 * is held by the caller -- no reference counts are updated.
 	 */
@@ -4643,7 +4660,7 @@
 			 * OK the old & new d_id's match, and the remote
 			 * port struct is not marked as PORT_DEVICE_OLD, so
 			 * presume that it's still the same device and is
-			 * still in good shape.  Also this presumes that we
+			 * still in good shape.	 Also this presumes that we
 			 * do not need to update d_id or pwwn hash tables.
 			 */
 			/* sanitize device values */
@@ -4684,7 +4701,7 @@
 	}
 
 	/*
-	 * Add  the fc_remote_port_t onto the linked list of remote port
+	 * Add	the fc_remote_port_t onto the linked list of remote port
 	 * devices associated with the given fc_remote_node_t (remote node).
 	 */
 	fctl_link_remote_port_to_remote_node(rnodep, pd);
@@ -4705,7 +4722,7 @@
  * If pd_ref_count in the given fc_remote_port_t is nonzero, then this
  * function just sets the pd->pd_aux_flags |= PD_NEEDS_REMOVAL and the
  * pd->pd_type = PORT_DEVICE_OLD and lets some other function(s) worry about
- * the cleanup.  The function then also returns '1'
+ * the cleanup.	 The function then also returns '1'
  * instead of the actual number of remaining fc_remote_port_t structs
  *
  * If there are no more remote ports on the remote node, return 0.
@@ -4714,7 +4731,7 @@
 int
 fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
 {
-	fc_remote_node_t 	*rnodep;
+	fc_remote_node_t	*rnodep;
 	int			rcount = 0;
 
 	mutex_enter(&pd->pd_mutex);
@@ -4775,7 +4792,7 @@
  * For each fc_remote_port_t found, this will:
  *
  *  - Remove the fc_remote_port_t from the linked list of remote ports for
- *    the associated fc_remote_node_t.  If the linked list goes empty, then this
+ *    the associated fc_remote_node_t.	If the linked list goes empty, then this
  *    tries to deconstruct & free the fc_remote_node_t (that also removes the
  *    fc_remote_node_t from the global fctl_nwwn_hash_table[]).
  *
@@ -4793,7 +4810,7 @@
 	int			index;
 	fc_remote_port_t	*pd;
 	fc_remote_node_t	*rnodep;
-	struct d_id_hash 	*head;
+	struct d_id_hash	*head;
 
 	mutex_enter(&port->fp_mutex);
 
@@ -4889,7 +4906,7 @@
 	int			check_type;
 	int			rval;
 	uint32_t		claimed;
-	fc_ulp_module_t 	*mod;
+	fc_ulp_module_t		*mod;
 	fc_ulp_ports_t		*ulp_port;
 
 	claimed = 0;
@@ -5048,14 +5065,14 @@
 static int
 fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
 {
-	int 	rval = FC_SUCCESS;
+	int	rval = FC_SUCCESS;
 
 	switch (ns_req->ns_cmd) {
 	case NS_RFT_ID: {
 		int		count;
 		uint32_t	*src;
 		uint32_t	*dst;
-		ns_rfc_type_t 	*rfc;
+		ns_rfc_type_t	*rfc;
 
 		rfc = (ns_rfc_type_t *)ns_req->ns_req_payload;
 
@@ -5140,7 +5157,7 @@
 static int
 fctl_retrieve_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
 {
-	int 	rval = FC_SUCCESS;
+	int	rval = FC_SUCCESS;
 
 	switch (ns_req->ns_cmd) {
 	case NS_GFT_ID: {
@@ -5279,8 +5296,8 @@
 {
 	int			ret;
 	int			save;
-	uint32_t 		claimed;
-	fc_ulp_module_t 	*mod;
+	uint32_t		claimed;
+	fc_ulp_module_t		*mod;
 	fc_ulp_ports_t		*ulp_port;
 
 	save = *rval;
@@ -5456,14 +5473,14 @@
  * only ONE port on the adapter will be returned.
  * pathList should be (count * MAXPATHLEN) long.
  * The return value will be set to the number of
- * HBAs that were found on the system.  If the value
+ * HBAs that were found on the system.	If the value
  * is greater than count, the routine should be retried
  * with a larger buffer.
  */
 int
 fc_ulp_get_adapter_paths(char *pathList, int count)
 {
-	fc_fca_port_t 	*fca_port;
+	fc_fca_port_t	*fca_port;
 	int		in = 0, out = 0, check, skip, maxPorts = 0;
 	fc_local_port_t		**portList;
 	fc_local_port_t		*new_port, *stored_port;
@@ -5493,67 +5510,73 @@
 
 		/* Filter out secondary ports from the list */
 		for (check = 0; check < out; check++) {
-		if (portList[check] == NULL) {
-			continue;
-		}
-		/* Guard against duplicates (should never happen) */
-		if (portList[check] == fca_port->port_handle) {
-			/* Same port */
-			skip = 1;
-			break;
-		}
-
-		/* Lock the already stored port for comparison */
-		stored_port = portList[check];
-		mutex_enter(&stored_port->fp_mutex);
-		stored_fru = &stored_port->fp_hba_port_attrs.hba_fru_details;
-
-		/* Are these ports on the same HBA? */
-		if (new_fru->high == stored_fru->high &&
-			new_fru->low == stored_fru->low) {
-		    /* Now double check driver */
-		    if (strncmp(new_port->fp_hba_port_attrs.driver_name,
-			    stored_port->fp_hba_port_attrs.driver_name,
-			    FCHBA_DRIVER_NAME_LEN) == 0) {
-			/* we no we don't need to grow the list */
-			skip = 1;
-			/* Are we looking at a lower port index? */
-			if (new_fru->port_index < stored_fru->port_index) {
-				/* Replace the port in the list */
-				mutex_exit(&stored_port->fp_mutex);
-				if (new_port->fp_npiv_type == FC_NPIV_PORT) {
-					break;
+			if (portList[check] == NULL) {
+				continue;
+			}
+			/* Guard against duplicates (should never happen) */
+			if (portList[check] == fca_port->port_handle) {
+				/* Same port */
+				skip = 1;
+				break;
+			}
+
+			/* Lock the already stored port for comparison */
+			stored_port = portList[check];
+			mutex_enter(&stored_port->fp_mutex);
+			stored_fru =
+			    &stored_port->fp_hba_port_attrs.hba_fru_details;
+
+			/* Are these ports on the same HBA? */
+			if (new_fru->high == stored_fru->high &&
+			    new_fru->low == stored_fru->low) {
+				/* Now double check driver */
+				if (strncmp(
+				    new_port->fp_hba_port_attrs.driver_name,
+				    stored_port->fp_hba_port_attrs.driver_name,
+				    FCHBA_DRIVER_NAME_LEN) == 0) {
+					/* we don't need to grow the list */
+					skip = 1;
+					/* looking at a lower port index? */
+					if (new_fru->port_index <
+					    stored_fru->port_index) {
+						/* Replace the port in list */
+						mutex_exit(
+						    &stored_port->fp_mutex);
+						if (new_port->fp_npiv_type ==
+						    FC_NPIV_PORT) {
+							break;
+						}
+						portList[check] = new_port;
+						break;
+					} /* Else, just skip this port */
 				}
-				portList[check] = new_port;
-				break;
-			} /* Else, just skip this port */
-		    }
-		}
-
-		mutex_exit(&stored_port->fp_mutex);
-	    }
-	    mutex_exit(&new_port->fp_mutex);
-
-	    if (!skip) {
-		/*
-		 * Either this is the first port for this HBA, or
-		 * it's a secondary port and we haven't stored the
-		 * primary/first port for that HBA.  In the latter case,
-		 * will just filter it out as we proceed to loop.
-		 */
-		if (fca_port->port_handle->fp_npiv_type == FC_NPIV_PORT) {
-			continue;
-		} else {
-			portList[out++] = fca_port->port_handle;
-		}
-	    }
+			}
+
+			mutex_exit(&stored_port->fp_mutex);
+		}
+		mutex_exit(&new_port->fp_mutex);
+
+		if (!skip) {
+			/*
+			 * Either this is the first port for this HBA, or
+			 * it's a secondary port and we haven't stored the
+			 * primary/first port for that HBA.  In the latter case,
+			 * will just filter it out as we proceed to loop.
+			 */
+			if (fca_port->port_handle->fp_npiv_type ==
+			    FC_NPIV_PORT) {
+				continue;
+			} else {
+				portList[out++] = fca_port->port_handle;
+			}
+		}
 	}
 
 	if (out <= count) {
-	    for (in = 0; in < out; in++) {
-		(void) ddi_pathname(portList[in]->fp_port_dip,
-		    &pathList[MAXPATHLEN * in]);
-	    }
+		for (in = 0; in < out; in++) {
+			(void) ddi_pathname(portList[in]->fp_port_dip,
+			    &pathList[MAXPATHLEN * in]);
+		}
 	}
 	mutex_exit(&fctl_port_lock);
 	kmem_free(portList, sizeof (*portList) * maxPorts);
@@ -5588,7 +5611,7 @@
 {
 	int		rval = FC_FAILURE;
 	la_wwn_t	pwwn;
-	fc_orphan_t 	*orp;
+	fc_orphan_t	*orp;
 	fc_orphan_t	*orphan;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
@@ -5625,7 +5648,7 @@
 {
 	int		rval = FC_FAILURE;
 	la_wwn_t	pwwn;
-	fc_orphan_t 	*orp;
+	fc_orphan_t	*orp;
 	fc_orphan_t	*orphan;
 
 	mutex_enter(&port->fp_mutex);
@@ -5669,7 +5692,7 @@
 {
 	int		rval = FC_FAILURE;
 	fc_orphan_t	*prev = NULL;
-	fc_orphan_t 	*orp;
+	fc_orphan_t	*orp;
 
 	mutex_enter(&port->fp_mutex);
 	for (orp = port->fp_orphan_list; orp != NULL; orp = orp->orp_next) {
@@ -5699,9 +5722,9 @@
 static void
 fctl_print_if_not_orphan(fc_local_port_t *port, fc_remote_port_t *pd)
 {
-	char 		ww_name[17];
-	la_wwn_t 	pwwn;
-	fc_orphan_t 	*orp;
+	char		ww_name[17];
+	la_wwn_t	pwwn;
+	fc_orphan_t	*orp;
 
 	mutex_enter(&port->fp_mutex);
 
@@ -5772,7 +5795,7 @@
     char **action, char **expln)
 {
 	int		ret;
-	int 		len;
+	int		len;
 	int		index;
 	fc_pkt_error_t	*error;
 	fc_pkt_reason_t	*reason_b;	/* Base pointer */
@@ -5840,9 +5863,9 @@
 	int			index;
 	int			initiator;
 	fc_remote_node_t	*node;
-	struct pwwn_hash 	*head;
-	fc_remote_port_t 	*pd;
-	fc_remote_port_t 	*old_pd;
+	struct pwwn_hash	*head;
+	fc_remote_port_t	*pd;
+	fc_remote_port_t	*old_pd;
 	fc_remote_port_t	*last_pd;
 
 	/*
@@ -5954,7 +5977,7 @@
 {
 	int			index;
 	struct pwwn_hash	*head;
-	fc_remote_port_t 	*pd;
+	fc_remote_port_t	*pd;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
 
@@ -5984,7 +6007,7 @@
 fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
     int errno, const char *fmt, ...)
 {
-	char 	buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
+	char	buf[FC_MAX_TRACE_BUF_LEN + 3]; /* 3 is for "\n" */
 	char	*bufptr = buf;
 	va_list	ap;
 	int	cnt = 0;
@@ -5995,16 +6018,16 @@
 
 	if (name) {
 		cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>%s::",
-			logq->il_id++, name);
+		    logq->il_id++, name);
 	} else {
 		cnt = snprintf(buf, FC_MAX_TRACE_BUF_LEN + 1, "%d=>trace::",
-			logq->il_id++);
+		    logq->il_id++);
 	}
 
 	if (cnt < FC_MAX_TRACE_BUF_LEN) {
 		va_start(ap, fmt);
 		cnt += vsnprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
-			fmt, ap);
+		    fmt, ap);
 		va_end(ap);
 	}
 
@@ -6013,7 +6036,7 @@
 	}
 	if (errno && (cnt < FC_MAX_TRACE_BUF_LEN)) {
 		cnt += snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 1 - cnt,
-			"error=0x%x\n", errno);
+		    "error=0x%x\n", errno);
 	}
 	(void) snprintf(buf + cnt, FC_MAX_TRACE_BUF_LEN + 3 - cnt, "\n");
 
@@ -6175,21 +6198,21 @@
 	int			outer;
 	int			match = 0;
 	struct pwwn_hash	*head;
-	fc_remote_port_t 	*pd;
+	fc_remote_port_t	*pd;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
 
 	for (outer = 0;
-		outer < pwwn_table_size && match <= index;
-		outer++) {
-	    head = &port->fp_pwwn_table[outer];
-	    pd = head->pwwn_head;
-	    if (pd != NULL) match ++;
-
-	    while (pd != NULL && match <= index) {
-		pd = pd->pd_wwn_hnext;
+	    outer < pwwn_table_size && match <= index;
+	    outer++) {
+		head = &port->fp_pwwn_table[outer];
+		pd = head->pwwn_head;
 		if (pd != NULL) match ++;
-	    }
+
+		while (pd != NULL && match <= index) {
+			pd = pd->pd_wwn_hnext;
+			if (pd != NULL) match ++;
+		}
 	}
 
 	return (pd);
@@ -6203,7 +6226,7 @@
 {
 	int			index;
 	struct pwwn_hash	*head;
-	fc_remote_port_t 	*pd;
+	fc_remote_port_t	*pd;
 
 	ASSERT(MUTEX_HELD(&port->fp_mutex));
 
@@ -6211,21 +6234,21 @@
 		head = &port->fp_pwwn_table[index];
 		pd = head->pwwn_head;
 
-	    while (pd != NULL) {
-		mutex_enter(&pd->pd_mutex);
-		if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn,
-			sizeof (la_wwn_t)) == 0) {
-		    mutex_exit(&pd->pd_mutex);
-		    return (pd);
-		}
-		if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn, wwn.raw_wwn,
-			sizeof (la_wwn_t)) == 0) {
-		    mutex_exit(&pd->pd_mutex);
-		    return (pd);
-		}
-		mutex_exit(&pd->pd_mutex);
-		pd = pd->pd_wwn_hnext;
-	    }
+		while (pd != NULL) {
+			mutex_enter(&pd->pd_mutex);
+			if (bcmp(pd->pd_port_name.raw_wwn, wwn.raw_wwn,
+			    sizeof (la_wwn_t)) == 0) {
+				mutex_exit(&pd->pd_mutex);
+				return (pd);
+			}
+			if (bcmp(pd->pd_remote_nodep->fd_node_name.raw_wwn,
+			    wwn.raw_wwn, sizeof (la_wwn_t)) == 0) {
+				mutex_exit(&pd->pd_mutex);
+				return (pd);
+			}
+			mutex_exit(&pd->pd_mutex);
+			pd = pd->pd_wwn_hnext;
+		}
 	}
 	/* No match */
 	return (NULL);
@@ -6244,7 +6267,7 @@
 fctl_count_fru_ports(fc_local_port_t *port, int npivflag)
 {
 	fca_hba_fru_details_t	*fru;
-	fc_fca_port_t 	*fca_port;
+	fc_fca_port_t	*fca_port;
 	fc_local_port_t	*tmpPort = NULL;
 	uint32_t	count = 1;
 
@@ -6262,11 +6285,11 @@
 
 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
 	    fca_port = fca_port->port_next) {
-	    tmpPort = fca_port->port_handle;
-	    if (tmpPort == port) {
-		continue;
-	    }
-	    mutex_enter(&tmpPort->fp_mutex);
+		tmpPort = fca_port->port_handle;
+		if (tmpPort == port) {
+			continue;
+		}
+		mutex_enter(&tmpPort->fp_mutex);
 
 		/*
 		 * If an FCA driver returns unique fru->high and fru->low for
@@ -6344,7 +6367,7 @@
 fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
 {
 	fca_hba_fru_details_t	*fru;
-	fc_fca_port_t 	*fca_port;
+	fc_fca_port_t	*fca_port;
 	fc_local_port_t	*tmpPort = NULL;
 	fc_fca_port_t	*list = NULL, *tmpEntry;
 	fc_local_port_t		*phyPort, *virPort = NULL;
@@ -6374,41 +6397,43 @@
 	/* Loop through all known ports */
 	for (fca_port = fctl_fca_portlist; fca_port != NULL;
 	    fca_port = fca_port->port_next) {
-	    tmpPort = fca_port->port_handle;
-	    if (tmpPort == port) {
-		/* Skip over the port that was passed in as the argument */
-		continue;
-	    }
-	    mutex_enter(&tmpPort->fp_mutex);
-
-	    /* See if this port is on the same HBA FRU (fast check) */
-	    if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
+		tmpPort = fca_port->port_handle;
+		if (tmpPort == port) {
+			/* Skip the port that was passed in as the argument */
+			continue;
+		}
+		mutex_enter(&tmpPort->fp_mutex);
+
+		/* See if this port is on the same HBA FRU (fast check) */
+		if (tmpPort->fp_hba_port_attrs.hba_fru_details.high ==
 		    fru->high &&
 		    tmpPort->fp_hba_port_attrs.hba_fru_details.low ==
 		    fru->low) {
-		/* Now double check driver (slower check) */
-		if (strncmp(port->fp_hba_port_attrs.driver_name,
-			tmpPort->fp_hba_port_attrs.driver_name,
-			FCHBA_DRIVER_NAME_LEN) == 0) {
-
-		    fru = &tmpPort->fp_hba_port_attrs.hba_fru_details;
-		    /* Check for the matching port_index */
-			if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) &&
-			    (fru->port_index == port_index)) {
-				/* Found it! */
-				mutex_exit(&tmpPort->fp_mutex);
-				mutex_exit(&port->fp_mutex);
-				mutex_exit(&fctl_port_lock);
-				fctl_local_port_list_free(list);
-				return (tmpPort);
-			}
-			if (tmpPort->fp_npiv_type != FC_NPIV_PORT) {
-				(void) fctl_local_port_list_add(list, tmpPort);
-				phyPortNum++;
-			}
-		} /* Else, different FCA driver */
-	    } /* Else not the same HBA FRU */
-	    mutex_exit(&tmpPort->fp_mutex);
+			/* Now double check driver (slower check) */
+			if (strncmp(port->fp_hba_port_attrs.driver_name,
+			    tmpPort->fp_hba_port_attrs.driver_name,
+			    FCHBA_DRIVER_NAME_LEN) == 0) {
+
+				fru =
+				    &tmpPort->fp_hba_port_attrs.hba_fru_details;
+				/* Check for the matching port_index */
+				if ((tmpPort->fp_npiv_type != FC_NPIV_PORT) &&
+				    (fru->port_index == port_index)) {
+					/* Found it! */
+					mutex_exit(&tmpPort->fp_mutex);
+					mutex_exit(&port->fp_mutex);
+					mutex_exit(&fctl_port_lock);
+					fctl_local_port_list_free(list);
+					return (tmpPort);
+				}
+				if (tmpPort->fp_npiv_type != FC_NPIV_PORT) {
+					(void) fctl_local_port_list_add(list,
+					    tmpPort);
+					phyPortNum++;
+				}
+			} /* Else, different FCA driver */
+		} /* Else not the same HBA FRU */
+		mutex_exit(&tmpPort->fp_mutex);
 
 	}
 
@@ -6461,7 +6486,7 @@
 		 * This wouldn't be a problem except that if we have
 		 * registered our PM components in the meantime, we will
 		 * then be idling a component that was never busied.  PM
-		 * will be very unhappy if we do this.  Thus, we keep
+		 * will be very unhappy if we do this.	Thus, we keep
 		 * track of this with port->fp_pm_busy_nocomp.
 		 */
 		port->fp_pm_busy_nocomp++;
@@ -6533,12 +6558,10 @@
  *
  * Return Value: Nothing
  *
- *      Context: Kernel context.
+ *	Context: Kernel context.
  */
 static void
-fctl_tc_timer(
-    void	*arg
-)
+fctl_tc_timer(void *arg)
 {
 	timed_counter_t	*tc = (timed_counter_t *)arg;
 
@@ -6559,21 +6582,17 @@
  *  Description: Constructs a timed counter.
  *
  *    Arguments: *tc		Address where the timed counter will reside.
- *		 max_value      Maximum value the counter is allowed to take.
+ *		 max_value	Maximum value the counter is allowed to take.
  *		 timer		Number of microseconds after which the counter
  *				will be reset. The timer is started when the
  *				value of the counter goes from 0 to 1.
  *
  * Return Value: Nothing
  *
- *      Context: Kernel context.
+ *	Context: Kernel context.
  */
 void
-fctl_tc_constructor(
-    timed_counter_t	*tc,
-    uint32_t		max_value,
-    clock_t		timer
-)
+fctl_tc_constructor(timed_counter_t *tc, uint32_t max_value, clock_t timer)
 {
 	ASSERT(tc != NULL);
 	ASSERT(tc->sig != tc);
@@ -6596,12 +6615,10 @@
  *
  * Return Value: Nothing
  *
- *      Context: Kernel context.
+ *	Context: Kernel context.
  */
 void
-fctl_tc_destructor(
-    timed_counter_t	*tc
-)
+fctl_tc_destructor(timed_counter_t *tc)
 {
 	ASSERT(tc != NULL);
 	ASSERT(tc->sig == tc);
@@ -6627,12 +6644,10 @@
  * Return Value: B_TRUE		Counter reached the max value.
  *		 B_FALSE	Counter hasn't reached the max value.
  *
- *      Context: Kernel or interrupt context.
+ *	Context: Kernel or interrupt context.
  */
 boolean_t
-fctl_tc_increment(
-    timed_counter_t *tc
-)
+fctl_tc_increment(timed_counter_t *tc)
 {
 	ASSERT(tc != NULL);
 	ASSERT(tc->sig == tc);
@@ -6667,12 +6682,10 @@
  * Return Value: 0		Counter reached the max value.
  *		 Not 0		Counter hasn't reached the max value.
  *
- *      Context: Kernel or interrupt context.
+ *	Context: Kernel or interrupt context.
  */
 void
-fctl_tc_reset(
-    timed_counter_t *tc
-)
+fctl_tc_reset(timed_counter_t *tc)
 {
 	ASSERT(tc != NULL);
 	ASSERT(tc->sig == tc);
--- a/usr/src/uts/common/io/fibre-channel/impl/fp.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fibre-channel/impl/fp.c	Wed Aug 05 17:14:23 2009 -0700
@@ -95,7 +95,7 @@
 	ddi_quiesce_not_needed 		/* quiesce */
 };
 
-#define	FP_VERSION		"1.99"
+#define	FP_VERSION		"20090729-1.100"
 #define	FP_NAME_VERSION		"SunFC Port v" FP_VERSION
 
 char *fp_version = FP_NAME_VERSION;
@@ -928,13 +928,10 @@
 	char pwwn[17], nwwn[17];
 
 	instance = ddi_get_instance(dip);
-
 	port_len = sizeof (port_num);
-
 	rval = ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "port",
 	    (caddr_t)&port_num, &port_len);
-
 	if (rval != DDI_SUCCESS) {
 		cmn_err(CE_WARN, "fp(%d): No port property in devinfo",
 		    instance);
@@ -1884,17 +1881,22 @@
 	cmd->cmd_port = port;
 	pkt = &cmd->cmd_pkt;
 
-	if (ddi_dma_alloc_handle(port->fp_fca_dip,
-	    port->fp_fca_tran->fca_dma_attr, cb, NULL,
-	    &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
-		return (-1);
-	}
-
-	if (ddi_dma_alloc_handle(port->fp_fca_dip,
-	    port->fp_fca_tran->fca_dma_attr, cb, NULL,
-	    &pkt->pkt_resp_dma) != DDI_SUCCESS) {
-		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
-		return (-1);
+	if (!(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
+		if (ddi_dma_alloc_handle(port->fp_fca_dip,
+		    port->fp_fca_tran->fca_dma_attr, cb, NULL,
+		    &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
+			return (-1);
+		}
+
+		if (ddi_dma_alloc_handle(port->fp_fca_dip,
+		    port->fp_fca_tran->fca_dma_attr, cb, NULL,
+		    &pkt->pkt_resp_dma) != DDI_SUCCESS) {
+			ddi_dma_free_handle(&pkt->pkt_cmd_dma);
+			return (-1);
+		}
+	} else {
+		pkt->pkt_cmd_dma = 0;
+		pkt->pkt_resp_dma = 0;
 	}
 
 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
@@ -1951,6 +1953,13 @@
  * ensures that the pd_ref_count for the fc_remote_port_t is valid.
  * If there is no fc_remote_port_t associated with the fc_packet_t, then
  * fp_alloc_pkt() must be called with pd set to NULL.
+ *
+ * fp/fctl will resue fp_cmd_t somewhere, and change pkt_cmdlen/rsplen,
+ * actually, it's a design fault. But there's no problem for physical
+ * FCAs. But it will cause memory leak or panic for virtual FCAs like fcoei.
+ *
+ * For FCAs that don't support DMA, such as fcoei, we will use
+ * pkt_fctl_rsvd1/rsvd2 to keep the real cmd_len/resp_len.
  */
 
 static fp_cmd_t *
@@ -1986,6 +1995,10 @@
 	pkt->pkt_action = 0;
 	pkt->pkt_reason = 0;
 	pkt->pkt_expln = 0;
+	pkt->pkt_cmd = NULL;
+	pkt->pkt_resp = NULL;
+	pkt->pkt_fctl_rsvd1 = NULL;
+	pkt->pkt_fctl_rsvd2 = NULL;
 
 	/*
 	 * Init pkt_pd with the given pointer; this must be done _before_
@@ -1998,7 +2011,7 @@
 		goto alloc_pkt_failed;
 	}
 
-	if (cmd_len) {
+	if (cmd_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
 		ASSERT(pkt->pkt_cmd_dma != NULL);
 
 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
@@ -2047,9 +2060,12 @@
 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
 			*cp = pkt_cookie;
 		}
-	}
-
-	if (resp_len) {
+	} else if (cmd_len != 0) {
+		pkt->pkt_cmd = kmem_alloc(cmd_len, KM_SLEEP);
+		pkt->pkt_fctl_rsvd1 = (opaque_t)(uintptr_t)cmd_len;
+	}
+
+	if (resp_len && !(port->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {
 		ASSERT(pkt->pkt_resp_dma != NULL);
 
 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
@@ -2099,6 +2115,9 @@
 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
 			*cp = pkt_cookie;
 		}
+	} else if (resp_len != 0) {
+		pkt->pkt_resp = kmem_alloc(resp_len, KM_SLEEP);
+		pkt->pkt_fctl_rsvd2 = (opaque_t)(uintptr_t)resp_len;
 	}
 
 	pkt->pkt_cmdlen = cmd_len;
@@ -2123,6 +2142,16 @@
 		pkt->pkt_resp_cookie = NULL;
 	}
 
+	if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
+		if (pkt->pkt_cmd) {
+			kmem_free(pkt->pkt_cmd, cmd_len);
+		}
+
+		if (pkt->pkt_resp) {
+			kmem_free(pkt->pkt_resp, resp_len);
+		}
+	}
+
 	kmem_cache_free(port->fp_pkt_cache, cmd);
 
 	return (NULL);
@@ -2160,6 +2189,18 @@
 		pkt->pkt_resp_cookie = NULL;
 	}
 
+	if (port->fp_soft_state & FP_SOFT_FCA_IS_NODMA) {
+		if (pkt->pkt_cmd) {
+			kmem_free(pkt->pkt_cmd,
+			    (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd1);
+		}
+
+		if (pkt->pkt_resp) {
+			kmem_free(pkt->pkt_resp,
+			    (uint32_t)(uintptr_t)pkt->pkt_fctl_rsvd2);
+		}
+	}
+
 	fp_free_dma(cmd);
 	(void) fc_ulp_uninit_packet((opaque_t)port, pkt);
 	kmem_cache_free(port->fp_pkt_cache, (void *)cmd);
@@ -4153,16 +4194,16 @@
 	}
 
 	if (handle) {
-		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_csp,
+		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_csp,
 		    (uint8_t *)&acc->common_service,
 		    sizeof (acc->common_service), DDI_DEV_AUTOINCR);
-		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp1,
+		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp1,
 		    (uint8_t *)&acc->class_1, sizeof (acc->class_1),
 		    DDI_DEV_AUTOINCR);
-		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp2,
+		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp2,
 		    (uint8_t *)&acc->class_2, sizeof (acc->class_2),
 		    DDI_DEV_AUTOINCR);
-		ddi_rep_get8(*handle, (uint8_t *)&pd->pd_clsp3,
+		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)&pd->pd_clsp3,
 		    (uint8_t *)&acc->class_3, sizeof (acc->class_3),
 		    DDI_DEV_AUTOINCR);
 	} else {
@@ -4183,7 +4224,7 @@
 
 	mutex_enter(&node->fd_mutex);
 	if (handle) {
-		ddi_rep_get8(*handle, (uint8_t *)node->fd_vv,
+		FC_GET_RSP(pd->pd_port, *handle, (uint8_t *)node->fd_vv,
 		    (uint8_t *)acc->vendor_version, sizeof (node->fd_vv),
 		    DDI_DEV_AUTOINCR);
 	} else {
@@ -4405,12 +4446,12 @@
 	payload.ls_code = ls_code;
 	payload.mbz = 0;
 
-	ddi_rep_put8(cmd->cmd_pkt.pkt_cmd_acc,
+	FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc,
 	    (uint8_t *)&port->fp_service_params,
 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (port->fp_service_params),
 	    DDI_DEV_AUTOINCR);
 
-	ddi_rep_put8(cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, cmd->cmd_pkt.pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)cmd->cmd_pkt.pkt_cmd, sizeof (payload),
 	    DDI_DEV_AUTOINCR);
 }
@@ -4444,7 +4485,7 @@
 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
 	payload.nport_id = port->fp_port_id;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -4477,7 +4518,7 @@
 	payload.ls_code.mbz = 0;
 	payload.data_format = flag;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -4510,7 +4551,7 @@
 	payload.ls_code.mbz = 0;
 	payload.rls_portid = port->fp_port_id;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -4547,7 +4588,7 @@
 	payload.node_wwn = port->fp_service_params.node_ww_name;
 	payload.hard_addr = port->fp_hard_addr;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -4943,31 +4984,31 @@
 			ls_code.ls_code = LA_ELS_ACC;
 			ls_code.mbz = 0;
 
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&ls_code, (uint8_t *)&els_data->ls_code,
 			    sizeof (ls_code_t), DDI_DEV_AUTOINCR);
 
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&pd->pd_csp,
 			    (uint8_t *)&els_data->common_service,
 			    sizeof (pd->pd_csp), DDI_DEV_AUTOINCR);
 
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&pd->pd_port_name,
 			    (uint8_t *)&els_data->nport_ww_name,
 			    sizeof (pd->pd_port_name), DDI_DEV_AUTOINCR);
 
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&pd->pd_clsp1,
 			    (uint8_t *)&els_data->class_1,
 			    sizeof (pd->pd_clsp1), DDI_DEV_AUTOINCR);
 
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&pd->pd_clsp2,
 			    (uint8_t *)&els_data->class_2,
 			    sizeof (pd->pd_clsp2), DDI_DEV_AUTOINCR);
 
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&pd->pd_clsp3,
 			    (uint8_t *)&els_data->class_3,
 			    sizeof (pd->pd_clsp3), DDI_DEV_AUTOINCR);
@@ -4979,13 +5020,12 @@
 			mutex_exit(&pd->pd_mutex);
 
 			mutex_enter(&node->fd_mutex);
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&node->fd_node_name,
 			    (uint8_t *)(&els_data->node_ww_name),
 			    sizeof (node->fd_node_name), DDI_DEV_AUTOINCR);
 
-
-			ddi_rep_put8(ulp_pkt->pkt_resp_acc,
+			FC_SET_CMD(pd->pd_port, ulp_pkt->pkt_resp_acc,
 			    (uint8_t *)&node->fd_vv,
 			    (uint8_t *)(&els_data->vendor_version),
 			    sizeof (node->fd_vv), DDI_DEV_AUTOINCR);
@@ -5299,7 +5339,7 @@
 	payload.ls_code.mbz = 0;
 	payload.nport_ww_name = port->fp_service_params.nport_ww_name;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 
 	if (fp_sendcmd(port, cmd, port->fp_fca_handle) != FC_SUCCESS) {
@@ -5379,7 +5419,7 @@
 		}
 		rxn.rxn_port_id = s_id;
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rxn,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rxn,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (rxn), DDI_DEV_AUTOINCR);
 
@@ -5406,7 +5446,7 @@
 		}
 		rcos.rcos_port_id = s_id;
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rcos,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rcos,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (rcos), DDI_DEV_AUTOINCR);
 
@@ -5438,7 +5478,7 @@
 		}
 		rfc.rfc_port_id = s_id;
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rfc,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rfc,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (rfc), DDI_DEV_AUTOINCR);
 
@@ -5474,23 +5514,24 @@
 
 		spn = s_id;
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&spn, (uint8_t *)
 		    (pkt->pkt_cmd + sizeof (fc_ct_header_t)), sizeof (spn),
 		    DDI_DEV_AUTOINCR);
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&name_len,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)
 		    + sizeof (fc_portid_t)), 1, DDI_DEV_AUTOINCR);
 
 		if (pd == NULL) {
 			mutex_enter(&port->fp_mutex);
-			ddi_rep_put8(pkt->pkt_cmd_acc,
+			FC_SET_CMD(port, pkt->pkt_cmd_acc,
 			    (uint8_t *)port->fp_sym_port_name, (uint8_t *)
 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
 			mutex_exit(&port->fp_mutex);
 		} else {
 			mutex_enter(&pd->pd_mutex);
-			ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)pd->pd_spn,
+			FC_SET_CMD(port, pkt->pkt_cmd_acc,
+			    (uint8_t *)pd->pd_spn,
 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
 			    sizeof (spn) + 1), name_len, DDI_DEV_AUTOINCR);
 			mutex_exit(&pd->pd_mutex);
@@ -5518,7 +5559,7 @@
 		}
 		rpt.rpt_port_id = s_id;
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rpt,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rpt,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (rpt), DDI_DEV_AUTOINCR);
 
@@ -5562,7 +5603,7 @@
 			mutex_exit(&node->fd_mutex);
 		}
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rip,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rip,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (rip), DDI_DEV_AUTOINCR);
 
@@ -5599,7 +5640,7 @@
 			mutex_exit(&node->fd_mutex);
 		}
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&ipa,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ipa,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (ipa), DDI_DEV_AUTOINCR);
 
@@ -5642,7 +5683,7 @@
 
 		if (pd == NULL) {
 			mutex_enter(&port->fp_mutex);
-			ddi_rep_put8(pkt->pkt_cmd_acc,
+			FC_SET_CMD(port, pkt->pkt_cmd_acc,
 			    (uint8_t *)port->fp_sym_node_name, (uint8_t *)
 			    (pkt->pkt_cmd + sizeof (fc_ct_header_t) +
 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
@@ -5650,17 +5691,17 @@
 		} else {
 			ASSERT(node != NULL);
 			mutex_enter(&node->fd_mutex);
-			ddi_rep_put8(pkt->pkt_cmd_acc,
+			FC_SET_CMD(port, pkt->pkt_cmd_acc,
 			    (uint8_t *)node->fd_snn,
 			    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t) +
 			    sizeof (snn) + 1), name_len, DDI_DEV_AUTOINCR);
 			mutex_exit(&node->fd_mutex);
 		}
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&snn,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&snn,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (snn), DDI_DEV_AUTOINCR);
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&name_len,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&name_len,
 		    (uint8_t *)(pkt->pkt_cmd
 		    + sizeof (fc_ct_header_t) + sizeof (snn)),
 		    1, DDI_DEV_AUTOINCR);
@@ -5693,7 +5734,7 @@
 #else
 		rall.rem_port_id = s_id;
 #endif
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&rall,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&rall,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    sizeof (rall), DDI_DEV_AUTOINCR);
 
@@ -5843,7 +5884,7 @@
 	 */
 	acc = (la_els_logi_t *)pkt->pkt_resp;
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
 	    sizeof (resp), DDI_DEV_AUTOINCR);
 
 	ASSERT(resp.ls_code == LA_ELS_ACC);
@@ -5852,7 +5893,7 @@
 		return;
 	}
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&csp,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&csp,
 	    (uint8_t *)&acc->common_service, sizeof (csp), DDI_DEV_AUTOINCR);
 
 	f_port = FP_IS_F_PORT(csp.cmn_features) ? 1 : 0;
@@ -5863,15 +5904,15 @@
 	state = FC_PORT_STATE_MASK(port->fp_state);
 	mutex_exit(&port->fp_mutex);
 
-	if (pkt->pkt_resp_fhdr.d_id == 0) {
-		if (f_port == 0 && state != FC_STATE_LOOP) {
+	if (f_port == 0) {
+		if (state != FC_STATE_LOOP) {
 			swwn = &port->fp_service_params.nport_ww_name;
 
-			ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&dwwn,
+			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&dwwn,
 			    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
 			    DDI_DEV_AUTOINCR);
 
-			ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn,
+			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
 			    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
 			    DDI_DEV_AUTOINCR);
 
@@ -5948,7 +5989,7 @@
 			} else {
 				port->fp_topology = FC_TOP_FABRIC;
 
-				ddi_rep_get8(pkt->pkt_resp_acc,
+				FC_GET_RSP(port, pkt->pkt_resp_acc,
 				    (uint8_t *)&port->fp_fabric_name,
 				    (uint8_t *)&acc->node_ww_name,
 				    sizeof (la_wwn_t),
@@ -6088,7 +6129,7 @@
 
 	acc = (la_els_logi_t *)pkt->pkt_resp;
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp, (uint8_t *)acc,
 	    sizeof (resp), DDI_DEV_AUTOINCR);
 
 	ASSERT(resp.ls_code == LA_ELS_ACC);
@@ -6107,11 +6148,11 @@
 
 	ASSERT(acc == (la_els_logi_t *)pkt->pkt_resp);
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&pwwn,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
 	    (uint8_t *)&acc->nport_ww_name, sizeof (la_wwn_t),
 	    DDI_DEV_AUTOINCR);
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
 	    (uint8_t *)&acc->node_ww_name, sizeof (la_wwn_t),
 	    DDI_DEV_AUTOINCR);
 
@@ -6507,13 +6548,13 @@
 	if (pkt->pkt_state == FC_PKT_SUCCESS && pkt->pkt_resp_resid == 0) {
 		acc = (la_els_adisc_t *)pkt->pkt_resp;
 
-		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
+		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
 		    (uint8_t *)acc, sizeof (resp), DDI_DEV_AUTOINCR);
 
 		if (resp.ls_code == LA_ELS_ACC) {
 			int	is_private;
 
-			ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&ha,
+			FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&ha,
 			    (uint8_t *)&acc->hard_addr, sizeof (ha),
 			    DDI_DEV_AUTOINCR);
 
@@ -6625,7 +6666,7 @@
 		if (adiscfail) {
 			mutex_enter(&pd->pd_mutex);
 			initiator =
-			    (pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0;
+			    ((pd->pd_recepient == PD_PLOGI_INITIATOR) ? 1 : 0);
 			pd->pd_state = PORT_DEVICE_VALID;
 			pd->pd_aux_flags |= PD_LOGGED_OUT;
 			if (pd->pd_aux_flags & PD_DISABLE_RELOGIN) {
@@ -6670,12 +6711,13 @@
 fp_logo_intr(fc_packet_t *pkt)
 {
 	ls_code_t	resp;
+	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
 
 	mutex_enter(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
 	((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_out_fpcmds--;
 	mutex_exit(&((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port->fp_mutex);
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
 
 	if (FP_IS_PKT_ERROR(pkt)) {
@@ -6707,8 +6749,9 @@
 	job_request_t		*job;
 	fp_cmd_t		*cmd;
 	la_els_rnid_acc_t	*acc;
-
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
+	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
+
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
 	cmd = pkt->pkt_ulp_private;
 
@@ -6728,7 +6771,7 @@
 	/* Save node_id memory allocated in ioctl code */
 	acc = (la_els_rnid_acc_t *)pkt->pkt_resp;
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)job->job_private,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
 	    (uint8_t *)acc, sizeof (la_els_rnid_acc_t), DDI_DEV_AUTOINCR);
 
 	/* wakeup the ioctl thread and free the pkt */
@@ -6746,8 +6789,9 @@
 	job_request_t		*job;
 	fp_cmd_t		*cmd;
 	la_els_rls_acc_t	*acc;
-
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp,
+	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
+
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp,
 	    (uint8_t *)pkt->pkt_resp, sizeof (resp), DDI_DEV_AUTOINCR);
 	cmd = pkt->pkt_ulp_private;
 
@@ -6767,7 +6811,7 @@
 	/* Save link error status block in memory allocated in ioctl code */
 	acc = (la_els_rls_acc_t *)pkt->pkt_resp;
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)job->job_private,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)job->job_private,
 	    (uint8_t *)&acc->rls_link_params, sizeof (fc_rls_acc_t),
 	    DDI_DEV_AUTOINCR);
 
@@ -6984,7 +7028,7 @@
 	payload.scr_rsvd = 0;
 	payload.scr_func = scr_func;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 
 	job->job_counter = 1;
@@ -10521,6 +10565,7 @@
 	fp_cmd_t		*cmd;
 	job_request_t		*job;
 	fc_linit_resp_t		acc;
+	fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
 
 	cmd = (fp_cmd_t *)pkt->pkt_ulp_private;
 
@@ -10534,7 +10579,8 @@
 	}
 
 	job = cmd->cmd_job;
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&acc,
+
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&acc,
 	    (uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
 	if (acc.status != FC_LINIT_SUCCESS) {
 		job->job_result = FC_FAILURE;
@@ -11068,7 +11114,7 @@
 	payload.explanation = FC_EXPLN_NONE;
 	payload.vendor = 0;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -11105,7 +11151,7 @@
 	payload.reserved = 0;
 	payload.vu = 0;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -11171,7 +11217,7 @@
 		flags |= SP_RESP_CODE_REQ_EXECUTED;
 		req->flags = htons(flags);
 
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)req,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)req,
 		    (uint8_t *)pkt->pkt_cmd, len, DDI_DEV_AUTOINCR);
 	}
 	return (cmd);
@@ -11203,7 +11249,7 @@
 	payload.ls_code = LA_ELS_ACC;
 	payload.mbz = 0;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -11535,6 +11581,7 @@
 	pkt->pkt_cmd_fhdr.rsvd = 0;
 	pkt->pkt_comp = fp_unsol_intr;
 	pkt->pkt_timeout = FP_ELS_TIMEOUT;
+	pkt->pkt_ub_resp_token = (opaque_t)buf;
 }
 
 /*
@@ -11655,18 +11702,6 @@
 				cmd->cmd_pkt.pkt_rsplen = 0;
 
 				/*
-				 * Sometime later, we should validate
-				 * the service parameters instead of
-				 * just accepting it.
-				 */
-				fp_login_acc_init(port, cmd, buf, NULL,
-				    KM_NOSLEEP);
-				FP_TRACE(FP_NHEAD1(3, 0),
-				    "fp_i_handle_unsol_els: Accepting PLOGI,"
-				    " f_port=%d, small=%d, do_acc=%d,"
-				    " sent=%d.", f_port, small, do_acc,
-				    sent);
-				/*
 				 * If fp_port_id is zero and topology is
 				 * Point-to-Point, get the local port id from
 				 * the d_id in the PLOGI request.
@@ -11684,6 +11719,19 @@
 					    buf->ub_frame.d_id;
 				}
 				mutex_exit(&port->fp_mutex);
+
+				/*
+				 * Sometime later, we should validate
+				 * the service parameters instead of
+				 * just accepting it.
+				 */
+				fp_login_acc_init(port, cmd, buf, NULL,
+				    KM_NOSLEEP);
+				FP_TRACE(FP_NHEAD1(3, 0),
+				    "fp_i_handle_unsol_els: Accepting PLOGI,"
+				    " f_port=%d, small=%d, do_acc=%d,"
+				    " sent=%d.", f_port, small, do_acc,
+				    sent);
 			}
 		} else {
 			if (FP_IS_CLASS_1_OR_2(buf->ub_class) ||
@@ -12163,7 +12211,7 @@
 	payload = port->fp_service_params;
 	payload.ls_code.ls_code = LA_ELS_ACC;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 
 	FP_TRACE(FP_NHEAD1(3, 0), "login_acc_init: ELS:0x%x d_id:0x%x "
@@ -12494,13 +12542,13 @@
 	ASSERT(!MUTEX_HELD(&port->fp_mutex));
 
 	if (handle) {
-		ddi_rep_get8(*handle, (uint8_t *)&port_map->map_pwwn,
+		FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_pwwn,
 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (gan_resp->gan_pwwn),
 		    DDI_DEV_AUTOINCR);
-		ddi_rep_get8(*handle, (uint8_t *)&port_map->map_nwwn,
+		FC_GET_RSP(port, *handle, (uint8_t *)&port_map->map_nwwn,
 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (gan_resp->gan_nwwn),
 		    DDI_DEV_AUTOINCR);
-		ddi_rep_get8(*handle, (uint8_t *)port_map->map_fc4_types,
+		FC_GET_RSP(port, *handle, (uint8_t *)port_map->map_fc4_types,
 		    (uint8_t *)gan_resp->gan_fc4types,
 		    sizeof (gan_resp->gan_fc4types), DDI_DEV_AUTOINCR);
 	} else {
@@ -12686,7 +12734,7 @@
 	payload.lip_b3 = 0xF7;		/* Normal LIP */
 	payload.lip_b4 = 0xF7;		/* No valid source AL_PA */
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 
 	job->job_counter = 1;
@@ -12727,7 +12775,7 @@
 
 	mutex_enter(&pd->pd_mutex);
 
-	ddi_rep_get8(*handle, (uint8_t *)&type,
+	FC_GET_RSP(port, *handle, (uint8_t *)&type,
 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (type), DDI_DEV_AUTOINCR);
 
 	pd->pd_porttype.port_type = type.port_type;
@@ -12735,18 +12783,18 @@
 
 	pd->pd_spn_len = gan_resp->gan_spnlen;
 	if (pd->pd_spn_len) {
-		ddi_rep_get8(*handle, (uint8_t *)pd->pd_spn,
+		FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_spn,
 		    (uint8_t *)gan_resp->gan_spname, pd->pd_spn_len,
 		    DDI_DEV_AUTOINCR);
 	}
 
-	ddi_rep_get8(*handle, (uint8_t *)pd->pd_ip_addr,
+	FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_ip_addr,
 	    (uint8_t *)gan_resp->gan_ip, sizeof (pd->pd_ip_addr),
 	    DDI_DEV_AUTOINCR);
-	ddi_rep_get8(*handle, (uint8_t *)&pd->pd_cos,
+	FC_GET_RSP(port, *handle, (uint8_t *)&pd->pd_cos,
 	    (uint8_t *)&gan_resp->gan_cos, sizeof (pd->pd_cos),
 	    DDI_DEV_AUTOINCR);
-	ddi_rep_get8(*handle, (uint8_t *)pd->pd_fc4types,
+	FC_GET_RSP(port, *handle, (uint8_t *)pd->pd_fc4types,
 	    (uint8_t *)gan_resp->gan_fc4types, sizeof (pd->pd_fc4types),
 	    DDI_DEV_AUTOINCR);
 
@@ -12755,13 +12803,13 @@
 
 	mutex_enter(&node->fd_mutex);
 
-	ddi_rep_get8(*handle, (uint8_t *)node->fd_ipa,
+	FC_GET_RSP(port, *handle, (uint8_t *)node->fd_ipa,
 	    (uint8_t *)gan_resp->gan_ipa, sizeof (node->fd_ipa),
 	    DDI_DEV_AUTOINCR);
 
 	node->fd_snn_len = gan_resp->gan_snnlen;
 	if (node->fd_snn_len) {
-		ddi_rep_get8(*handle, (uint8_t *)node->fd_snn,
+		FC_GET_RSP(port, *handle, (uint8_t *)node->fd_snn,
 		    (uint8_t *)gan_resp->gan_snname, node->fd_snn_len,
 		    DDI_DEV_AUTOINCR);
 	}
@@ -12865,8 +12913,8 @@
 	ct.ct_expln = 0;
 	ct.ct_vendor = 0;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&ct, (uint8_t *)pkt->pkt_cmd,
-	    sizeof (ct), DDI_DEV_AUTOINCR);
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&ct,
+	    (uint8_t *)pkt->pkt_cmd, sizeof (ct), DDI_DEV_AUTOINCR);
 
 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
 	pkt->pkt_cmd_fhdr.d_id = 0xFFFFFC;
@@ -12887,7 +12935,7 @@
 	pkt->pkt_timeout = FP_NS_TIMEOUT;
 
 	if (cmd_buf) {
-		ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
+		FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)cmd_buf,
 		    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 		    cmd_len, DDI_DEV_AUTOINCR);
 	}
@@ -12921,12 +12969,12 @@
 	port->fp_out_fpcmds--;
 	mutex_exit(&port->fp_mutex);
 
-	ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
+	FC_GET_RSP(port, pkt->pkt_cmd_acc, (uint8_t *)&cmd_hdr,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (cmd_hdr), DDI_DEV_AUTOINCR);
 	ns_cmd = (fctl_ns_req_t *)
 	    (((fp_cmd_t *)(pkt->pkt_ulp_private))->cmd_private);
 	if (!FP_IS_PKT_ERROR(pkt)) {
-		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
+		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&resp_hdr,
 		    (uint8_t *)pkt->pkt_resp, sizeof (resp_hdr),
 		    DDI_DEV_AUTOINCR);
 
@@ -13035,7 +13083,7 @@
 
 	gan_resp = (ns_resp_gan_t *)(pkt->pkt_resp + sizeof (fc_ct_header_t));
 
-	ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&d_id,
+	FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&d_id,
 	    (uint8_t *)&gan_resp->gan_type_id, sizeof (d_id), DDI_DEV_AUTOINCR);
 
 	*(uint32_t *)&d_id = BE_32(*(uint32_t *)&d_id);
@@ -13093,11 +13141,11 @@
 		    gan_resp->gan_nwwn.raw_wwn[6],
 		    gan_resp->gan_nwwn.raw_wwn[7]);
 
-		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&nwwn,
+		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&nwwn,
 		    (uint8_t *)&gan_resp->gan_nwwn, sizeof (nwwn),
 		    DDI_DEV_AUTOINCR);
 
-		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)&pwwn,
+		FC_GET_RSP(port, pkt->pkt_resp_acc, (uint8_t *)&pwwn,
 		    (uint8_t *)&gan_resp->gan_pwwn, sizeof (pwwn),
 		    DDI_DEV_AUTOINCR);
 
@@ -13128,7 +13176,7 @@
 
 				userbuf->dev_did = d_id;
 
-				ddi_rep_get8(pkt->pkt_resp_acc,
+				FC_GET_RSP(port, pkt->pkt_resp_acc,
 				    (uint8_t *)userbuf->dev_type,
 				    (uint8_t *)gan_resp->gan_fc4types,
 				    sizeof (userbuf->dev_type),
@@ -13174,7 +13222,7 @@
 				dst_ptr = ns_cmd->ns_data_buf +
 				    (NS_GAN_RESP_LEN) * ns_cmd->ns_gan_index++;
 
-				ddi_rep_get8(pkt->pkt_resp_acc,
+				FC_GET_RSP(port, pkt->pkt_resp_acc,
 				    (uint8_t *)dst_ptr, (uint8_t *)gan_resp,
 				    NS_GAN_RESP_LEN, DDI_DEV_AUTOINCR);
 			}
@@ -13189,7 +13237,7 @@
 
 	gan_req.pid = d_id;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&gan_req,
 	    (uint8_t *)(pkt->pkt_cmd + sizeof (fc_ct_header_t)),
 	    sizeof (gan_req), DDI_DEV_AUTOINCR);
 
@@ -13232,7 +13280,8 @@
 
 	if (xfer_len <= ns_cmd->ns_data_len) {
 		src_ptr = (caddr_t)pkt->pkt_resp + sizeof (fc_ct_header_t);
-		ddi_rep_get8(pkt->pkt_resp_acc, (uint8_t *)ns_cmd->ns_data_buf,
+		FC_GET_RSP(port, pkt->pkt_resp_acc,
+		    (uint8_t *)ns_cmd->ns_data_buf,
 		    (uint8_t *)src_ptr, xfer_len, DDI_DEV_AUTOINCR);
 	}
 
@@ -13341,7 +13390,7 @@
 	payload.port_wwn = port->fp_service_params.nport_ww_name;
 	payload.node_wwn = port->fp_service_params.node_ww_name;
 
-	ddi_rep_put8(pkt->pkt_cmd_acc, (uint8_t *)&payload,
+	FC_SET_CMD(port, pkt->pkt_cmd_acc, (uint8_t *)&payload,
 	    (uint8_t *)pkt->pkt_cmd, sizeof (payload), DDI_DEV_AUTOINCR);
 }
 
@@ -13716,6 +13765,14 @@
 		goto exit;
 	}
 
+	/*
+	 * Only fcoei will set this bit
+	 */
+	if (port_info->pi_port_state & FC_STATE_FCA_IS_NODMA) {
+		port->fp_soft_state |= FP_SOFT_FCA_IS_NODMA;
+		port_info->pi_port_state &= ~(FC_STATE_FCA_IS_NODMA);
+	}
+
 	port->fp_bind_state = port->fp_state = port_info->pi_port_state;
 	port->fp_service_params = port_info->pi_login_params;
 	port->fp_hard_addr = port_info->pi_hard_addr;
@@ -14133,7 +14190,6 @@
 					job->job_result = rval;
 					fp_jobdone(job);
 				}
-
 				FP_TRACE(FP_NHEAD2(4, 0),
 				    "PLOGI succeeded:no skip(1) for "
 				    "D_ID %x", d_id);
--- a/usr/src/uts/common/io/fibre-channel/ulp/fcp.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fibre-channel/ulp/fcp.c	Wed Aug 05 17:14:23 2009 -0700
@@ -625,6 +625,21 @@
 static int fcp_should_mask(la_wwn_t *wwn, uint32_t lun_id);
 static void fcp_cleanup_blacklist(struct fcp_black_list_entry **lun_blacklist);
 
+/*
+ * New functions to support software FCA (like fcoei)
+ */
+static struct scsi_pkt *fcp_pseudo_init_pkt(
+	struct scsi_address *ap, struct scsi_pkt *pkt,
+	struct buf *bp, int cmdlen, int statuslen,
+	int tgtlen, int flags, int (*callback)(), caddr_t arg);
+static void fcp_pseudo_destroy_pkt(
+	struct scsi_address *ap, struct scsi_pkt *pkt);
+static void fcp_pseudo_sync_pkt(
+	struct scsi_address *ap, struct scsi_pkt *pkt);
+static int fcp_pseudo_start(struct scsi_address *ap, struct scsi_pkt *pkt);
+static void fcp_pseudo_dmafree(
+	struct scsi_address *ap, struct scsi_pkt *pkt);
+
 extern struct mod_ops	mod_driverops;
 /*
  * This variable is defined in modctl.c and set to '1' after the root driver
@@ -717,7 +732,7 @@
 	(es)->es_add_code == 0x25 &&		\
 	(es)->es_qual_code == 0x0)
 
-#define	FCP_VERSION		"1.189"
+#define	FCP_VERSION		"20090729-1.190"
 #define	FCP_NAME_VERSION	"SunFC FCP v" FCP_VERSION
 
 #define	FCP_NUM_ELEMENTS(array)			\
@@ -1078,6 +1093,29 @@
 	sizeof (fcp_symmetric_disk_table)/sizeof (char *);
 
 /*
+ * This structure is bogus. scsi_hba_attach_setup() requires, as in the kernel
+ * will panic if you don't pass this in to the routine, this information.
+ * Need to determine what the actual impact to the system is by providing
+ * this information if any. Since dma allocation is done in pkt_init it may
+ * not have any impact. These values are straight from the Writing Device
+ * Driver manual.
+ */
+static ddi_dma_attr_t pseudo_fca_dma_attr = {
+	DMA_ATTR_V0,	/* ddi_dma_attr version */
+	0,		/* low address */
+	0xffffffff,	/* high address */
+	0x00ffffff,	/* counter upper bound */
+	1,		/* alignment requirements */
+	0x3f,		/* burst sizes */
+	1,		/* minimum DMA access */
+	0xffffffff,	/* maximum DMA access */
+	(1 << 24) - 1,	/* segment boundary restrictions */
+	1,		/* scater/gather list length */
+	512,		/* device granularity */
+	0		/* DMA flags */
+};
+
+/*
  * The _init(9e) return value should be that of mod_install(9f). Under
  * some circumstances, a failure may not be related mod_install(9f) and
  * one would then require a return value to indicate the failure. Looking
@@ -2836,6 +2874,7 @@
 	struct fcp_reportlun_resp	*report_lun;
 	uint8_t			reconfig_needed = FALSE;
 	uint8_t			lun_exists = FALSE;
+	fcp_port_t			*pptr		 = ptgt->tgt_port;
 
 	report_lun = kmem_zalloc(fpkt->pkt_datalen, KM_SLEEP);
 
@@ -3255,8 +3294,9 @@
 
 	/* Alloc internal packet */
 	icmd = fcp_icmd_alloc(pptr, ptgt, sizeof (la_els_logi_t),
-	    sizeof (la_els_logi_t), 0, 0, lcount, tcount, 0,
-	    FC_INVALID_RSCN_COUNT);
+	    sizeof (la_els_logi_t), 0,
+	    pptr->port_state & FCP_STATE_FCA_IS_NODMA,
+	    lcount, tcount, 0, FC_INVALID_RSCN_COUNT);
 
 	if (icmd == NULL) {
 		ret = ENOMEM;
@@ -5056,7 +5096,8 @@
 
 	alloc = FCP_MAX(sizeof (la_els_logi_t), sizeof (la_els_prli_t));
 
-	icmd = fcp_icmd_alloc(pptr, ptgt, alloc, alloc, 0, 0, lcount, tcount,
+	icmd = fcp_icmd_alloc(pptr, ptgt, alloc, alloc, 0,
+	    pptr->port_state & FCP_STATE_FCA_IS_NODMA, lcount, tcount,
 	    cause, map_entry->map_rscn_info.ulp_rscn_count);
 
 	if (icmd == NULL) {
@@ -5134,7 +5175,8 @@
 	if (icmd == NULL) {
 		alloc = FCP_MAX(sizeof (la_els_logi_t),
 		    sizeof (la_els_prli_t));
-		icmd = fcp_icmd_alloc(pptr, ptgt, alloc, alloc, 0, 0,
+		icmd = fcp_icmd_alloc(pptr, ptgt, alloc, alloc, 0,
+		    pptr->port_state & FCP_STATE_FCA_IS_NODMA,
 		    lcount, tcount, cause, FC_INVALID_RSCN_COUNT);
 		if (icmd == NULL) {
 			FCP_TGT_TRACE(ptgt, tcount, FCP_TGT_TRACE_10);
@@ -5545,6 +5587,7 @@
 	pkt->pkt_cmd_fhdr.rsvd = 0;
 	pkt->pkt_comp = fcp_unsol_callback;
 	pkt->pkt_pd = NULL;
+	pkt->pkt_ub_resp_token = (opaque_t)buf;
 }
 
 
@@ -5564,22 +5607,24 @@
 
 	from = (struct la_els_prli *)buf->ub_buffer;
 	orig = (struct fcp_prli *)from->service_params;
-
 	if ((ptgt = fcp_get_target_by_did(pptr, buf->ub_frame.s_id)) !=
 	    NULL) {
 		mutex_enter(&ptgt->tgt_mutex);
 		tcount = ptgt->tgt_change_cnt;
 		mutex_exit(&ptgt->tgt_mutex);
 	}
+
 	mutex_enter(&pptr->port_mutex);
 	lcount = pptr->port_link_cnt;
 	mutex_exit(&pptr->port_mutex);
 
 	if ((icmd = fcp_icmd_alloc(pptr, ptgt, sizeof (la_els_prli_t),
-	    sizeof (la_els_prli_t), 0, 0, lcount, tcount, 0,
-	    FC_INVALID_RSCN_COUNT)) == NULL) {
+	    sizeof (la_els_prli_t), 0,
+	    pptr->port_state & FCP_STATE_FCA_IS_NODMA,
+	    lcount, tcount, 0, FC_INVALID_RSCN_COUNT)) == NULL) {
 		return (FC_FAILURE);
 	}
+
 	fpkt = icmd->ipkt_fpkt;
 	fpkt->pkt_tran_flags = FC_TRAN_CLASS3 | FC_TRAN_INTR;
 	fpkt->pkt_tran_type = FC_PKT_OUTBOUND;
@@ -5637,7 +5682,8 @@
 
 		if ((rval = fc_ulp_issue_els(pptr->port_fp_handle, fpkt)) !=
 		    FC_SUCCESS) {
-			if (rval == FC_STATEC_BUSY || rval == FC_OFFLINE) {
+			if ((rval == FC_STATEC_BUSY || rval == FC_OFFLINE) &&
+			    ptgt != NULL) {
 				fcp_queue_ipkt(pptr, fpkt);
 				return (FC_SUCCESS);
 			}
@@ -5951,7 +5997,8 @@
 		cmd_resp++;
 	}
 
-	if (fpkt->pkt_datalen != 0) {
+	if ((fpkt->pkt_datalen != 0) &&
+	    !(pptr->port_state & FCP_STATE_FCA_IS_NODMA)) {
 		/*
 		 * set up DMA handle and memory for the data in this packet
 		 */
@@ -5998,6 +6045,16 @@
 			*cp = pkt_data_cookie;
 		}
 
+	} else if (fpkt->pkt_datalen != 0) {
+		/*
+		 * If it's a pseudo FCA, then it can't support DMA even in
+		 * SCSI data phase.
+		 */
+		fpkt->pkt_data = kmem_alloc(fpkt->pkt_datalen, flags);
+		if (fpkt->pkt_data == NULL) {
+			goto fail;
+		}
+
 	}
 
 	return (FC_SUCCESS);
@@ -6012,6 +6069,10 @@
 			ddi_dma_mem_free(&fpkt->pkt_data_acc);
 		}
 		ddi_dma_free_handle(&fpkt->pkt_data_dma);
+	} else {
+		if (fpkt->pkt_data) {
+			kmem_free(fpkt->pkt_data, fpkt->pkt_datalen);
+		}
 	}
 
 	if (nodma) {
@@ -6042,6 +6103,13 @@
 			ddi_dma_mem_free(&fpkt->pkt_data_acc);
 		}
 		ddi_dma_free_handle(&fpkt->pkt_data_dma);
+	} else {
+		if (fpkt->pkt_data) {
+			kmem_free(fpkt->pkt_data, fpkt->pkt_datalen);
+		}
+		/*
+		 * Need we reset pkt_* to zero???
+		 */
 	}
 
 	if (icmd->ipkt_nodma) {
@@ -6471,7 +6539,6 @@
 	    "fcp_send_scsi: d_id=0x%x opcode=0x%x", ptgt->tgt_d_id, opcode);
 
 	nodma = (pptr->port_fcp_dma == FC_NO_DVMA_SPACE) ? 1 : 0;
-
 	icmd = fcp_icmd_alloc(pptr, ptgt, sizeof (struct fcp_cmd),
 	    FCP_MAX_RSP_IU_SIZE, alloc_len, nodma, lcount, tcount, cause,
 	    rscn_count);
@@ -6838,6 +6905,10 @@
 	struct fcp_lun	*plun;
 	struct fcp_rsp		response, *rsp;
 
+	ptgt = icmd->ipkt_tgt;
+	pptr = ptgt->tgt_port;
+	plun = icmd->ipkt_lun;
+
 	if (icmd->ipkt_nodma) {
 		rsp = (struct fcp_rsp *)fpkt->pkt_resp;
 	} else {
@@ -6846,10 +6917,6 @@
 		    sizeof (struct fcp_rsp));
 	}
 
-	ptgt = icmd->ipkt_tgt;
-	pptr = ptgt->tgt_port;
-	plun = icmd->ipkt_lun;
-
 	FCP_TRACE(fcp_logq, pptr->port_instbuf,
 	    fcp_trace, FCP_BUF_LEVEL_2, 0,
 	    "SCSI callback state=0x%x for %x, op_code=0x%x, "
@@ -7079,8 +7146,10 @@
 	}
 
 	ASSERT(rsp->fcp_u.fcp_status.scsi_status == STATUS_GOOD);
-
-	(void) ddi_dma_sync(fpkt->pkt_data_dma, 0, 0, DDI_DMA_SYNC_FORCPU);
+	if (!(pptr->port_state & FCP_STATE_FCA_IS_NODMA)) {
+		(void) ddi_dma_sync(fpkt->pkt_data_dma, 0, 0,
+		    DDI_DMA_SYNC_FORCPU);
+	}
 
 	switch (icmd->ipkt_opcode) {
 	case SCMD_INQUIRY:
@@ -8730,7 +8799,7 @@
 
 		pkt->pkt_resid = 0;
 
-		if (cmd->cmd_pkt->pkt_numcookies) {
+		if (fpkt->pkt_datalen) {
 			pkt->pkt_state |= STATE_XFERRED_DATA;
 			if (fpkt->pkt_data_resid) {
 				error++;
@@ -9762,17 +9831,30 @@
 			kmem_free(pathname, MAXPATHLEN);
 		}
 	}
-	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(pptr->port_link_cnt))
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(pptr->port_link_cnt));
 	pptr->port_link_cnt = 1;
-	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(pptr->port_link_cnt))
+	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(pptr->port_link_cnt));
 	pptr->port_id = s_id;
 	pptr->port_instance = instance;
-	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(pptr->port_state))
+	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(pptr->port_state));
 	pptr->port_state = FCP_STATE_INIT;
-	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(pptr->port_state))
-
-	pptr->port_dmacookie_sz = (pptr->port_data_dma_attr.dma_attr_sgllen *
-	    sizeof (ddi_dma_cookie_t));
+	if (pinfo->port_acc_attr == NULL) {
+		/*
+		 * The corresponding FCA doesn't support DMA at all
+		 */
+		pptr->port_state |= FCP_STATE_FCA_IS_NODMA;
+	}
+
+	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(pptr->port_state));
+
+	if (!(pptr->port_state & FCP_STATE_FCA_IS_NODMA)) {
+		/*
+		 * If FCA supports DMA in SCSI data phase, we need preallocate
+		 * dma cookie, so stash the cookie size
+		 */
+		pptr->port_dmacookie_sz = sizeof (ddi_dma_cookie_t) *
+		    pptr->port_data_dma_attr.dma_attr_sgllen;
+	}
 
 	/*
 	 * The two mutexes of fcp_port are initialized.	 The variable
@@ -9832,6 +9914,22 @@
 	tran->tran_teardown_pkt		= fcp_pkt_teardown;
 	tran->tran_hba_len		= pptr->port_priv_pkt_len +
 	    sizeof (struct fcp_pkt) + pptr->port_dmacookie_sz;
+	if (pptr->port_state & FCP_STATE_FCA_IS_NODMA) {
+		/*
+		 * If FCA don't support DMA, then we use different vectors to
+		 * minimize the effects on DMA code flow path
+		 */
+		tran->tran_start	   = fcp_pseudo_start;
+		tran->tran_init_pkt	   = fcp_pseudo_init_pkt;
+		tran->tran_destroy_pkt	   = fcp_pseudo_destroy_pkt;
+		tran->tran_sync_pkt	   = fcp_pseudo_sync_pkt;
+		tran->tran_dmafree	   = fcp_pseudo_dmafree;
+		tran->tran_setup_pkt	   = NULL;
+		tran->tran_teardown_pkt	   = NULL;
+		tran->tran_pkt_constructor = NULL;
+		tran->tran_pkt_destructor  = NULL;
+		pptr->port_data_dma_attr   = pseudo_fca_dma_attr;
+	}
 
 	/*
 	 * Allocate an ndi event handle
@@ -12214,10 +12312,15 @@
 	pptr->port_fp_modlinkage = *pinfo->port_linkage;
 	pptr->port_dip = pinfo->port_dip;
 	pptr->port_fp_handle = pinfo->port_handle;
-	pptr->port_data_dma_attr = *pinfo->port_data_dma_attr;
-	pptr->port_cmd_dma_attr = *pinfo->port_cmd_dma_attr;
-	pptr->port_resp_dma_attr = *pinfo->port_resp_dma_attr;
-	pptr->port_dma_acc_attr = *pinfo->port_acc_attr;
+	if (pinfo->port_acc_attr != NULL) {
+		/*
+		 * FCA supports DMA
+		 */
+		pptr->port_data_dma_attr = *pinfo->port_data_dma_attr;
+		pptr->port_cmd_dma_attr = *pinfo->port_cmd_dma_attr;
+		pptr->port_resp_dma_attr = *pinfo->port_resp_dma_attr;
+		pptr->port_dma_acc_attr = *pinfo->port_acc_attr;
+	}
 	pptr->port_priv_pkt_len = pinfo->port_fca_pkt_size;
 	pptr->port_max_exch = pinfo->port_fca_max_exch;
 	pptr->port_phys_state = pinfo->port_state;
@@ -13043,9 +13146,13 @@
 		 */
 		if (!i_ddi_devi_attached(ddi_get_parent(cdip))) {
 			rval = ndi_devi_bind_driver(cdip, flags);
+			FCP_TRACE(fcp_logq, pptr->port_instbuf,
+			    fcp_trace, FCP_BUF_LEVEL_3, 0,
+			    "!Invoking ndi_devi_bind_driver: rval=%d", rval);
 		} else {
 			rval = ndi_devi_online(cdip, flags);
 		}
+
 		/*
 		 * We log the message into trace buffer if the device
 		 * is "ses" and into syslog for any other device
@@ -15917,3 +16024,248 @@
 	}
 	*pplun_blacklist = NULL;
 }
+
+/*
+ * In fcp module,
+ *   pkt@scsi_pkt, cmd@fcp_pkt, icmd@fcp_ipkt, fpkt@fc_packet, pptr@fcp_port
+ */
+static struct scsi_pkt *
+fcp_pseudo_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
+    struct buf *bp, int cmdlen, int statuslen, int tgtlen,
+    int flags, int (*callback)(), caddr_t arg)
+{
+	fcp_port_t	*pptr = ADDR2FCP(ap);
+	fcp_pkt_t	*cmd  = NULL;
+	fc_frame_hdr_t	*hp;
+
+	/*
+	 * First step: get the packet
+	 */
+	if (pkt == NULL) {
+		pkt = scsi_hba_pkt_alloc(pptr->port_dip, ap, cmdlen, statuslen,
+		    tgtlen, sizeof (fcp_pkt_t) + pptr->port_priv_pkt_len,
+		    callback, arg);
+		if (pkt == NULL) {
+			return (NULL);
+		}
+
+		/*
+		 * All fields in scsi_pkt will be initialized properly or
+		 * set to zero. We need do nothing for scsi_pkt.
+		 */
+		/*
+		 * But it's our responsibility to link other related data
+		 * structures. Their initialization will be done, just
+		 * before the scsi_pkt will be sent to FCA.
+		 */
+		cmd		= PKT2CMD(pkt);
+		cmd->cmd_pkt	= pkt;
+		cmd->cmd_fp_pkt = &cmd->cmd_fc_packet;
+		/*
+		 * fc_packet_t
+		 */
+		cmd->cmd_fp_pkt->pkt_ulp_private = (opaque_t)cmd;
+		cmd->cmd_fp_pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd +
+		    sizeof (struct fcp_pkt));
+		cmd->cmd_fp_pkt->pkt_cmd = (caddr_t)&cmd->cmd_fcp_cmd;
+		cmd->cmd_fp_pkt->pkt_cmdlen = sizeof (struct fcp_cmd);
+		cmd->cmd_fp_pkt->pkt_resp = cmd->cmd_fcp_rsp;
+		cmd->cmd_fp_pkt->pkt_rsplen = FCP_MAX_RSP_IU_SIZE;
+		/*
+		 * Fill in the Fabric Channel Header
+		 */
+		hp = &cmd->cmd_fp_pkt->pkt_cmd_fhdr;
+		hp->r_ctl = R_CTL_COMMAND;
+		hp->rsvd = 0;
+		hp->type = FC_TYPE_SCSI_FCP;
+		hp->f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ;
+		hp->seq_id = 0;
+		hp->df_ctl  = 0;
+		hp->seq_cnt = 0;
+		hp->ox_id = 0xffff;
+		hp->rx_id = 0xffff;
+		hp->ro = 0;
+	} else {
+		/*
+		 * We need think if we should reset any elements in
+		 * related data structures.
+		 */
+		FCP_TRACE(fcp_logq, pptr->port_instbuf,
+		    fcp_trace, FCP_BUF_LEVEL_6, 0,
+		    "reusing pkt, flags %d", flags);
+		cmd = PKT2CMD(pkt);
+		if (cmd->cmd_fp_pkt->pkt_pd) {
+			cmd->cmd_fp_pkt->pkt_pd = NULL;
+		}
+	}
+
+	/*
+	 * Second step:	 dma allocation/move
+	 */
+	if (bp && bp->b_bcount != 0) {
+		/*
+		 * Mark if it's read or write
+		 */
+		if (bp->b_flags & B_READ) {
+			cmd->cmd_flags |= CFLAG_IS_READ;
+		} else {
+			cmd->cmd_flags &= ~CFLAG_IS_READ;
+		}
+
+		bp_mapin(bp);
+		cmd->cmd_fp_pkt->pkt_data = bp->b_un.b_addr;
+		cmd->cmd_fp_pkt->pkt_datalen = bp->b_bcount;
+		cmd->cmd_fp_pkt->pkt_data_resid = 0;
+	} else {
+		/*
+		 * It seldom happens, except when CLUSTER or SCSI_VHCI wants
+		 * to send zero-length read/write.
+		 */
+		cmd->cmd_fp_pkt->pkt_data = NULL;
+		cmd->cmd_fp_pkt->pkt_datalen = 0;
+	}
+
+	return (pkt);
+}
+
+static void
+fcp_pseudo_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	fcp_port_t	*pptr = ADDR2FCP(ap);
+
+	/*
+	 * First we let FCA to uninitilize private part.
+	 */
+	fc_ulp_uninit_packet(pptr->port_fp_handle, PKT2CMD(pkt)->cmd_fp_pkt);
+
+	/*
+	 * Then we uninitialize fc_packet.
+	 */
+
+	/*
+	 * Thirdly, we uninitializae fcp_pkt.
+	 */
+
+	/*
+	 * In the end, we free scsi_pkt.
+	 */
+	scsi_hba_pkt_free(ap, pkt);
+}
+
+static int
+fcp_pseudo_start(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	fcp_port_t	*pptr = ADDR2FCP(ap);
+	fcp_lun_t	*plun = ADDR2LUN(ap);
+	fcp_tgt_t	*ptgt = plun->lun_tgt;
+	fcp_pkt_t	*cmd  = PKT2CMD(pkt);
+	fcp_cmd_t	*fcmd = &cmd->cmd_fcp_cmd;
+	fc_packet_t	*fpkt = cmd->cmd_fp_pkt;
+	int		 rval;
+
+	fpkt->pkt_pd = ptgt->tgt_pd_handle;
+	fc_ulp_init_packet(pptr->port_fp_handle, cmd->cmd_fp_pkt, 1);
+
+	/*
+	 * Firstly, we need initialize fcp_pkt_t
+	 * Secondly, we need initialize fcp_cmd_t.
+	 */
+	bcopy(pkt->pkt_cdbp, fcmd->fcp_cdb, pkt->pkt_cdblen);
+	fcmd->fcp_data_len = fpkt->pkt_datalen;
+	fcmd->fcp_ent_addr = plun->lun_addr;
+	if (pkt->pkt_flags & FLAG_HTAG) {
+		fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_HEAD_OF_Q;
+	} else if (pkt->pkt_flags & FLAG_OTAG) {
+		fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_ORDERED;
+	} else if (pkt->pkt_flags & FLAG_STAG) {
+		fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_SIMPLE;
+	} else {
+		fcmd->fcp_cntl.cntl_qtype = FCP_QTYPE_UNTAGGED;
+	}
+
+	if (cmd->cmd_flags & CFLAG_IS_READ) {
+		fcmd->fcp_cntl.cntl_read_data = 1;
+		fcmd->fcp_cntl.cntl_write_data = 0;
+	} else {
+		fcmd->fcp_cntl.cntl_read_data = 0;
+		fcmd->fcp_cntl.cntl_write_data = 1;
+	}
+
+	/*
+	 * Then we need initialize fc_packet_t too.
+	 */
+	fpkt->pkt_timeout = pkt->pkt_time + 2;
+	fpkt->pkt_cmd_fhdr.d_id = ptgt->tgt_d_id;
+	fpkt->pkt_cmd_fhdr.s_id = pptr->port_id;
+	if (cmd->cmd_flags & CFLAG_IS_READ) {
+		fpkt->pkt_tran_type = FC_PKT_FCP_READ;
+	} else {
+		fpkt->pkt_tran_type = FC_PKT_FCP_WRITE;
+	}
+
+	if (pkt->pkt_flags & FLAG_NOINTR) {
+		fpkt->pkt_comp = NULL;
+		fpkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_NO_INTR);
+	} else {
+		fpkt->pkt_comp = fcp_cmd_callback;
+		fpkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR);
+		if (pkt->pkt_flags & FLAG_IMMEDIATE_CB) {
+			fpkt->pkt_tran_flags |= FC_TRAN_IMMEDIATE_CB;
+		}
+	}
+
+	/*
+	 * Lastly, we need initialize scsi_pkt
+	 */
+	pkt->pkt_reason = CMD_CMPLT;
+	pkt->pkt_state = 0;
+	pkt->pkt_statistics = 0;
+	pkt->pkt_resid = 0;
+
+	/*
+	 * if interrupts aren't allowed (e.g. at dump time) then we'll
+	 * have to do polled I/O
+	 */
+	if (pkt->pkt_flags & FLAG_NOINTR) {
+		return (fcp_dopoll(pptr, cmd));
+	}
+
+	cmd->cmd_state = FCP_PKT_ISSUED;
+	rval = fcp_transport(pptr->port_fp_handle, fpkt, 0);
+	if (rval == FC_SUCCESS) {
+		return (TRAN_ACCEPT);
+	}
+
+	/*
+	 * Need more consideration
+	 *
+	 * pkt->pkt_flags & FLAG_NOQUEUE could abort other pkt
+	 */
+	cmd->cmd_state = FCP_PKT_IDLE;
+	if (rval == FC_TRAN_BUSY) {
+		return (TRAN_BUSY);
+	} else {
+		return (TRAN_FATAL_ERROR);
+	}
+}
+
+/*
+ * scsi_poll will always call tran_sync_pkt for pseudo FC-HBAs
+ * SCSA will initialize it to scsi_sync_cache_pkt for physical FC-HBAs
+ */
+static void
+fcp_pseudo_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	FCP_TRACE(fcp_logq, "fcp_pseudo_sync_pkt", fcp_trace,
+	    FCP_BUF_LEVEL_2, 0, "ap-%p, scsi_pkt-%p", ap, pkt);
+}
+
+/*
+ * scsi_dmafree will always call tran_dmafree, when STATE_ARQ_DONE
+ */
+static void
+fcp_pseudo_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
+{
+	FCP_TRACE(fcp_logq, "fcp_pseudo_dmafree", fcp_trace,
+	    FCP_BUF_LEVEL_2, 0, "ap-%p, scsi_pkt-%p", ap, pkt);
+}
--- a/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c	Wed Aug 05 17:14:23 2009 -0700
@@ -33,17 +33,14 @@
 #include <sys/scsi/scsi.h>
 #include <sys/var.h>
 #include <sys/byteorder.h>
-
 #include <sys/fibre-channel/fc.h>
 #include <sys/fibre-channel/impl/fc_ulpif.h>
 #include <sys/fibre-channel/ulp/fcsm.h>
 
 /* Definitions */
-#define	FCSM_VERSION		"1.27"
+#define	FCSM_VERSION		"20090729-1.28"
 #define	FCSM_NAME_VERSION	"SunFC FCSM v" FCSM_VERSION
 
-
-
 /* Global Variables */
 static char		fcsm_name[] = "FCSM";
 static void		*fcsm_state = NULL;
@@ -68,7 +65,7 @@
 
 #ifdef DEBUG
 uint32_t		fcsm_debug = (SMDL_TRACE | SMDL_IO |
-			    SMDL_ERR | SMDL_INFO);
+    SMDL_ERR | SMDL_INFO);
 #endif
 
 
@@ -289,7 +286,7 @@
 _fini(void)
 {
 	int	rval;
-#ifdef  DEBUG
+#ifdef	DEBUG
 	int	status;
 #endif /* DEBUG */
 
@@ -668,6 +665,12 @@
 	fcsm->sm_flags |= FCSM_ATTACHED;
 	fcsm->sm_port_top = pinfo->port_flags;
 	fcsm->sm_port_state = pinfo->port_state;
+	if (pinfo->port_acc_attr == NULL) {
+		/*
+		 * The corresponding FCA doesn't support DMA at all
+		 */
+		fcsm->sm_flags |= FCSM_USING_NODMA_FCA;
+	}
 	mutex_exit(&fcsm->sm_mutex);
 
 	(void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname);
@@ -972,18 +975,18 @@
 	 */
 
 	switch (cmd) {
-		case FC_CMD_DETACH:
-		case FC_CMD_SUSPEND:
-		case FC_CMD_POWER_DOWN:
-			break;
-
-		default:
-			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
-			    "port_detach: port unknown cmd 0x%x", cmd));
-			mutex_enter(&fcsm_global_mutex);
-			fcsm_num_detaching--;
-			mutex_exit(&fcsm_global_mutex);
-			return (rval);
+	case FC_CMD_DETACH:
+	case FC_CMD_SUSPEND:
+	case FC_CMD_POWER_DOWN:
+		break;
+
+	default:
+		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL,
+		    "port_detach: port unknown cmd 0x%x", cmd));
+		mutex_enter(&fcsm_global_mutex);
+		fcsm_num_detaching--;
+		mutex_exit(&fcsm_global_mutex);
+		return (rval);
 	};
 
 	if (fcsm_handle_port_detach(pinfo, fcsm, cmd) == DDI_SUCCESS) {
@@ -1020,25 +1023,25 @@
 	mutex_enter(&fcsm->sm_mutex);
 
 	switch (cmd) {
-		case FC_CMD_DETACH:
-			flag = FCSM_DETACHING;
-			break;
-
-		case FC_CMD_SUSPEND:
-		case FC_CMD_POWER_DOWN:
-			(cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) : \
-			    (flag = FCSM_POWER_DOWN);
-			if (fcsm->sm_flags &
-			    (FCSM_POWER_DOWN | FCSM_SUSPENDED)) {
-				fcsm->sm_flags |= flag;
-				mutex_exit(&fcsm->sm_mutex);
-				return (DDI_SUCCESS);
-			}
-			break;
-
-		default:
+	case FC_CMD_DETACH:
+		flag = FCSM_DETACHING;
+		break;
+
+	case FC_CMD_SUSPEND:
+	case FC_CMD_POWER_DOWN:
+		((cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) :
+		    (flag = FCSM_POWER_DOWN));
+		if (fcsm->sm_flags &
+		    (FCSM_POWER_DOWN | FCSM_SUSPENDED)) {
+			fcsm->sm_flags |= flag;
 			mutex_exit(&fcsm->sm_mutex);
-			return (DDI_FAILURE);
+			return (DDI_SUCCESS);
+		}
+		break;
+
+	default:
+		mutex_exit(&fcsm->sm_mutex);
+		return (DDI_FAILURE);
 	};
 
 	fcsm->sm_flags |= flag;
@@ -1625,7 +1628,7 @@
 
 	case  FCSMIO_ADAPTER_LIST: {
 		fc_hba_list_t	*list;
-		int		count;
+		int			count;
 
 		if ((fcio->fcio_xfer != FCIO_XFER_RW) ||
 		    (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) {
@@ -1648,7 +1651,8 @@
 
 		count = fc_ulp_get_adapter_paths((char *)list->hbaPaths,
 		    list->numAdapters);
-		if (count < 0) { /* Did something go wrong? */
+		if (count < 0) {
+			/* Did something go wrong? */
 			FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL,
 			    "Error fetching adapter list."));
 			retval = ENXIO;
@@ -1851,17 +1855,17 @@
 	}
 
 	switch (flags) {
-		case SM_LOG:
-			cmn_err(level, "!%s", buf);
-			break;
-
-		case SM_CONSOLE:
-			cmn_err(level, "^%s", buf);
-			break;
-
-		default:
-			cmn_err(level, "%s", buf);
-			break;
+	case SM_LOG:
+		cmn_err(level, "!%s", buf);
+		break;
+
+	case SM_CONSOLE:
+		cmn_err(level, "^%s", buf);
+		break;
+
+	default:
+		cmn_err(level, "%s", buf);
+		break;
 	}
 
 	kmem_free(buf, 256);
@@ -1974,16 +1978,25 @@
 	pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd + sizeof (fcsm_cmd_t));
 	pkt->pkt_ulp_private = (opaque_t)cmd;
 
-	pinfo = &fcsm->sm_port_info;
-	if (ddi_dma_alloc_handle(pinfo->port_dip, pinfo->port_cmd_dma_attr,
-	    callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
-		return (1);
-	}
-
-	if (ddi_dma_alloc_handle(pinfo->port_dip, pinfo->port_resp_dma_attr,
-	    callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
-		ddi_dma_free_handle(&pkt->pkt_cmd_dma);
-		return (1);
+	if (!(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
+		pinfo = &fcsm->sm_port_info;
+		if (ddi_dma_alloc_handle(pinfo->port_dip,
+		    pinfo->port_cmd_dma_attr,
+		    callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) {
+			return (1);
+		}
+
+		if (ddi_dma_alloc_handle(pinfo->port_dip,
+		    pinfo->port_resp_dma_attr,
+		    callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) {
+			ddi_dma_free_handle(&pkt->pkt_cmd_dma);
+			return (1);
+		}
+	} else {
+		pkt->pkt_cmd_dma  = NULL;
+		pkt->pkt_cmd	  = NULL;
+		pkt->pkt_resp_dma = NULL;
+		pkt->pkt_resp	  = NULL;
 	}
 
 	pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL;
@@ -2071,7 +2084,7 @@
 		return (NULL);
 	}
 
-	if (cmd_len) {
+	if ((cmd_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
 		ASSERT(pkt->pkt_cmd_dma != NULL);
 
 		rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len,
@@ -2140,9 +2153,11 @@
 			ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
 			*cp = pkt_cookie;
 		}
+	} else if (cmd_len != 0) {
+		pkt->pkt_cmd = kmem_zalloc(cmd_len, KM_SLEEP);
 	}
 
-	if (resp_len) {
+	if ((resp_len) && !(fcsm->sm_flags & FCSM_USING_NODMA_FCA)) {
 		ASSERT(pkt->pkt_resp_dma != NULL);
 
 		rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len,
@@ -2211,6 +2226,8 @@
 			ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie);
 			*cp = pkt_cookie;
 		}
+	} else if (resp_len != 0) {
+		pkt->pkt_resp = kmem_zalloc(resp_len, KM_SLEEP);
 	}
 
 	pkt->pkt_cmdlen = cmd_len;
@@ -2247,6 +2264,18 @@
 	pkt = cmd->cmd_fp_pkt;
 	ASSERT(pkt != NULL);
 
+	if (cmd->cmd_fcsm->sm_flags & FCSM_USING_NODMA_FCA) {
+		if (pkt->pkt_cmd) {
+			kmem_free(pkt->pkt_cmd, pkt->pkt_cmdlen);
+			pkt->pkt_cmd = NULL;
+		}
+
+		if (pkt->pkt_resp) {
+			kmem_free(pkt->pkt_resp, pkt->pkt_rsplen);
+			pkt->pkt_resp = NULL;
+		}
+	}
+
 	pkt->pkt_cmdlen = 0;
 	pkt->pkt_rsplen = 0;
 	pkt->pkt_tran_type = 0;
@@ -2320,7 +2349,7 @@
 		job->job_code		= FCSM_JOB_NONE;
 		job->job_flags		= 0;
 		job->job_port_instance	= -1;
-		job->job_result 	= -1;
+		job->job_result		= -1;
 		job->job_arg		= (opaque_t)0;
 		job->job_caller_priv	= (opaque_t)0;
 		job->job_comp		= NULL;
@@ -2349,8 +2378,8 @@
 	job->job_port_instance	= instance;
 	job->job_code		= command;
 	job->job_flags		= flags;
-	job->job_arg 		= arg;
-	job->job_caller_priv 	= caller_priv;
+	job->job_arg		= arg;
+	job->job_caller_priv	= caller_priv;
 	job->job_comp		= comp;
 	job->job_comp_arg	= comp_arg;
 	job->job_retry_count	= 0;
@@ -2743,6 +2772,7 @@
 	fc_packet_t	*pkt;
 	fcsm_job_t	*job;
 	fcio_t		*fcio;
+	fcsm_t		*fcsm;
 
 	pkt = cmd->cmd_fp_pkt;
 	job = cmd->cmd_job;
@@ -2758,6 +2788,7 @@
 		    pkt->pkt_cmd_fhdr.d_id));
 	} else {
 		/* Get the CT response payload */
+		fcsm = cmd->cmd_fcsm;
 		FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf,
 		    pkt->pkt_resp, fcio->fcio_olen);
 	}
@@ -3121,7 +3152,6 @@
 		    pkt->pkt_resp, sizeof (la_els_logi_t));
 	}
 
-
 	job->job_result =
 	    fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason);
 
@@ -3257,7 +3287,7 @@
 	if (fcsm->sm_flags & FCSM_LINK_DOWN) {
 		/*
 		 * No need to retry the command. The link previously
-		 * suffered an offline  timeout.
+		 * suffered an offline	timeout.
 		 */
 		mutex_exit(&fcsm->sm_mutex);
 		FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL,
@@ -3548,7 +3578,7 @@
 
 			/*
 			 * No need to retry the command. The link has
-			 * suffered an offline  timeout.
+			 * suffered an offline	timeout.
 			 */
 			pkt = cmd->cmd_fp_pkt;
 			pkt->pkt_state = FC_PKT_PORT_OFFLINE;
--- a/usr/src/uts/common/sys/fcoe/fcoe_common.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fcoe/fcoe_common.h	Wed Aug 05 17:14:23 2009 -0700
@@ -57,10 +57,8 @@
 #define	FLOGI_REQ_PAYLOAD_SIZE	116
 #define	FLOGI_ACC_PAYLOAD_SIZE	116
 
-/*
- * Minimum MTU size
- */
 #define	FCOE_MIN_MTU_SIZE	2500
+#define	FCOE_MAX_FC_FRAME_SIZE	2136
 
 /*
  * 24 byte FC frame header
@@ -96,10 +94,19 @@
 typedef struct fcoe_frame {
 	uint32_t		 frm_flags;
 	void			*frm_netb;
+
+	/*
+	 * frm_hdr will be cleared by fcoe explicitly
+	 */
 	fcoe_fc_frame_header_t	*frm_hdr;
 	uint8_t			*frm_ofh1;
 	uint8_t			*frm_ofh2;
 	uint8_t			*frm_fc_frame;
+
+	/*
+	 * fcoe client need clear FC payload explicitly,
+	 * except for RD/WR data frames
+	 */
 	uint8_t			*frm_payload;
 	uint32_t		 frm_fc_frame_size;
 	uint32_t		 frm_payload_size;
@@ -107,6 +114,7 @@
 	struct fcoe_port	*frm_eport;
 	void			*frm_fcoe_private;
 	void			*frm_client_private;
+	clock_t			 frm_clock;
 } fcoe_frame_t;
 
 /*
@@ -122,6 +130,7 @@
 	uint32_t	   eport_mtu;
 	uint64_t	   eport_link_speed;
 	uint8_t		   eport_efh_dst[ETHERADDRL];
+
 	void		 (*eport_tx_frame)(fcoe_frame_t *frame);
 	fcoe_frame_t	*(*eport_alloc_frame)(struct fcoe_port *eport,
 	    uint32_t this_fc_frame_size, void *netb);
@@ -152,7 +161,23 @@
 #define	FCOE_CMD_PORT_ONLINE		(FCOE_PORT_CTL_CMDS | 0x01)
 #define	FCOE_CMD_PORT_OFFLINE		(FCOE_PORT_CTL_CMDS | 0x02)
 
+/*
+ * FCoE version control
+ */
+typedef enum fcoe_ver
+{
+	FCOE_VER_1 = 0xAA01,
+	FCOE_VER_2,
+	FCOE_VER_3,
+	FCOE_VER_4,
+	FCOE_VER_5
+} fcoe_ver_e;
+
+#define	FCOE_VER_NOW FCOE_VER_1
+extern const fcoe_ver_e fcoe_ver_now;
+
 typedef struct fcoe_client {
+	fcoe_ver_e	 ect_fcoe_ver;
 	uint32_t	 ect_eport_flags;
 	uint32_t	 ect_max_fc_frame_size;
 	uint32_t	 ect_private_frame_struct_size;
@@ -262,6 +287,7 @@
  * frame header checking
  */
 #define	FRM_IS_LAST_FRAME(x_frm)		(FRM_F_CTL(x_frm) & (1 << 19))
+#define	FRM_SENDER_IS_XCH_RESPONDER(x_frm)	(FRM_F_CTL(x_frm) & (1 << 23))
 
 /*
  * FCOET/FCOEI will only call this fcoe function explicitly, all others
@@ -336,7 +362,24 @@
 /*
  * FCOE project global functions
  */
+#if !defined(__FUNCTION__)
+#define	__FUNCTION__ ((caddr_t)__func__)
+#endif
+
+#define	FCOE_STR_LEN 32
+
+/*
+ * timestamp (golbal variable in sys/systm.h)
+ */
+#define	CURRENT_CLOCK lbolt
 #define	FCOE_SEC2TICK(x_sec)	(drv_usectohz((x_sec) * 1000000))
+
+/*
+ * Form/convert mod_hash_key from/to xch ID
+ */
+#define	FMHK(x_xid)		(mod_hash_key_t)(uintptr_t)(x_xid)
+#define	CMHK(x_key)		(uint16_t)(uintptr_t)(x_key)
+
 typedef void (*TQ_FUNC_P)(void *);
 extern void fcoe_trace(caddr_t ident, const char *fmt, ...);
 
--- a/usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h	Wed Aug 05 17:14:23 2009 -0700
@@ -19,21 +19,19 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_FC_PORTIF_H
 #define	_FC_PORTIF_H
 
-
 #include <sys/note.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-
 /*
  * To remove the port WWN from the orphan list; An orphan list
  * scan typically happens during ONLINE processing (after a LIP
@@ -103,6 +101,7 @@
 #define	FP_DETACH_INPROGRESS		0x0200
 #define	FP_DETACH_FAILED		0x0400
 #define	FP_SOFT_NO_PMCOMP		0x0800
+#define	FP_SOFT_FCA_IS_NODMA		0x1000
 
 /*
  * Instruct the port driver to just accept logins from these addresses
@@ -144,14 +143,14 @@
 /*
  * Structure for issuing a work request to the per-instance "job handler"
  * thread. Primarily allocated/initialized by fctl_alloc_job() and freed by
- * fctl_dealloc_job().  fctl keeps a kmem_cache of these structs anchored by the
+ * fctl_dealloc_job().	fctl keeps a kmem_cache of these structs anchored by the
  * fctl_job_cache global variable.  The cache is created at fctl's _init(9E) and
  * destroyed at fctl's _fini(9E).  See also fctl_cache_constructor()
  * and fctl_cache_destructor().
  */
 typedef struct job_request {
 	/*
-	 * ID code for the job or task to be performed.  Set by fctl_alloc_job()
+	 * ID code for the job or task to be performed.	 Set by fctl_alloc_job()
 	 * and read by fp_job_handler().
 	 */
 	int		job_code;
@@ -197,7 +196,7 @@
 	 * maintained on a per-instance basis by the fp_port_head and
 	 * fp_port_tail pointers in the fc_local_port_t struct.
 	 */
-	struct job_request 	*job_next;
+	struct job_request	*job_next;
 } job_request_t;
 
 
@@ -250,7 +249,7 @@
  *
  * JOB_TYPE_FCTL_ASYNC is set in various places in fp and fctl. If set then
  * fctl_jobdone() will call the completion function in the job_comp field and
- * deallocate the job_request_t struct.  If not set then fctl_jobdone() will
+ * deallocate the job_request_t struct.	 If not set then fctl_jobdone() will
  * sema_v() the job_fctl_sema to wake up any waiting thread.  This bit is also
  * checked in fc_ulp_login(): if *clear* then fc_ulp_login() will call
  * fctl_jobwait() in order to block the calling thread in the job_fctl_sema, and
@@ -258,7 +257,7 @@
  *
  * JOB_TYPE_FP_ASYNC is set in various places in fp. If set then fp_jobdone()
  * will call fctl_jobdone(); if clear then fp_jobdone() will sema_v() the
- * job_port_sema in the job_request_t.  fp_port_shutdown() also looks for
+ * job_port_sema in the job_request_t.	fp_port_shutdown() also looks for
  * JOB_TYPE_FP_ASYNC.  Just to keep thing interesting, JOB_TYPE_FP_ASYNC is
  * also set in fp_validate_area_domain() and cleared in fp_fcio_login() and
  * fp_ns_get_devcount()
@@ -281,7 +280,7 @@
 	uint32_t	clist_state;		/* port state */
 	uint32_t	clist_len;		/* map len */
 	uint32_t	clist_size;		/* alloc len */
-	fc_portmap_t 	*clist_map;		/* changelist */
+	fc_portmap_t	*clist_map;		/* changelist */
 	uint32_t	clist_flags;		/* port topology */
 	uint32_t	clist_wait;		/* for synchronous requests */
 	kmutex_t	clist_mutex;		/* clist lock */
@@ -329,13 +328,34 @@
 	struct fc_orphan	*orp_next;	/* Next orphan */
 } fc_orphan_t;
 
+#define	FC_GET_RSP(x_port, x_handle, x_dest, x_src, x_size, x_flag)	\
+	{								\
+		if (!((x_port)->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {\
+			ddi_rep_get8((x_handle), (uint8_t *)(x_dest),	\
+				    (uint8_t *)(x_src), (x_size),	\
+				    (x_flag));				\
+		} else {						\
+			bcopy((x_src), (x_dest), (x_size));		\
+		}							\
+	}
+
+#define	FC_SET_CMD(x_port, x_handle, x_src, x_dest, x_size, x_flag)	\
+	{								\
+		if (!((x_port)->fp_soft_state & FP_SOFT_FCA_IS_NODMA)) {\
+			ddi_rep_put8((x_handle), (uint8_t *)(x_src),	\
+				    (uint8_t *)(x_dest), (x_size),	\
+				    (x_flag));				\
+		} else {						\
+			bcopy((x_src), (x_dest), (x_size));		\
+		}							\
+	}
+
 #if	!defined(__lint)
 _NOTE(SCHEME_PROTECTS_DATA("scans don't interleave",
-	fc_orphan::orp_nscan fc_orphan::orp_pwwn fc_orphan::orp_tstamp))
+    fc_orphan::orp_nscan fc_orphan::orp_pwwn fc_orphan::orp_tstamp))
 _NOTE(MUTEX_PROTECTS_DATA(fc_local_port::fp_mutex, fc_orphan::orp_next))
 #endif /* __lint */
 
-
 fc_remote_node_t *fctl_create_remote_node(la_wwn_t *nwwn, int sleep);
 void fctl_destroy_remote_node(fc_remote_node_t *rnp);
 fc_remote_port_t *fctl_create_remote_port(fc_local_port_t *port,
--- a/usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h	Wed Aug 05 17:14:23 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -154,6 +154,9 @@
 #define	NSRJTX_BADPORTID	0x11	/* Unacceptable port ID */
 #define	NSRJTX_DBEMPTY		0x12	/* Data base empty */
 
+/* Management Service Command Codes */
+#define	MS_GIEL		0x0101	/* Get Interconnect Element List */
+
 #define	FC_NS_CLASSF		0x01
 #define	FC_NS_CLASS1		0x02
 #define	FC_NS_CLASS2		0x04
--- a/usr/src/uts/common/sys/fibre-channel/impl/fctl.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/impl/fctl.h	Wed Aug 05 17:14:23 2009 -0700
@@ -70,6 +70,9 @@
 #define	FC_STATE_FULL_SPEED		FC_STATE_1GBIT_SPEED
 #define	FC_STATE_DOUBLE_SPEED		FC_STATE_2GBIT_SPEED
 
+/* pi_port_state, used only when binding port */
+#define	FC_STATE_FCA_IS_NODMA		0x80000000
+
 /*
  * Macros to discriminate between the link state byte and the link speed
  * byte in fp_state (also good for improved code obfuscation and job security
@@ -98,7 +101,6 @@
 #define	FC_NOTIFY_GET_FLAG(cmd)		FC_NOTIFY_FLAG_MASK(cmd)
 #define	FC_NOTIFY_GET_VALUE(cmd)	(FC_NOTIFY_VALUE_MASK(cmd) >> 8)
 
-
 /*
  * pkt_tran_flags definitions
  */
@@ -151,7 +153,7 @@
 	struct buf		*pkt_data_buf;		/* reserved */
 	void			(*pkt_ulp_comp)(struct fc_packet *);
 							/* framework private */
-	opaque_t		pkt_ulp_private; 	/* caller's private */
+	opaque_t		pkt_ulp_private;	/* caller's private */
 	void			(*pkt_comp)(struct fc_packet *); /* callback */
 	struct fc_remote_port	*pkt_pd;		/* port device */
 	ddi_dma_handle_t	pkt_cmd_dma;		/* command DMA */
@@ -162,12 +164,12 @@
 	ddi_dma_cookie_t	*pkt_resp_cookie;	/* response cookie */
 	ddi_dma_handle_t	pkt_data_dma;		/* data DMA */
 	ddi_acc_handle_t	pkt_data_acc;		/* data access */
-	ddi_dma_cookie_t	*pkt_data_cookie; 	/* data cookie */
+	ddi_dma_cookie_t	*pkt_data_cookie;	/* data cookie */
 	uint_t			pkt_cmd_cookie_cnt;
 	uint_t			pkt_resp_cookie_cnt;
 	uint_t			pkt_data_cookie_cnt;	/* of a window */
 	fc_frame_hdr_t		pkt_cmd_fhdr;		/* command frame hdr */
-	opaque_t		pkt_fca_private; 	/* FCA private */
+	opaque_t		pkt_fca_private;	/* FCA private */
 	uchar_t			pkt_state;		/* packet state */
 	uchar_t			pkt_action;		/* packet action */
 	uchar_t			pkt_expln;		/* reason explanation */
@@ -228,7 +230,7 @@
 #define	FC_HBA_PORTSPEED_4GBIT		8    /* 4 GBit/sec */
 #define	FC_HBA_PORTSPEED_8GBIT		16   /* 8 GBit/sec */
 #define	FC_HBA_PORTSPEED_16GBIT		32   /* 16 GBit/sec */
-#define	FC_HBA_PORTSPEED_NOT_NEGOTIATED	(1<<15)   /* Speed not established */
+#define	FC_HBA_PORTSPEED_NOT_NEGOTIATED	(1<<15)	  /* Speed not established */
 
 #define	FCHBA_MANUFACTURER_LEN		64
 #define	FCHBA_SERIAL_NUMBER_LEN		64
@@ -275,7 +277,7 @@
 	opaque_t	ub_port_handle;
 	opaque_t	ub_resp_token;		/* Response token */
 	uint64_t	ub_token;
-	fc_frame_hdr_t 	ub_frame;
+	fc_frame_hdr_t	ub_frame;
 } fc_unsol_buf_t;
 
 #define	FC_UB_RESP_LOGIN_REQUIRED	0x4000
--- a/usr/src/uts/common/sys/fibre-channel/ulp/fcp.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/ulp/fcp.h	Wed Aug 05 17:14:23 2009 -0700
@@ -19,14 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_FCP_H
 #define	_FCP_H
 
-
 /*
  * Frame format and protocol definitions for transferring
  * commands and data between a SCSI initiator and target
@@ -50,7 +49,6 @@
 #define	FCP_SCSI_RSP		0x03	/* frame contains SCSI response */
 #define	FCP_SCSI_XFER_RDY	0x05	/* frame contains xfer rdy block */
 
-
 /*
  * fcp SCSI control structure
  */
@@ -109,7 +107,6 @@
 #define	FCP_QTYPE_ACA_Q_TAG	4		/* ACA queueing */
 #define	FCP_QTYPE_UNTAGGED	5		/* Untagged */
 
-
 /*
  * fcp SCSI entity address
  *
@@ -125,7 +122,6 @@
 	ushort_t ent_addr_3;		/* entity address 3 */
 } fcp_ent_addr_t;
 
-
 /*
  * maximum size of SCSI cdb in fcp SCSI command
  */
@@ -143,7 +139,6 @@
 	int		fcp_data_len;			/* data length */
 } fcp_cmd_t;
 
-
 /*
  * fcp SCSI status
  */
@@ -170,7 +165,6 @@
 	uchar_t	scsi_status;			/* status of cmd */
 } fcp_status_t;
 
-
 /*
  * fcp SCSI response payload
  */
@@ -190,11 +184,9 @@
 	 */
 } fcp_rsp_t;
 
-
 /* MAde 256 for sonoma as it wants to give tons of sense info */
 #define	FCP_MAX_RSP_IU_SIZE	256
 
-
 /*
  * fcp rsp_info field format
  */
@@ -219,7 +211,6 @@
 #define		FCP_TASK_MGMT_NOT_SUPPTD	0x4
 #define		FCP_TASK_MGMT_FAILED		0x5
 
-
 #ifdef	THIS_NEEDED_YET
 
 /*
@@ -289,33 +280,51 @@
 
 };
 
-
 /*
  * fcp PRLI ACC payload
  */
 struct fcp_prli_acc {
 	uchar_t		type;
-	uchar_t		resvd1;
+	uchar_t		resvd1; /* type code extension */
 
-	uint32_t	orig_process_assoc_valid : 1;
-	uint32_t	resp_process_assoc_valid : 1;
-	uint32_t	image_pair_established : 1;
-	uint32_t	resvd2 : 1;
-	uint32_t	accept_response_code : 4;
-	uint32_t	resvd3 : 8;
+#if	defined(_BIT_FIELDS_HTOL)
+	uint16_t	orig_process_assoc_valid : 1,
+			resp_process_assoc_valid : 1,
+			image_pair_established : 1,
+			resvd2 : 1,
+			accept_response_code : 4,
+			resvd3 : 8;
+#elif	defined(_BIT_FIELDS_LTOH)
+	uint16_t	resvd3 : 8,
+			accept_response_code : 4,
+			resvd2 : 1,
+			image_pair_established : 1,
+			resp_process_assoc_valid : 1,
+			orig_process_assoc_valid : 1;
+#endif
+
 	uint32_t	orig_process_associator;
 	uint32_t	resp_process_associator;
-	uint32_t	resvd4 : 26;
-	uint32_t	initiator_fn : 1;
-	uint32_t	target_fn : 1;
-	uint32_t	cmd_data_mixed : 1;
-	uint32_t	data_resp_mixed : 1;
-	uint32_t	read_xfer_rdy_disabled : 1;
-	uint32_t	write_xfer_rdy_disabled : 1;
 
+#if	defined(_BIT_FIELDS_HTOL)
+	uint32_t	resvd4 : 26,
+			initiator_fn : 1,
+			target_fn : 1,
+			cmd_data_mixed : 1,
+			data_resp_mixed : 1,
+			read_xfer_rdy_disabled : 1,
+			write_xfer_rdy_disabled : 1;
+#elif	defined(_BIT_FIELDS_LTOH)
+	uint32_t	write_xfer_rdy_disabled : 1,
+			read_xfer_rdy_disabled : 1,
+			data_resp_mixed : 1,
+			cmd_data_mixed : 1,
+			target_fn : 1,
+			initiator_fn : 1,
+			resvd4 : 26;
+#endif
 };
 
-
 #define	FC_UB_FCP_CDB_FLAG	0x0001		/* UB has valid cdb */
 #define	FC_UB_FCP_PORT_LOGOUT	0x0002		/* Port logout UB */
 #define	FC_UB_FCP_ABORT_TASK	0x0004		/* Abort task UB */
--- a/usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h	Wed Aug 05 17:14:23 2009 -0700
@@ -26,8 +26,6 @@
 #ifndef	_FCPVAR_H
 #define	_FCPVAR_H
 
-
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -127,7 +125,7 @@
  * This is the master structure off of which all the others will be hanging at
  * some point and is the Solaris per-instance soft-state structure.
  */
-struct fcp_port {
+typedef struct fcp_port {
 	/*
 	 * This mutex protects the access to this structure (or most of its
 	 * fields).
@@ -409,7 +407,7 @@
 	 * list.
 	 */
 	int			port_dmacookie_sz;
-};
+} fcp_port_t;
 
 /*
  * We need to save the target change count values in a map tag so as
@@ -438,6 +436,11 @@
  */
 #define	FCP_STATE_IN_CB_DEVC		0x0400
 
+/*
+ * FCP_STATE_FCA_IS_NODMA indicates that FCA doesn't support DMA at all
+ */
+#define	FCP_STATE_FCA_IS_NODMA		0x80000000
+
 #define	FCP_MAX_DEVICES			127
 
 /* To remember that dip was allocated for a lun on this target. */
@@ -521,7 +524,7 @@
  * (a)	The underlying FCA does NOT support DMA for this field
  * (b)	The underlying FCA supports DMA for this field
  */
-struct fcp_pkt {
+typedef struct fcp_pkt {
 	/*
 	 * The two following fields are used to queue fcp_pkt in the double
 	 * link list of the lun structure.  The packet is queued in
@@ -578,7 +581,7 @@
 	 * fp/fctl.
 	 */
 	struct fc_packet	cmd_fc_packet;
-};
+} fcp_pkt_t;
 
 /*
  * fcp_ipkt : Packet for internal commands.
@@ -645,7 +648,7 @@
  * (a)	The underlying FCA does NOT support DMA for this field
  * (b)	The underlying FCA supports DMA for this field
  */
-struct fcp_ipkt {
+typedef struct fcp_ipkt {
 	/*
 	 * Pointer to the port (fcp_port) in behalf of which this internal
 	 * packet was allocated.
@@ -713,7 +716,7 @@
 	 * FC packet.
 	 */
 	struct fc_packet	ipkt_fc_packet;
-};
+} fcp_ipkt_t;
 
 /*
  * cmd_state definitions
@@ -725,7 +728,9 @@
 /*
  * These are the defined cmd_flags for this structure.
  */
-#define	CFLAG_IN_QUEUE		0x2000	/* command in fcp queue */
+#define	CFLAG_NONE		0x0000
+#define	CFLAG_IS_READ		0x0001
+#define	CFLAG_IN_QUEUE		0x0002	/* command in fcp queue */
 
 /*
  * Target structure
@@ -735,7 +740,7 @@
  * structure doesn't represent the object registered with the OS (NDI or
  * MPxIO...).
  */
-struct fcp_tgt {
+typedef struct fcp_tgt {
 	/*
 	 * This field is used to queue the target structure in one of the
 	 * buckets of the fcp_port target hash table port_tgt_hash_table[].
@@ -850,7 +855,7 @@
 	 * used to detect user unconfig when auto configuration is enabled.
 	 */
 	uint32_t		tgt_manual_config_only;
-};
+} fcp_tgt_t;
 
 /*
  * Target States
@@ -964,7 +969,7 @@
  * structure is the one representing the object registered with the OS (NDI
  * or MPxIO...).
  */
-struct fcp_lun {
+typedef struct fcp_lun {
 	/*
 	 * Mutex protecting the access to this structure.
 	 */
@@ -1058,7 +1063,7 @@
 	 * LUN inquiry data (as returned by the INQUIRY command).
 	 */
 	struct scsi_inquiry	lun_inq;
-};
+} fcp_lun_t;
 
 
 /*
@@ -1297,10 +1302,10 @@
 	int				masked;
 } fcp_black_list_entry_t;
 
-#define	ADDR2FCP(ap)	((struct fcp_port *) \
-			    ((ap)->a_hba_tran->tran_hba_private))
-#define	ADDR2LUN(ap)	((struct fcp_lun *) \
-			scsi_device_hba_private_get(scsi_address_device(ap)))
+#define	ADDR2FCP(ap)	((struct fcp_port *)		\
+		((ap)->a_hba_tran->tran_hba_private))
+#define	ADDR2LUN(ap)	((struct fcp_lun *)				\
+		scsi_device_hba_private_get(scsi_address_device(ap)))
 #define	CMD2PKT(cmd)	((cmd)->cmd_pkt)
 #define	PKT2CMD(pkt)	((struct fcp_pkt *)((pkt)->pkt_ha_private))
 
@@ -1366,13 +1371,28 @@
     scsi_pkt scsi_arq_status scsi_device scsi_hba_tran scsi_cdb))
 #endif	/* __lint */
 
-#define	FCP_CP_IN(s, d, handle, len)	(ddi_rep_get8((handle), \
-					(uint8_t *)(d), (uint8_t *)(s), \
-					(len), DDI_DEV_AUTOINCR))
+/*
+ * Local variable "pptr" must exist before using these
+ */
+#define	FCP_CP_IN(s, d, handle, len)					\
+	{								\
+		if (!((pptr)->port_state & FCP_STATE_FCA_IS_NODMA)) {	\
+			ddi_rep_get8((handle), (uint8_t *)(d),		\
+			    (uint8_t *)(s), (len), DDI_DEV_AUTOINCR);	\
+		} else {						\
+			bcopy((s), (d), (len));				\
+		}							\
+	}
 
-#define	FCP_CP_OUT(s, d, handle, len)	(ddi_rep_put8((handle), \
-					(uint8_t *)(s), (uint8_t *)(d), \
-					(len), DDI_DEV_AUTOINCR))
+#define	FCP_CP_OUT(s, d, handle, len)				\
+	{								\
+		if (!((pptr)->port_state & FCP_STATE_FCA_IS_NODMA)) {	\
+			ddi_rep_put8((handle), (uint8_t *)(s),		\
+			    (uint8_t *)(d), (len), DDI_DEV_AUTOINCR);	\
+		} else {						\
+			bcopy((s), (d), (len));				\
+		}							\
+	}
 
 #define	FCP_ONLINE			0x1
 #define	FCP_OFFLINE			0x2
--- a/usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h	Wed Aug 05 17:14:23 2009 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_FCSM_H
 #define	_FCSM_H
 
-
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -95,7 +93,7 @@
 	ksema_t		job_sema;		/* To wait for completion */
 	struct fcsm_job	*job_next;		/* for linked list */
 	int		job_retry_count;	/* Retry count */
-	void		*job_priv;		/* for fcsm private use  */
+	void		*job_priv;		/* for fcsm private use	 */
 	uint32_t	job_priv_flags;		/* fcsm private flags */
 } fcsm_job_t;
 
@@ -163,6 +161,7 @@
 #define	FCSM_LINK_DOWN			0x1000
 #define	FCSM_MGMT_SERVER_LOGGED_IN	0x2000
 #define	FCSM_MGMT_SERVER_LOGIN_IN_PROG	0x4000
+#define	FCSM_USING_NODMA_FCA		0x8000
 
 /* Command flags for Job structure */
 #define	FCSM_JOBFLAG_SYNC		0x01
@@ -197,48 +196,29 @@
 
 /*
  * Macros to address endian issues
+ * local variable "fcsm" must exist before using these
  */
-#define	FCSM_RD8(acchandle, addr)       \
-	ddi_get8((acchandle), (uint8_t *)(addr))
-#define	FCSM_RD16(acchandle, addr)      \
-	ddi_get16((acchandle), (uint16_t *)(addr))
-#define	FCSM_RD32(acchandle, addr)      \
-	ddi_get32((acchandle), (uint32_t *)(addr))
-#define	FCSM_RD64(acchandle, addr)      \
-	ddi_get64((acchandle), (uint64_t *)(addr))
-
-#define	FCSM_WR8(acchandle, addr, val)  \
-	ddi_put8((acchandle), (uint8_t *)(addr), (uint8_t)(val))
-#define	FCSM_WR16(acchandle, addr, val) \
-	ddi_put16((acchandle), (uint16_t *)(addr), (uint16_t)(val))
-#define	FCSM_WR32(acchandle, addr, val) \
-	ddi_put32((acchandle), (uint32_t *)(addr), (uint32_t)(val))
-#define	FCSM_WR64(acchandle, addr, val) \
-	ddi_put64((acchandle), (uint64_t *)(addr), (uint64_t)(val))
+#define	FCSM_REP_RD(handle, hostaddr, devaddr, cnt)			\
+	{								\
+		if (!((fcsm)->sm_flags & FCSM_USING_NODMA_FCA)) {	\
+			ddi_rep_get8((handle), (uint8_t *)(hostaddr),	\
+				    (uint8_t *)(devaddr), (cnt),	\
+				    DDI_DEV_AUTOINCR);			\
+		} else {						\
+			bcopy((devaddr), (hostaddr), (cnt));		\
+		}							\
+	}
 
-#define	FCSM_REP_RD(acchandle, hostaddr, devaddr, cnt)  \
-	ddi_rep_get8((acchandle), (uint8_t *)(hostaddr), (uint8_t *)(devaddr),\
-	    (size_t)(cnt), DDI_DEV_AUTOINCR)
-#define	FCSM_REP_RD32(acchandle, hostaddr, devaddr, cnt)        \
-	ddi_rep_get32((acchandle), (uint32_t *)(hostaddr),      \
-	    (uint32_t *)(devaddr), ((size_t)(cnt)) >> 2, DDI_DEV_AUTOINCR)
-
-#define	FCSM_REP_WR(acchandle, hostaddr, devaddr, cnt)  \
-	ddi_rep_put8((acchandle), (uint8_t *)(hostaddr), (uint8_t *)(devaddr),\
-	    (size_t)(cnt), DDI_DEV_AUTOINCR)
-#define	FCSM_REP_WR32(acchandle, hostaddr, devaddr, cnt)        \
-	ddi_rep_put32((acchandle), (uint32_t *)(hostaddr),\
-	    (uint32_t *)(devaddr), ((size_t)(cnt)) >> 2, DDI_DEV_AUTOINCR)
-
-/*
- * Macros to perform DMA Sync
- */
-#define	FCSM_SYNC_FOR_DEV(dmahandle, offset, length)    \
-	(void) ddi_dma_sync((dmahandle), (offset),\
-	    (size_t)(length), DDI_DMA_SYNC_FORDEV)
-#define	FCSM_SYNC_FOR_KERNEL(dmahandle, offset, length) \
-	(void) ddi_dma_sync((acchandle), (offset),\
-	    (length), DDI_DMA_SYNC_FORKERNEL)
+#define	FCSM_REP_WR(handle, hostaddr, devaddr, cnt)			\
+	{								\
+		if (!((fcsm)->sm_flags & FCSM_USING_NODMA_FCA)) {	\
+			ddi_rep_put8((handle), (uint8_t *)(hostaddr),	\
+				    (uint8_t *)(devaddr), (cnt),	\
+				    DDI_DEV_AUTOINCR);			\
+		} else {						\
+			bcopy((hostaddr), (devaddr), (cnt));		\
+		}							\
+	}
 
 #endif /* _KERNEL */
 
--- a/usr/src/uts/intel/Makefile.intel.shared	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Wed Aug 05 17:14:23 2009 -0700
@@ -353,6 +353,7 @@
 DRV_KMODS	+= fct
 DRV_KMODS	+= fcoe
 DRV_KMODS	+= fcoet
+DRV_KMODS	+= fcoei
 DRV_KMODS	+= qlt
 DRV_KMODS	+= iscsit
 DRV_KMODS	+= ncall nsctl sdbc nskern sv
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/fcoei/Makefile	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,85 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	This makefile drives the production of the fcoei driver for 
+#	LEADVILLE.
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+ARCHDIR:sh = cd ..; basename `pwd`
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= fcoei
+OBJECTS		= $(FCOEI_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(FCOEI_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io/fibre-channel/fca/fcoei
+
+#
+#	Include common rules.
+#
+include ../Makefile.$(ARCHDIR)
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Overrides and depends_on
+#
+LDFLAGS		+= -dy -Nmisc/fctl -Ndrv/fcoe
+INC_PATH	+= -I$(UTSBASE)/common/io/fibre-channel/fca/fcoei
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include ../Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Wed Aug 05 16:12:50 2009 -0700
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Wed Aug 05 17:14:23 2009 -0700
@@ -303,6 +303,7 @@
 DRV_KMODS	+= fct
 DRV_KMODS	+= fcoe
 DRV_KMODS	+= fcoet
+DRV_KMODS	+= fcoei
 DRV_KMODS	+= qlt
 DRV_KMODS	+= iscsit
 DRV_KMODS	+= ncall nsctl sdbc nskern sv
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/fcoei/Makefile	Wed Aug 05 17:14:23 2009 -0700
@@ -0,0 +1,85 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#	This makefile drives the production of the fcoei driver for 
+#	LEADVILLE.
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+ARCHDIR:sh = cd ..; basename `pwd`
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= fcoei
+OBJECTS		= $(FCOEI_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(FCOEI_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/io/fibre-channel/fca/fcoei
+
+#
+#	Include common rules.
+#
+include ../Makefile.$(ARCHDIR)
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Overrides and depends_on
+#
+LDFLAGS		+= -dy -Nmisc/fctl -Ndrv/fcoe
+INC_PATH	+= -I$(UTSBASE)/common/io/fibre-channel/fca/fcoei
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include ../Makefile.targ