summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorZhong Wang <Zhong.Wang@Sun.COM>2009-08-05 17:14:23 -0700
committerZhong Wang <Zhong.Wang@Sun.COM>2009-08-05 17:14:23 -0700
commit7ff836697c120cb94bd30d5c2204eb9b74718e4c (patch)
tree2fec718afdfa781207ea1408a409fd0394e89bd8 /usr/src
parent0df7087fda4bb16f7e1cf07d1b90fcf070c19484 (diff)
downloadillumos-joyent-7ff836697c120cb94bd30d5c2204eb9b74718e4c.tar.gz
PSARC 2008/311 FCoE (Fibre Channel over Ethernet) Initiator
6823827 FCoE initiator for Leadville
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fcinfo/fcinfo.c5
-rw-r--r--usr/src/cmd/fcinfo/fcoeadm.c43
-rw-r--r--usr/src/cmd/fcoesvc/Makefile44
-rw-r--r--usr/src/cmd/fcoesvc/fcoe_initiator.xml102
-rw-r--r--usr/src/cmd/fcoesvc/fcoeisvc.c64
-rw-r--r--usr/src/lib/storage/libg_fc/common/genf.c4
-rw-r--r--usr/src/pkgdefs/Makefile1
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/Makefile33
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/depend52
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/pkginfo.tmpl50
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/postinstall54
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/preremove33
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/prototype_com41
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/prototype_i38653
-rw-r--r--usr/src/pkgdefs/SUNWfcoei/prototype_sparc52
-rw-r--r--usr/src/pkgdefs/SUNWfcprtr/preremove3
-rw-r--r--usr/src/pkgdefs/SUNWfcprtr/prototype_com2
-rw-r--r--usr/src/tools/scripts/bfu.sh2
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet.c2
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet.h2
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c4
-rw-r--r--usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c1
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe.c39
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe.h1
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe_eth.c5
-rw-r--r--usr/src/uts/common/io/fcoe/fcoe_fc.c26
-rw-r--r--usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c1130
-rw-r--r--usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.conf24
-rw-r--r--usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.h371
-rw-r--r--usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c1390
-rw-r--r--usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_lv.c2065
-rw-r--r--usr/src/uts/common/io/fibre-channel/impl/fctl.c805
-rw-r--r--usr/src/uts/common/io/fibre-channel/impl/fp.c284
-rw-r--r--usr/src/uts/common/io/fibre-channel/ulp/fcp.c408
-rw-r--r--usr/src/uts/common/io/fibre-channel/ulp/fcsm.c154
-rw-r--r--usr/src/uts/common/sys/fcoe/fcoe_common.h49
-rw-r--r--usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h42
-rw-r--r--usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h5
-rw-r--r--usr/src/uts/common/sys/fibre-channel/impl/fctl.h14
-rw-r--r--usr/src/uts/common/sys/fibre-channel/ulp/fcp.h61
-rw-r--r--usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h68
-rw-r--r--usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h70
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared1
-rw-r--r--usr/src/uts/intel/fcoei/Makefile85
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared1
-rw-r--r--usr/src/uts/sparc/fcoei/Makefile85
48 files changed, 7068 insertions, 771 deletions
diff --git a/usr/src/cmd/fcinfo/fcinfo.c b/usr/src/cmd/fcinfo/fcinfo.c
index 8f94354c11..bb8b95ee60 100644
--- a/usr/src/cmd/fcinfo/fcinfo.c
+++ b/usr/src/cmd/fcinfo/fcinfo.c
@@ -78,6 +78,7 @@ optionTbl_t fcadmlongOptions[] = {
{"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 @@ subCommandProps_t fcadmsubcommands[] = {
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}
};
diff --git a/usr/src/cmd/fcinfo/fcoeadm.c b/usr/src/cmd/fcinfo/fcoeadm.c
index c3ffe637b2..5d9a4a9dd3 100644
--- a/usr/src/cmd/fcinfo/fcoeadm.c
+++ b/usr/src/cmd/fcinfo/fcoeadm.c
@@ -86,11 +86,11 @@ printFCOEPortInfo(FCOE_PORT_ATTRIBUTE *attr)
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_adm_delete_port(int objects, char *argv[])
{
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 @@ fcoe_adm_delete_port(int objects, char *argv[])
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:
diff --git a/usr/src/cmd/fcoesvc/Makefile b/usr/src/cmd/fcoesvc/Makefile
index ab4bd84e4b..e15836ce3c 100644
--- a/usr/src/cmd/fcoesvc/Makefile
+++ b/usr/src/cmd/fcoesvc/Makefile
@@ -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 @@ install: all $(ROOTMANIFEST) $(ROOTSVCMETHOD)
check: $(CHKMANIFEST)
$(CSTYLE) -pPc $(SRCS:%=%)
-cmdparse.o:
- $(COMPILE.c) -o $@
- $(POST_PROCESS_O)
-
clean:
- $(RM) $(OBJS)
+ $(RM) $(OBJSFCOET) ${OBJSFCOEI}
-lint: lint_SRCS
+lint:
+ $(LINT.c) $(SRCSFCOET) $(LDLIBS)
+ $(LINT.c) $(SRCSFCOEI) ${LDLIBS}
include ../Makefile.targ
diff --git a/usr/src/cmd/fcoesvc/fcoe_initiator.xml b/usr/src/cmd/fcoesvc/fcoe_initiator.xml
new file mode 100644
index 0000000000..4fc2081d71
--- /dev/null
+++ b/usr/src/cmd/fcoesvc/fcoe_initiator.xml
@@ -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>
diff --git a/usr/src/cmd/fcoesvc/fcoeisvc.c b/usr/src/cmd/fcoesvc/fcoeisvc.c
new file mode 100644
index 0000000000..99bd01b5c6
--- /dev/null
+++ b/usr/src/cmd/fcoesvc/fcoeisvc.c
@@ -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 */
diff --git a/usr/src/lib/storage/libg_fc/common/genf.c b/usr/src/lib/storage/libg_fc/common/genf.c
index 930aa39fa2..7359923974 100644
--- a/usr/src/lib/storage/libg_fc/common/genf.c
+++ b/usr/src/lib/storage/libg_fc/common/genf.c
@@ -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 @@ struct str_type {
static struct str_type ValidBusStrings[] = {
{"pci@", PCI_BUS},
{"sbus@", SBUS},
+ {"fcoe", FCOE},
{NULL, 0}
};
diff --git a/usr/src/pkgdefs/Makefile b/usr/src/pkgdefs/Makefile
index 298a22abdc..3e9f63d267 100644
--- a/usr/src/pkgdefs/Makefile
+++ b/usr/src/pkgdefs/Makefile
@@ -255,6 +255,7 @@ COMMON_SUBDIRS= \
SUNWfcoe \
SUNWfcoeu \
SUNWfcoet \
+ SUNWfcoei \
SUNWfilebench \
SUNWfmd \
SUNWfmdr \
diff --git a/usr/src/pkgdefs/SUNWfcoei/Makefile b/usr/src/pkgdefs/SUNWfcoei/Makefile
new file mode 100644
index 0000000000..0c86629d67
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/Makefile
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcoei/depend b/usr/src/pkgdefs/SUNWfcoei/depend
new file mode 100644
index 0000000000..d8cecedc17
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/depend
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcoei/pkginfo.tmpl b/usr/src/pkgdefs/SUNWfcoei/pkginfo.tmpl
new file mode 100644
index 0000000000..a2c467b3b4
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/pkginfo.tmpl
@@ -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"
diff --git a/usr/src/pkgdefs/SUNWfcoei/postinstall b/usr/src/pkgdefs/SUNWfcoei/postinstall
new file mode 100644
index 0000000000..dfff205ed7
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/postinstall
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcoei/preremove b/usr/src/pkgdefs/SUNWfcoei/preremove
new file mode 100644
index 0000000000..61ece22fbc
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/preremove
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcoei/prototype_com b/usr/src/pkgdefs/SUNWfcoei/prototype_com
new file mode 100644
index 0000000000..497cf4a41d
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/prototype_com
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcoei/prototype_i386 b/usr/src/pkgdefs/SUNWfcoei/prototype_i386
new file mode 100644
index 0000000000..f1f9e4c1f8
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/prototype_i386
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcoei/prototype_sparc b/usr/src/pkgdefs/SUNWfcoei/prototype_sparc
new file mode 100644
index 0000000000..f226d66477
--- /dev/null
+++ b/usr/src/pkgdefs/SUNWfcoei/prototype_sparc
@@ -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
diff --git a/usr/src/pkgdefs/SUNWfcprtr/preremove b/usr/src/pkgdefs/SUNWfcprtr/preremove
index cefdcb7b8e..896ee11ae8 100644
--- a/usr/src/pkgdefs/SUNWfcprtr/preremove
+++ b/usr/src/pkgdefs/SUNWfcprtr/preremove
@@ -71,4 +71,7 @@ disable_service
SERVICE="svc:/system/fcoe_target:default"
disable_service
+SERVICE="svc:/system/fcoe_initiator:default"
+disable_service
+
exit $exitcode
diff --git a/usr/src/pkgdefs/SUNWfcprtr/prototype_com b/usr/src/pkgdefs/SUNWfcprtr/prototype_com
index c9052a62f0..deefd7e657 100644
--- a/usr/src/pkgdefs/SUNWfcprtr/prototype_com
+++ b/usr/src/pkgdefs/SUNWfcprtr/prototype_com
@@ -47,9 +47,11 @@ d none var/svc/manifest 755 root sys
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
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index f63bc624de..33e20c31e4 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -313,6 +313,7 @@ superfluous_nonglobal_zone_files="
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 @@ superfluous_nonglobal_zone_files="
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
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 0076d096ee..3d4d975854 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -894,6 +894,8 @@ FCOE_OBJS += fcoe.o fcoe_eth.o fcoe_fc.o
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
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index 874e1eebb2..ced5768cb5 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -983,6 +983,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/fibre-channel/fca/emlxs/%.c
$(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/qlc/%.c
$(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))
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c
index 16a91d3f01..76ac37cef1 100644
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.c
@@ -453,6 +453,8 @@ fcoet_attach_init(fcoet_soft_state_t *ss)
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) {
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h
index e2859d7f17..d1bf7db1ff 100644
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet.h
@@ -33,7 +33,7 @@ extern "C" {
#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
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c
index e82cb206ab..d68d59ecc2 100644
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_eth.c
@@ -540,9 +540,11 @@ fcoet_process_sol_fcp_data(fcoe_frame_t *frm)
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;
diff --git a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c
index 962f9cef1a..96ad967ab4 100644
--- a/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c
+++ b/usr/src/uts/common/io/comstar/port/fcoet/fcoet_fc.c
@@ -234,6 +234,7 @@ fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
* 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);
diff --git a/usr/src/uts/common/io/fcoe/fcoe.c b/usr/src/uts/common/io/fcoe/fcoe.c
index 372995df44..f4cc784350 100644
--- a/usr/src/uts/common/io/fcoe/fcoe.c
+++ b/usr/src/uts/common/io/fcoe/fcoe.c
@@ -195,7 +195,7 @@ static struct dev_ops fcoe_ops = {
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 @@ static int fcoe_trace_buf_size = (1 * 1024 * 1024);
/*
* 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 @@ fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip,
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;
-
- if (strcmp(ddi_driver_name(client_dip), FCOET_DRIVER_NAME) == 0) {
- counter = &tgtcounter;
- tgtcounter++;
- } else {
- counter = &inicounter;
- inicounter++;
+ char client_addr[FCOE_STR_LEN];
+ int rval;
+
+ 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 @@ fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode)
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 @@ fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode)
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) {
diff --git a/usr/src/uts/common/io/fcoe/fcoe.h b/usr/src/uts/common/io/fcoe/fcoe.h
index 38a1a05cf8..fd79ff97e7 100644
--- a/usr/src/uts/common/io/fcoe/fcoe.h
+++ b/usr/src/uts/common/io/fcoe/fcoe.h
@@ -156,6 +156,7 @@ typedef struct fcoe_mac
#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 */
diff --git a/usr/src/uts/common/io/fcoe/fcoe_eth.c b/usr/src/uts/common/io/fcoe/fcoe_eth.c
index 7f2763c5cd..6332327f5e 100644
--- a/usr/src/uts/common/io/fcoe/fcoe_eth.c
+++ b/usr/src/uts/common/io/fcoe/fcoe_eth.c
@@ -199,6 +199,9 @@ fcoe_enable_callback(fcoe_mac_t *mac)
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 @@ fcoe_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t loopback)
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 @@ fcoe_mac_notify(void *arg, mac_notify_type_t type)
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);
diff --git a/usr/src/uts/common/io/fcoe/fcoe_fc.c b/usr/src/uts/common/io/fcoe/fcoe_fc.c
index 268bd1c05f..ba7b6cbad5 100644
--- a/usr/src/uts/common/io/fcoe/fcoe_fc.c
+++ b/usr/src/uts/common/io/fcoe/fcoe_fc.c
@@ -72,7 +72,11 @@ fcoe_register_client(fcoe_client_t *client)
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_deregister_client(fcoe_port_t *eport)
{
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 @@ fcoe_deregister_client(fcoe_port_t *eport)
}
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 @@ fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, datalink_id_t linkid,
}
*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);
}
- atomic_and_32(&mac->fm_eport.eport_flags, ~EPORT_FLAG_MAC_IN_USE);
+ 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 @@ fcoe_delete_port(dev_info_t *parent, fcoeio_t *fcoeio, datalink_id_t linkid,
fcoeio->fcoeio_status = FCOEIOE_OFFLINE_FAILURE;
return (EBUSY);
}
+
+skip_devi_offline:
(void) fcoe_close_mac(mac);
fcoe_destroy_mac(mac);
return (0);
diff --git a/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c
new file mode 100644
index 0000000000..6e24fe8198
--- /dev/null
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.c
@@ -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);
+ }
+}
diff --git a/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.conf b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.conf
new file mode 100644
index 0000000000..673f715efe
--- /dev/null
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.conf
@@ -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.
+#
diff --git a/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.h b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.h
new file mode 100644
index 0000000000..cbaa49b03c
--- /dev/null
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei.h
@@ -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 */
diff --git a/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c
new file mode 100644
index 0000000000..c7a8dedfeb
--- /dev/null
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_eth.c
@@ -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));
+}
diff --git a/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_lv.c b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_lv.c
new file mode 100644
index 0000000000..63d7655eca
--- /dev/null
+++ b/usr/src/uts/common/io/fibre-channel/fca/fcoei/fcoei_lv.c
@@ -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);
+ }
+}
diff --git a/usr/src/uts/common/io/fibre-channel/impl/fctl.c b/usr/src/uts/common/io/fibre-channel/impl/fctl.c
index 77ad0c5b11..036632faea 100644
--- a/usr/src/uts/common/io/fibre-channel/impl/fctl.c
+++ b/usr/src/uts/common/io/fibre-channel/impl/fctl.c
@@ -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 @@ static krwlock_t fctl_mod_ports_lock;
/*
* 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 @@ _NOTE(MUTEX_PROTECTS_DATA(ulp_ports::port_mutex, ulp_ports::port_statec
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 @@ static struct bus_ops fctl_fca_busops = {
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 remote_stop_reasons [] = {
};
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_pkt_reason_t rjt_reasons [] = {
{ 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_pkt_reason_t rjt_reasons [] = {
{ 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 @@ fc_pkt_error_t fc_pkt_errlist[] = {
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 @@ fctl_cache_destructor(void *buf, void *cdarg)
* 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_add(fc_ulp_modinfo_t *ulp_info)
{
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 @@ fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
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 @@ fc_ulp_add(fc_ulp_modinfo_t *ulp_info)
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 @@ fc_ulp_remove(fc_ulp_modinfo_t *ulp_info)
* 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 @@ int
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 @@ opaque_t
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 @@ fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
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 @@ fc_ulp_get_remote_port(opaque_t port_handle, la_wwn_t *pwwn, int *error,
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 @@ int
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 @@ int
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 @@ opaque_t
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_ulp_pwwn_to_portmap(opaque_t port_handle, la_wwn_t *bytes, fc_portmap_t *map)
{
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_ulp_enable_relogin(opaque_t *fc_port, la_wwn_t *pwwn)
/*
* 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 @@ fc_wwn_to_str(la_wwn_t *wwn, caddr_t str)
*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 @@ fc_str_to_wwn(caddr_t str, la_wwn_t *wwn)
*/
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 @@ fctl_fca_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
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 @@ fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
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 @@ fctl_findchild(dev_info_t *pdip, char *cname, char *caddr)
ddi_prop_free(addr);
}
} else {
- if (strcmp(caddr, addr) == 0)
+ if (strcmp(caddr, addr) == 0) {
return (dip);
+ }
}
}
@@ -2308,7 +2308,7 @@ fctl_fca_create_npivport(dev_info_t *parent,
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 @@ fctl_add_port(fc_local_port_t *port)
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 @@ fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
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 @@ fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
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 @@ fctl_attach_ulps(fc_local_port_t *port, fc_attach_cmd_t cmd,
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 @@ fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
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 @@ fctl_detach_ulps(fc_local_port_t *port, fc_detach_cmd_t cmd,
static void
fctl_init_dma_attr(fc_local_port_t *port, fc_ulp_module_t *mod,
- 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 */
- }
+ 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 */
+ }
}
static int
@@ -2984,8 +3000,8 @@ fctl_ulp_statec_cb(void *arg)
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 @@ fctl_ulp_statec_cb(void *arg)
* 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 @@ fctl_ulp_statec_cb(void *arg)
* 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 @@ fctl_ulp_statec_cb(void *arg)
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 @@ fctl_ulp_statec_cb(void *arg)
/*
* 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 @@ fctl_destroy_remote_node(fc_remote_node_t *rnodep)
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 @@ fctl_enlist_nwwn_table(fc_remote_node_t *rnodep, int sleep)
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 @@ fctl_delist_nwwn_table(fc_remote_node_t *rnodep)
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 @@ fctl_get_remote_node_by_nwwn(la_wwn_t *node_wwn)
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 @@ fctl_lock_remote_node_by_nwwn(la_wwn_t *node_wwn)
/*
* 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 @@ fctl_unlink_remote_port_from_remote_node(fc_remote_node_t *rnodep,
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 @@ fctl_enlist_did_table(fc_local_port_t *port, fc_remote_port_t *pd)
#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 @@ void
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 @@ fctl_enlist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
#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 @@ fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
{
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 @@ fctl_delist_pwwn_table(fc_local_port_t *port, fc_remote_port_t *pd)
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_ulp_hold_remote_port(opaque_t port_handle)
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 @@ fc_remote_port_t *
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 @@ fc_remote_port_t *
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 @@ fc_remote_port_t *
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 @@ fctl_hold_remote_port_by_pwwn(fc_local_port_t *port, la_wwn_t *pwwn)
* 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 @@ fctl_fillout_map(fc_local_port_t *port, fc_portmap_t **map, uint32_t *len,
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 @@ fctl_jobdone(job_request_t *job)
/*
- * 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 @@ fctl_jobdone(job_request_t *job)
int
fctl_wwn_cmp(la_wwn_t *src, la_wwn_t *dst)
{
- la_wwn_t tmpsrc, tmpdst;
+ uint8_t *l, *r;
+ int i;
+ uint64_t wl, wr;
- /*
- * 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]);
+ l = (uint8_t *)src;
+ r = (uint8_t *)dst;
- tmpdst.i_wwn[0] = BE_32(dst->i_wwn[0]);
- tmpdst.i_wwn[1] = BE_32(dst->i_wwn[1]);
+ 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];
+ }
- 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);
+ if (wl > wr) {
+ return (1);
+ } else if (wl == wr) {
+ return (0);
+ } else {
+ return (-1);
+ }
}
@@ -4499,7 +4516,7 @@ fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
{
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 @@ fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
/*
* 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 @@ fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
* 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 @@ fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
}
/*
- * 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 @@ fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
* 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 @@ fctl_create_remote_port(fc_local_port_t *port, la_wwn_t *node_wwn,
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 @@ fctl_destroy_remote_port(fc_local_port_t *port, fc_remote_port_t *pd)
* 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 @@ fctl_destroy_all_remote_ports(fc_local_port_t *port)
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 @@ fctl_ulp_unsol_cb(fc_local_port_t *port, fc_unsol_buf_t *buf, uchar_t type)
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 @@ fctl_copy_portmap(fc_portmap_t *map, fc_remote_port_t *pd)
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 @@ fctl_update_host_ns_values(fc_local_port_t *port, fc_ns_cmd_t *ns_req)
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 @@ fctl_ulp_port_ioctl(fc_local_port_t *port, dev_t dev, int cmd,
{
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 @@ fc_delete_npiv_port(fc_local_port_t *port, la_wwn_t *pwwn)
* 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 @@ fc_ulp_get_adapter_paths(char *pathList, int count)
/* 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;
+ if (portList[check] == NULL) {
+ continue;
+ }
+ /* Guard against duplicates (should never happen) */
+ if (portList[check] == fca_port->port_handle) {
+ /* Same port */
+ skip = 1;
+ break;
+ }
- /* 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;
+ /* 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);
+ 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 (!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 @@ fctl_add_orphan_held(fc_local_port_t *port, fc_remote_port_t *pd)
{
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 @@ fctl_add_orphan(fc_local_port_t *port, fc_remote_port_t *pd, int sleep)
{
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 @@ fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
{
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 @@ fctl_remove_if_orphan(fc_local_port_t *port, la_wwn_t *pwwn)
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 @@ fctl_pkt_error(fc_packet_t *pkt, char **state, char **reason,
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 @@ fctl_remove_oldies(fc_local_port_t *port)
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 @@ fctl_lookup_pd_by_did(fc_local_port_t *port, uint32_t d_id)
{
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 @@ void
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 @@ fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
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 @@ fc_trace_debug(fc_trace_logq_t *logq, caddr_t name, int dflag, int dlevel,
}
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 @@ fctl_lookup_pd_by_index(fc_local_port_t *port, uint32_t index)
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 @@ fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
{
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 @@ fctl_lookup_pd_by_wwn(fc_local_port_t *port, la_wwn_t wwn)
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);
+ 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;
}
- mutex_exit(&pd->pd_mutex);
- pd = pd->pd_wwn_hnext;
- }
}
/* No match */
return (NULL);
@@ -6244,7 +6267,7 @@ int
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 @@ fctl_count_fru_ports(fc_local_port_t *port, int npivflag)
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 @@ fc_local_port_t *
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 @@ fctl_get_adapter_port_by_index(fc_local_port_t *port, uint32_t port_index)
/* 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 @@ fctl_busy_port(fc_local_port_t *port)
* 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 @@ fctl_idle_port(fc_local_port_t *port)
*
* 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 @@ fctl_tc_timer(
* 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 @@ fctl_tc_constructor(
*
* 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 @@ fctl_tc_destructor(
* 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 @@ fctl_tc_increment(
* 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);
diff --git a/usr/src/uts/common/io/fibre-channel/impl/fp.c b/usr/src/uts/common/io/fibre-channel/impl/fp.c
index c2b6dc3e4b..7a5aab6505 100644
--- a/usr/src/uts/common/io/fibre-channel/impl/fp.c
+++ b/usr/src/uts/common/io/fibre-channel/impl/fp.c
@@ -95,7 +95,7 @@ static struct dev_ops fp_ops = {
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 @@ fp_attach_handler(dev_info_t *dip)
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 @@ fp_cache_constructor(void *buf, void *cdarg, int kmflags)
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 (!(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);
+ 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 @@ fp_cache_destructor(void *buf, void *cdarg)
* 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 @@ fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
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 @@ fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
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 @@ fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie);
*cp = pkt_cookie;
}
+ } 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) {
+ 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 @@ fp_alloc_pkt(fc_local_port_t *port, int cmd_len, int resp_len, int kmflags,
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 @@ alloc_pkt_failed:
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 @@ fp_free_pkt(fp_cmd_t *cmd)
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 @@ fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
}
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 @@ fp_register_login(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
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 @@ fp_xlogi_init(fc_local_port_t *port, fp_cmd_t *cmd, uint32_t s_id,
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 @@ fp_logo_init(fc_remote_port_t *pd, fp_cmd_t *cmd, job_request_t *job)
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 @@ fp_rnid_init(fp_cmd_t *cmd, uint16_t flag, job_request_t *job)
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 @@ fp_rls_init(fp_cmd_t *cmd, job_request_t *job)
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 @@ fp_adisc_init(fp_cmd_t *cmd, job_request_t *job)
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 @@ fp_plogi_group(fc_local_port_t *port, job_request_t *job)
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 @@ fp_plogi_group(fc_local_port_t *port, job_request_t *job)
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 @@ fp_ns_fini(fc_local_port_t *port, job_request_t *job)
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
}
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
}
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
}
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
}
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
} 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 @@ fp_ns_reg(fc_local_port_t *port, fc_remote_port_t *pd, uint16_t cmd_code,
#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 @@ fp_flogi_intr(fc_packet_t *pkt)
*/
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 @@ fp_flogi_intr(fc_packet_t *pkt)
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 @@ fp_flogi_intr(fc_packet_t *pkt)
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 @@ fp_flogi_intr(fc_packet_t *pkt)
} 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 @@ fp_plogi_intr(fc_packet_t *pkt)
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 @@ fp_plogi_intr(fc_packet_t *pkt)
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 @@ fp_adisc_intr(fc_packet_t *pkt)
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 @@ fp_adisc_intr(fc_packet_t *pkt)
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 @@ static void
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 @@ fp_rnid_intr(fc_packet_t *pkt)
job_request_t *job;
fp_cmd_t *cmd;
la_els_rnid_acc_t *acc;
+ fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
- 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);
cmd = pkt->pkt_ulp_private;
@@ -6728,7 +6771,7 @@ fp_rnid_intr(fc_packet_t *pkt)
/* 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 @@ fp_rls_intr(fc_packet_t *pkt)
job_request_t *job;
fp_cmd_t *cmd;
la_els_rls_acc_t *acc;
+ fc_local_port_t *port = ((fp_cmd_t *)pkt->pkt_ulp_private)->cmd_port;
- 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);
cmd = pkt->pkt_ulp_private;
@@ -6767,7 +6811,7 @@ fp_rls_intr(fc_packet_t *pkt)
/* 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 @@ fp_ns_scr(fc_local_port_t *port, job_request_t *job, uchar_t scr_func,
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_linit_intr(fc_packet_t *pkt)
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 @@ fp_linit_intr(fc_packet_t *pkt)
}
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 @@ fp_ba_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
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 @@ fp_els_rjt_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
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 @@ fp_prlo_acc_init(fc_local_port_t *port, fc_remote_port_t *pd,
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 @@ fp_els_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
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 @@ fp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
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 @@ fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
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 @@ fp_i_handle_unsol_els(fc_local_port_t *port, fc_unsol_buf_t *buf)
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 @@ fp_login_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
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 @@ fp_fillout_new_nsmap(fc_local_port_t *port, ddi_acc_handle_t *handle,
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 @@ fp_remote_lip(fc_local_port_t *port, la_wwn_t *pwwn, int sleep,
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 @@ fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
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 @@ fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
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 @@ fp_stuff_device_with_gan(ddi_acc_handle_t *handle, fc_remote_port_t *pd,
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 @@ fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
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 @@ fp_ct_init(fc_local_port_t *port, fp_cmd_t *cmd, fctl_ns_req_t *ns_cmd,
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 @@ fp_ns_intr(fc_packet_t *pkt)
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 @@ fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
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 @@ fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
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 @@ fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
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 @@ fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
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 @@ fp_gan_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
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 @@ fp_ns_query_handler(fc_packet_t *pkt, fctl_ns_req_t *ns_cmd)
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 @@ fp_adisc_acc_init(fc_local_port_t *port, fp_cmd_t *cmd, fc_unsol_buf_t *buf,
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 @@ fp_bind_callbacks(fc_local_port_t *port)
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 @@ fp_validate_area_domain(fc_local_port_t *port, uint32_t id, uint32_t mask,
job->job_result = rval;
fp_jobdone(job);
}
-
FP_TRACE(FP_NHEAD2(4, 0),
"PLOGI succeeded:no skip(1) for "
"D_ID %x", d_id);
diff --git a/usr/src/uts/common/io/fibre-channel/ulp/fcp.c b/usr/src/uts/common/io/fibre-channel/ulp/fcp.c
index 8e0483433a..c2529cdb8a 100644
--- a/usr/src/uts/common/io/fibre-channel/ulp/fcp.c
+++ b/usr/src/uts/common/io/fibre-channel/ulp/fcp.c
@@ -625,6 +625,21 @@ static void fcp_add_one_mask(char *curr_pwwn, uint32_t lun_id,
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 @@ extern dev_info_t *scsi_vhci_dip;
(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 @@ int fcp_symmetric_disk_table_size =
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 @@ fcp_is_reconfig_needed(struct fcp_tgt *ptgt,
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 @@ fcp_tgt_send_plogi(struct fcp_tgt *ptgt, int *fc_status, int *fc_pkt_state,
/* 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 @@ fcp_handle_mapflags(struct fcp_port *pptr, struct fcp_tgt *ptgt,
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 @@ fcp_send_els(struct fcp_port *pptr, struct fcp_tgt *ptgt,
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 @@ fcp_unsol_resp_init(fc_packet_t *pkt, fc_unsol_buf_t *buf,
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 @@ fcp_unsol_prli(struct fcp_port *pptr, fc_unsol_buf_t *buf)
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 @@ fcp_unsol_prli(struct fcp_port *pptr, fc_unsol_buf_t *buf)
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 @@ fcp_alloc_dma(struct fcp_port *pptr, struct fcp_ipkt *icmd,
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 @@ fcp_alloc_dma(struct fcp_port *pptr, struct fcp_ipkt *icmd,
*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 @@ fail:
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 @@ fcp_free_dma(struct fcp_port *pptr, struct fcp_ipkt *icmd)
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(struct fcp_lun *plun, uchar_t opcode, int alloc_len,
"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 @@ fcp_scsi_callback(fc_packet_t *fpkt)
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 @@ fcp_scsi_callback(fc_packet_t *fpkt)
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 @@ fcp_scsi_callback(fc_packet_t *fpkt)
}
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 @@ fcp_complete_pkt(fc_packet_t *fpkt)
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 @@ fcp_handle_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo,
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))
+ 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));
- pptr->port_dmacookie_sz = (pptr->port_data_dma_attr.dma_attr_sgllen *
- sizeof (ddi_dma_cookie_t));
+ 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 @@ fcp_handle_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo,
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 @@ fcp_cp_pinfo(struct fcp_port *pptr, fc_ulp_port_info_t *pinfo)
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 @@ again:
*/
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 @@ fcp_cleanup_blacklist(struct fcp_black_list_entry **pplun_blacklist) {
}
*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);
+}
diff --git a/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c b/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c
index d94d163b9e..ea8f862b2d 100644
--- a/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c
+++ b/usr/src/uts/common/io/fibre-channel/ulp/fcsm.c
@@ -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 @@ static clock_t fcsm_offline_ticks;
#ifdef DEBUG
uint32_t fcsm_debug = (SMDL_TRACE | SMDL_IO |
- SMDL_ERR | SMDL_INFO);
+ SMDL_ERR | SMDL_INFO);
#endif
@@ -289,7 +286,7 @@ int
_fini(void)
{
int rval;
-#ifdef DEBUG
+#ifdef DEBUG
int status;
#endif /* DEBUG */
@@ -668,6 +665,12 @@ fcsm_handle_port_attach(fc_ulp_port_info_t *pinfo, uint32_t s_id, int instance)
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 @@ fcsm_port_detach(opaque_t ulph, fc_ulp_port_info_t *pinfo, fc_detach_cmd_t cmd)
*/
switch (cmd) {
- case FC_CMD_DETACH:
- case FC_CMD_SUSPEND:
- case FC_CMD_POWER_DOWN:
- break;
+ 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);
+ 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 @@ fcsm_handle_port_detach(fc_ulp_port_info_t *pinfo, fcsm_t *fcsm,
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;
+ case FC_CMD_DETACH:
+ flag = FCSM_DETACHING;
+ break;
- default:
+ 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 @@ fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio)
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 @@ fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio)
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 @@ fcsm_display(int level, int flags, fcsm_t *fcsm, fc_packet_t *pkt,
}
switch (flags) {
- case SM_LOG:
- cmn_err(level, "!%s", buf);
- break;
+ case SM_LOG:
+ cmn_err(level, "!%s", buf);
+ break;
- case SM_CONSOLE:
- cmn_err(level, "^%s", buf);
- break;
+ case SM_CONSOLE:
+ cmn_err(level, "^%s", buf);
+ break;
- default:
- cmn_err(level, "%s", buf);
- break;
+ default:
+ cmn_err(level, "%s", buf);
+ break;
}
kmem_free(buf, 256);
@@ -1974,16 +1978,25 @@ fcsm_cmd_cache_constructor(void *buf, void *cdarg, int kmflags)
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 (!(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);
+ 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 @@ fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
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 @@ fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
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 @@ fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep)
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 @@ fcsm_free_cmd_dma(fcsm_cmd_t *cmd)
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 @@ fcsm_alloc_job(int sleep)
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 @@ fcsm_init_job(fcsm_job_t *job, int instance, uint32_t command, uint32_t flags,
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 @@ fcsm_ct_intr(fcsm_cmd_t *cmd)
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 @@ fcsm_ct_intr(fcsm_cmd_t *cmd)
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 @@ fcsm_xlogi_intr(fcsm_cmd_t *cmd)
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 @@ fcsm_pkt_common_intr(fc_packet_t *pkt)
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 @@ fcsm_retry_timeout(void *handle)
/*
* 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;
diff --git a/usr/src/uts/common/sys/fcoe/fcoe_common.h b/usr/src/uts/common/sys/fcoe/fcoe_common.h
index c59554c2e7..6ab5ea2cbf 100644
--- a/usr/src/uts/common/sys/fcoe/fcoe_common.h
+++ b/usr/src/uts/common/sys/fcoe/fcoe_common.h
@@ -57,10 +57,8 @@ extern "C" {
#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 @@ struct fcoe_port;
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 @@ typedef struct fcoe_frame {
struct fcoe_port *frm_eport;
void *frm_fcoe_private;
void *frm_client_private;
+ clock_t frm_clock;
} fcoe_frame_t;
/*
@@ -122,6 +130,7 @@ typedef struct fcoe_port {
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 @@ typedef struct fcoe_port {
#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 @@ typedef struct fcoe_client {
* 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 @@ typedef struct fcoe_fcp_xfer_rdy {
/*
* 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, ...);
diff --git a/usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h b/usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h
index ca1a387dce..2abf07c386 100644
--- a/usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h
+++ b/usr/src/uts/common/sys/fibre-channel/impl/fc_portif.h
@@ -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 @@ extern "C" {
#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 @@ extern "C" {
/*
* 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 @@ typedef struct job_request {
* 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 @@ _NOTE(MUTEX_PROTECTS_DATA(job_request::job_mutex, job_request::job_counter))
*
* 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 @@ _NOTE(MUTEX_PROTECTS_DATA(job_request::job_mutex, job_request::job_counter))
*
* 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 @@ typedef struct fc_port_clist {
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 @@ typedef struct fc_orphan {
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,
diff --git a/usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h b/usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h
index f124055675..b18419299c 100644
--- a/usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h
+++ b/usr/src/uts/common/sys/fibre-channel/impl/fcgs2.h
@@ -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 @@ extern "C" {
#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
diff --git a/usr/src/uts/common/sys/fibre-channel/impl/fctl.h b/usr/src/uts/common/sys/fibre-channel/impl/fctl.h
index db66561121..8b672e82ef 100644
--- a/usr/src/uts/common/sys/fibre-channel/impl/fctl.h
+++ b/usr/src/uts/common/sys/fibre-channel/impl/fctl.h
@@ -70,6 +70,9 @@ extern "C" {
#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 @@ extern "C" {
#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 @@ typedef struct fc_packet {
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 @@ typedef struct fc_packet {
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 @@ typedef struct fca_hba_fru_details {
#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 @@ typedef struct unsolicited_buffer {
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
diff --git a/usr/src/uts/common/sys/fibre-channel/ulp/fcp.h b/usr/src/uts/common/sys/fibre-channel/ulp/fcp.h
index 3891293a15..8f6db0bd3a 100644
--- a/usr/src/uts/common/sys/fibre-channel/ulp/fcp.h
+++ b/usr/src/uts/common/sys/fibre-channel/ulp/fcp.h
@@ -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 @@ extern "C" {
#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 @@ typedef struct fcp_cntl {
#define FCP_QTYPE_ACA_Q_TAG 4 /* ACA queueing */
#define FCP_QTYPE_UNTAGGED 5 /* Untagged */
-
/*
* fcp SCSI entity address
*
@@ -125,7 +122,6 @@ typedef struct fcp_ent_addr {
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 @@ typedef struct fcp_cmd {
int fcp_data_len; /* data length */
} fcp_cmd_t;
-
/*
* fcp SCSI status
*/
@@ -170,7 +165,6 @@ typedef struct fcp_status {
uchar_t scsi_status; /* status of cmd */
} fcp_status_t;
-
/*
* fcp SCSI response payload
*/
@@ -190,11 +184,9 @@ typedef struct fcp_rsp {
*/
} 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 @@ struct fcp_rsp_info {
#define FCP_TASK_MGMT_NOT_SUPPTD 0x4
#define FCP_TASK_MGMT_FAILED 0x5
-
#ifdef THIS_NEEDED_YET
/*
@@ -289,33 +280,51 @@ struct fcp_prli {
};
-
/*
* fcp PRLI ACC payload
*/
struct fcp_prli_acc {
uchar_t type;
- uchar_t resvd1;
+ uchar_t resvd1; /* type code extension */
+
+#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_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;
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 */
diff --git a/usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h b/usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h
index 35be66da30..b642f97219 100644
--- a/usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h
+++ b/usr/src/uts/common/sys/fibre-channel/ulp/fcpvar.h
@@ -26,8 +26,6 @@
#ifndef _FCPVAR_H
#define _FCPVAR_H
-
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -127,7 +125,7 @@ struct fcp_stats {
* 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 @@ struct fcp_port {
* 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 @@ typedef int fcp_map_tag_t;
*/
#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 @@ typedef int fcp_map_tag_t;
* (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 @@ struct fcp_pkt {
* fp/fctl.
*/
struct fc_packet cmd_fc_packet;
-};
+} fcp_pkt_t;
/*
* fcp_ipkt : Packet for internal commands.
@@ -645,7 +648,7 @@ struct fcp_pkt {
* (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 @@ struct fcp_ipkt {
* FC packet.
*/
struct fc_packet ipkt_fc_packet;
-};
+} fcp_ipkt_t;
/*
* cmd_state definitions
@@ -725,7 +728,9 @@ struct fcp_ipkt {
/*
* 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 @@ struct fcp_ipkt {
* 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 @@ struct fcp_tgt {
* 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 @@ typedef void *child_info_t;
* 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 @@ struct fcp_lun {
* LUN inquiry data (as returned by the INQUIRY command).
*/
struct scsi_inquiry lun_inq;
-};
+} fcp_lun_t;
/*
@@ -1297,10 +1302,10 @@ typedef struct fcp_black_list_entry {
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 @@ _NOTE(SCHEME_PROTECTS_DATA("Safe Data",
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))
-
-#define FCP_CP_OUT(s, d, handle, len) (ddi_rep_put8((handle), \
- (uint8_t *)(s), (uint8_t *)(d), \
- (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) \
+ { \
+ 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
diff --git a/usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h b/usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h
index e3248a5d48..78b7704b5e 100644
--- a/usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h
+++ b/usr/src/uts/common/sys/fibre-channel/ulp/fcsm.h
@@ -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 @@ typedef struct fcsm_job {
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 @@ typedef struct fcsm_cmd {
#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 @@ typedef struct fcsm_cmd {
/*
* 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(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_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_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 */
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index bbfeb4a82f..733a2abef6 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -353,6 +353,7 @@ DRV_KMODS += stmf_sbd
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
diff --git a/usr/src/uts/intel/fcoei/Makefile b/usr/src/uts/intel/fcoei/Makefile
new file mode 100644
index 0000000000..4f4c80292f
--- /dev/null
+++ b/usr/src/uts/intel/fcoei/Makefile
@@ -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
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 99fccfee09..934e948527 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -303,6 +303,7 @@ DRV_KMODS += stmf_sbd
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
diff --git a/usr/src/uts/sparc/fcoei/Makefile b/usr/src/uts/sparc/fcoei/Makefile
new file mode 100644
index 0000000000..4f4c80292f
--- /dev/null
+++ b/usr/src/uts/sparc/fcoei/Makefile
@@ -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